Removed redundant RotatingNavigationController class
[zxing.git] / iphone / Classes / DecoderViewController.m
1 //
2 //  DecoderViewController.m
3 //  ZXing
4 //
5 //  Created by Christian Brunschen on 22/05/2008.
6 /*
7  * Copyright 2008 Google Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #import "DecoderViewController.h"
23 #import "Decoder.h"
24 #import "NSString+HTML.h"
25 #import "ParsedResult.h"
26 #import "ResultAction.h"
27
28 #import "Database.h"
29 #import "ArchiveController.h"
30 #import "Scan.h"
31 #import "TwoDDecoderResult.h"
32
33
34 @implementation DecoderViewController
35
36 @synthesize cameraBarItem;
37 @synthesize libraryBarItem;
38 @synthesize savedPhotosBarItem;
39 @synthesize archiveBarItem;
40 @synthesize actionBarItem;
41
42 @synthesize messageView;
43 @synthesize resultView;
44 @synthesize imageView;
45 @synthesize toolbar;
46
47 @synthesize decoder;
48 @synthesize result;
49 @synthesize actions;
50
51 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
52         if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
53                 // Initialization code
54     self.title = @"ZXing";
55     
56     Decoder *d = [[Decoder alloc] init];
57     self.decoder = d;
58     d.delegate = self;
59     [d release];
60         }
61         return self;
62 }
63
64
65 // Implement loadView if you want to create a view hierarchy programmatically
66 - (void)loadView {
67   [super loadView];
68   
69   CGRect mViewFrame = self.resultView.bounds;
70   UITextView *mView = [[UITextView alloc] initWithFrame:mViewFrame];
71   mView.backgroundColor = [UIColor yellowColor];
72   mView.alpha = 0.95;
73   mView.editable = false;
74   mView.scrollEnabled = true;
75   mView.autoresizingMask = UIViewAutoresizingFlexibleHeight | 
76                            UIViewAutoresizingFlexibleWidth |
77                            UIViewAutoresizingFlexibleLeftMargin |
78                            UIViewAutoresizingFlexibleRightMargin |
79                            UIViewAutoresizingFlexibleTopMargin |
80                            UIViewAutoresizingFlexibleBottomMargin;
81   self.messageView = mView;
82   [mView release];
83   
84   [self.resultView addSubview:self.messageView];
85   [self updateToolbar];
86   [self showMessage:@"Please take or choose a picture containing a barcode"];
87 }
88
89 - (void) updateToolbar {
90   self.cameraBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
91   self.savedPhotosBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
92   self.libraryBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary];
93   self.archiveBarItem.enabled = true;
94   self.actionBarItem.enabled = (self.result != nil) && ([self.result actions] != nil) && ([self.result actions].count > 0);
95 }
96
97
98 // If you need to do additional setup after loading the view, override viewDidLoad.
99 - (void)viewDidLoad {
100   [super viewDidLoad];
101 }
102
103
104 - (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType {
105   self.result = nil;
106   // Create the Image Picker
107   if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
108     UIImagePickerController* picker = [[UIImagePickerController alloc] init];
109     picker.sourceType = sourceType;
110     picker.delegate = self;
111     picker.allowsImageEditing = [[NSUserDefaults standardUserDefaults] 
112                                  boolForKey:@"allowEditing"];
113     
114     // Picker is displayed asynchronously.
115     [self presentModalViewController:picker animated:YES];
116   } else {
117     NSLog(@"Attempted to pick an image with illegal source type '%d'", sourceType);
118   }
119 }
120
121 - (IBAction)pickAndDecode:(id) sender {
122   UIImagePickerControllerSourceType sourceType;
123   int i = [sender tag];
124   
125   switch (i) {
126     case 0: sourceType = UIImagePickerControllerSourceTypeCamera; break;
127     case 1: sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; break;
128     case 2: sourceType = UIImagePickerControllerSourceTypePhotoLibrary; break;
129     default: sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
130   }
131   [self pickAndDecodeFromSource:sourceType];
132 }
133
134
135 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
136         // Return YES for supported orientations
137         return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
138 }
139
140
141 - (void)didReceiveMemoryWarning {
142         [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
143         // Release anything that's not essential, such as cached data
144 }
145
146
147 - (void)dealloc {
148   [decoder release];
149   [imageView release];
150   [actionBarItem release];
151   [cameraBarItem release];
152   [libraryBarItem release];
153   [savedPhotosBarItem release];
154   [archiveBarItem release];
155   [toolbar release];
156   
157         [super dealloc];
158 }
159
160 - (void)showMessage:(NSString *)message {
161   NSLog(message);
162   self.messageView.text = message;
163   [self.messageView sizeToFit];
164 }
165
166 // DecoderDelegate methods
167
168 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image {
169   [self.imageView setImage:image];
170   [self showMessage:[NSString stringWithFormat:@"Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height]];
171 }
172
173 - (void)decoder:(Decoder *)decoder 
174   decodingImage:(UIImage *)image 
175     usingSubset:(UIImage *)subset
176        progress:(NSString *)message {
177   [self.imageView setImage:subset];
178   [self showMessage:message];
179 }
180
181 - (void)presentResultForString:(NSString *)resultString {
182   self.result = [ParsedResult parsedResultForString:resultString];
183   [self showMessage:[self.result stringForDisplay]];
184   self.actions = self.result.actions;
185   NSLog(@"result has %d actions", actions ? 0 : actions.count);
186   [self updateToolbar];
187 }  
188
189 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image withResult:(TwoDDecoderResult *)twoDResult {
190   [self presentResultForString:twoDResult.text];
191   
192   // save the scan to the shared database
193   [[Database sharedDatabase] addScanWithText:twoDResult.text];
194   
195   [self performResultAction:self];
196 }
197
198 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image reason:(NSString *)reason {
199   [self showMessage:reason];
200   [self updateToolbar];
201 }
202
203
204 // UIImagePickerControllerDelegate methods
205
206 - (void)imagePickerController:(UIImagePickerController *)picker
207         didFinishPickingImage:(UIImage *)image
208                   editingInfo:(NSDictionary *)editingInfo
209 {
210   NSLog(@"picked image size = (%f, %f)", image.size.width, image.size.height);
211   if (editingInfo) {
212     UIImage *originalImage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];
213     if (originalImage) {
214       NSLog(@"original image size = (%f, %f)", originalImage.size.width, originalImage.size.height);
215     }
216     NSValue *cropRectValue = [editingInfo objectForKey:UIImagePickerControllerCropRect];
217     if (cropRectValue) {
218       CGRect cropRect = [cropRectValue CGRectValue];
219       NSLog(@"crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
220     }
221   }
222   
223   [[picker parentViewController] dismissModalViewControllerAnimated:YES];
224   [image retain];
225   [picker release];
226   [self.decoder decodeImage:image];
227   [image release];
228   [self updateToolbar];
229 }
230
231 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
232 {
233   [picker dismissModalViewControllerAnimated:YES];
234   [picker release];
235   [self updateToolbar];
236 }
237
238 - (void)navigationController:(UINavigationController *)navigationController 
239        didShowViewController:(UIViewController *)viewController 
240                     animated:(BOOL)animated {
241   // no-op
242 }
243
244 - (void)navigationController:(UINavigationController *)navigationController 
245       willShowViewController:(UIViewController *)viewController 
246                     animated:(BOOL)animated {
247   // no-op
248 }
249
250
251 - (IBAction)performResultAction:(id)sender {
252   if (self.result == nil) {
253     NSLog(@"no result to perform an action on!");
254     return;
255   }
256   
257   if (self.actions == nil || self.actions.count == 0) {
258     NSLog(@"result has no actions to perform!");
259     return;
260   }
261   
262   if (self.actions.count == 1) {
263     ResultAction *action = [self.actions lastObject];
264     NSLog(@"Result has the single action, (%@)  '%@', performing it",
265           NSStringFromClass([action class]), [action title]);
266     [action performSelector:@selector(performActionWithController:) 
267                  withObject:self 
268                  afterDelay:0.0];
269   } else {
270     NSLog(@"Result has multiple actions, popping up an action sheet");
271     UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithFrame:self.view.bounds];
272         
273     for (ResultAction *action in self.actions) {
274       [actionSheet addButtonWithTitle:[action title]];
275     }
276     
277     int cancelIndex = [actionSheet addButtonWithTitle:@"Cancel"];
278     actionSheet.cancelButtonIndex = cancelIndex;
279     
280     actionSheet.delegate = self;
281     
282     [actionSheet showFromToolbar:self.toolbar];
283   }
284 }
285
286 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
287   if (buttonIndex < self.actions.count) {
288     int actionIndex = buttonIndex;
289     ResultAction *action = [self.actions objectAtIndex:actionIndex];
290     [action performSelector:@selector(performActionWithController:) 
291                  withObject:self 
292                  afterDelay:0.0];
293   }
294 }
295
296 - (IBAction)showArchive:(id)sender {
297   ArchiveController *archiveController = [[ArchiveController alloc] initWithDecoderViewController:self];
298   [[self navigationController] pushViewController:archiveController animated:true];
299   [archiveController release];
300 }
301
302 - (void)showScan:(Scan *)scan {
303   [[self navigationController] popToViewController:self animated:YES];
304   [self presentResultForString:scan.text];
305 }
306
307 @end