4 // Created by Marc Feeley on 11-03-06.
5 // Copyright 2011-2012 Université de Montréal. All rights reserved.
8 // Note: some of this code comes from the KeyboardAccessory
9 // sample application written by Apple.
11 #import <UIKit/UIKit.h>
12 #import <AudioToolbox/AudioToolbox.h>
13 #import "ViewController.h"
16 @implementation ViewController
18 @synthesize segmCtrl, webView0, webView1, webView2, webView3, textView0, textView1, imageView0, imageView1, cancelButton, accessoryView, toolbar, keyboardSounds, timer, queuedActions, locationManager;
20 //-----------------------------------------------------------------------------
22 // Gambit setup/cleanup.
26 * ___VERSION must match the version number of the Gambit header file.
29 #define ___VERSION 406004
33 * Define SCHEME_LIBRARY_LINKER as the name of the Scheme library
34 * prefixed with "____20_" and suffixed with "__". This is the
35 * function that initializes the Scheme library.
38 #define SCHEME_LIBRARY_LINKER ____20_program__
41 extern ___mod_or_lnk SCHEME_LIBRARY_LINKER (___global_state_struct*);
45 extern char **main_argv;
46 ___UCS_2 ucs2_gambcdir[1024];
51 * Setup the Scheme library by calling "___setup" with appropriate
52 * parameters. The call to "___setup_params_reset" sets all
53 * parameters to their default setting.
56 int debug_settings = ___DEBUG_SETTINGS_INITIAL;
57 ___UCS_2STRING *ucs2_argv;
61 if (___NONNULLCHARSTRINGLIST_to_NONNULLUCS_2STRINGLIST
70 while (ucs2_argv[0][i] != '\0')
72 if (ucs2_argv[0][i] == '/')
77 for (i=0; i<last_dir_sep; i++)
78 ucs2_gambcdir[i] = ucs2_argv[0][i];
80 ucs2_gambcdir[i] = '\0';
82 // Set debugging settings so that all threads with uncaught
83 // exceptions start a REPL.
87 & ~___DEBUG_SETTINGS_UNCAUGHT_MASK)
88 | (___DEBUG_SETTINGS_UNCAUGHT_ALL
89 << ___DEBUG_SETTINGS_UNCAUGHT_SHIFT);
93 & ~___DEBUG_SETTINGS_ERROR_MASK)
94 | (___DEBUG_SETTINGS_ERROR_REPL
95 << ___DEBUG_SETTINGS_ERROR_SHIFT);
97 ___setup_params_struct setup_params;
99 ___setup_params_reset (&setup_params);
101 setup_params.version = ___VERSION;
102 setup_params.linker = SCHEME_LIBRARY_LINKER;
103 setup_params.argv = ucs2_argv;
104 setup_params.gambcdir = ucs2_gambcdir;
105 setup_params.debug_settings = debug_settings;
107 ___setup (&setup_params);
109 ___disable_heartbeat_interrupts ();
113 void gambit_cleanup()
119 //-----------------------------------------------------------------------------
122 static ViewController *theViewController = nil;
124 - (void)viewDidLoad {
128 webViews[0] = webView0;
129 webViews[1] = webView1;
130 webViews[2] = webView2;
131 webViews[3] = webView3;
133 textViews[0] = textView0;
134 textViews[1] = textView1;
136 imageViews[0] = imageView0;
137 imageViews[1] = imageView1;
139 theViewController = self;
141 set_textView_font(0, @"Courier-Bold", 16);
143 segmCtrl.selectedSegmentIndex = UISegmentedControlNoSegment;
145 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
146 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
150 queuedActions = [[NSMutableArray alloc] init];
152 locationManager = nil;
156 [self heartbeat_tick];
160 - (void)viewDidUnload {
162 [super viewDidUnload];
164 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
165 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
185 theViewController = nil;
191 - (void)viewWillAppear:(BOOL)animated {
193 [super viewWillAppear:animated];
197 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
203 - (void)didReceiveMemoryWarning {
205 [super didReceiveMemoryWarning];
210 #pragma mark Text view delegate methods
212 - (BOOL)textViewShouldBeginEditing:(UITextView *)aTextView {
214 if (textViews[0].inputAccessoryView == nil)
216 [[NSBundle mainBundle] loadNibNamed:@"AccessoryView" owner:self options:nil];
218 textViews[0].inputAccessoryView = accessoryView;
229 - (BOOL)textViewShouldEndEditing:(UITextView *)aTextView {
231 [aTextView resignFirstResponder];
237 #pragma mark Responding to keyboard events
239 - (void)keyboardWillShow:(NSNotification *)notification {
242 Reduce the size of the text view so that it's not obscured by the keyboard.
243 Animate the resize so that it's in sync with the appearance of the keyboard.
246 NSDictionary *userInfo = [notification userInfo];
248 // Get the origin of the keyboard when it's displayed.
249 NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
251 // Get the top of the keyboard as the y coordinate of its origin in
252 // self's view's coordinate system. The bottom of the text view's
253 // frame should align with the top of the keyboard's final position.
254 CGRect keyboardRect = [aValue CGRectValue];
255 keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
257 CGFloat keyboardTop = keyboardRect.origin.y;
258 CGRect newTextViewFrame = self.view.bounds;
259 newTextViewFrame.size.height = keyboardTop - self.view.bounds.origin.y;
261 // Get the duration of the animation.
262 NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
263 NSTimeInterval animationDuration;
264 [animationDurationValue getValue:&animationDuration];
266 // Animate the resize of the text view's frame in sync with the
267 // keyboard's appearance.
268 [UIView beginAnimations:nil context:NULL];
269 [UIView setAnimationDuration:animationDuration];
271 textViews[0].frame = newTextViewFrame;
273 [UIView commitAnimations];
277 - (void)keyboardWillHide:(NSNotification *)notification {
279 NSDictionary* userInfo = [notification userInfo];
282 Restore the size of the text view (fill self's view). Animate the
283 resize so that it's in sync with the disappearance of the
287 NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
288 NSTimeInterval animationDuration;
289 [animationDurationValue getValue:&animationDuration];
291 [UIView beginAnimations:nil context:NULL];
292 [UIView setAnimationDuration:animationDuration];
294 textViews[0].frame = self.view.bounds;
296 [UIView commitAnimations];
303 void set_navigation(int n) {
305 ViewController *vc = theViewController;
308 [vc->segmCtrl removeTarget:vc action:@selector(navigation_changed:) forControlEvents:UIControlEventValueChanged];
309 vc->segmCtrl.selectedSegmentIndex = n;
310 [vc->segmCtrl addTarget:vc action:@selector(navigation_changed:) forControlEvents:UIControlEventValueChanged];
315 - (void)queue_action:(void(^)())action {
317 [queuedActions addObject:[action copy]];
321 - (void)queue_action_asap:(void(^)())action {
323 [self queue_action:action];
325 [self schedule_next_heartbeat_tick:0.0];
329 - (void)send_event:(NSString*)name {
331 [self queue_action_asap:^{ send_event(name); }];
335 - (void)send_key:(NSString*)name {
337 [self queue_action_asap:^{ send_key(name); }];
341 - (void)heartbeat_tick {
343 [self queue_action:^{ [self schedule_next_heartbeat_tick:heartbeat()]; }];
345 ___enable_heartbeat_interrupts ();
347 while ([queuedActions count] > 0)
349 void (^action)(void) = [queuedActions objectAtIndex:0];
350 [queuedActions removeObjectAtIndex:0];
360 ___disable_heartbeat_interrupts ();
364 - (void)schedule_next_heartbeat_tick:(double)interval {
374 timer = [[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(heartbeat_tick) userInfo:nil repeats:NO] retain];
379 - (void)app_become_active {
381 theViewController.keyboardSounds = -1; // delay check of user preferences
383 [self send_event:@"app-become-active"];
387 void show_cancelButton() {
389 ViewController *vc = theViewController;
392 vc->cancelButton.hidden = NO;
397 void hide_cancelButton() {
399 ViewController *vc = theViewController;
402 vc->cancelButton.hidden = YES;
407 void show_webView(int view) {
409 ViewController *vc = theViewController;
414 for (int i=0; i<NB_WEBVIEWS; i++)
417 [vc->webViews[i] resignFirstResponder];
418 vc->webViews[i].hidden = YES;
421 for (int i=0; i<NB_TEXTVIEWS; i++)
423 [vc->textViews[i] resignFirstResponder];
424 vc->textViews[i].hidden = YES;
427 for (int i=0; i<NB_IMAGEVIEWS; i++)
429 [vc->imageViews[i] resignFirstResponder];
430 vc->imageViews[i].hidden = YES;
433 [vc->webViews[view] becomeFirstResponder];
434 vc->webViews[view].hidden = NO;
439 void show_textView(int view) {
441 ViewController *vc = theViewController;
446 for (int i=0; i<NB_WEBVIEWS; i++)
448 [vc->webViews[i] resignFirstResponder];
449 vc->webViews[i].hidden = YES;
452 for (int i=0; i<NB_TEXTVIEWS; i++)
455 [vc->textViews[i] resignFirstResponder];
456 vc->textViews[i].hidden = YES;
459 for (int i=0; i<NB_IMAGEVIEWS; i++)
461 [vc->imageViews[i] resignFirstResponder];
462 vc->imageViews[i].hidden = YES;
465 [vc->textViews[view] becomeFirstResponder];
466 vc->textViews[view].hidden = NO;
471 void show_imageView(int view) {
473 ViewController *vc = theViewController;
478 for (int i=0; i<NB_WEBVIEWS; i++)
480 [vc->webViews[i] resignFirstResponder];
481 vc->webViews[i].hidden = YES;
484 for (int i=0; i<NB_TEXTVIEWS; i++)
486 [vc->textViews[i] resignFirstResponder];
487 vc->textViews[i].hidden = YES;
490 for (int i=0; i<NB_IMAGEVIEWS; i++)
493 [vc->imageViews[i] resignFirstResponder];
494 vc->imageViews[i].hidden = YES;
497 [vc->imageViews[view] becomeFirstResponder];
498 vc->imageViews[view].hidden = NO;
503 void set_textView_font(int view, NSString *name, int size) {
505 ViewController *vc = theViewController;
508 vc->textViews[view].font = [UIFont fontWithName:name size:size];
513 void set_textView_content(int view, NSString *str) {
515 ViewController *vc = theViewController;
518 vc->textViews[view].text = str;
523 NSString *get_textView_content(int view) {
525 ViewController *vc = theViewController;
528 return vc->textViews[view].text;
535 void add_to_textView(int view, NSString *str) {
537 ViewController *vc = theViewController;
540 NSMutableString *new_text = [vc->textViews[view].text mutableCopy];
541 [new_text appendString:str];
542 vc->textViews[view].text = new_text;
548 void add_output_to_textView(int view, NSString *str) {
550 add_to_textView(view, [str stringByReplacingOccurrencesOfString:@" " withString:@"\u2007"]);
554 void add_input_to_textView(int view, NSString *str) {
556 ViewController *vc = theViewController;
559 NSMutableString *new_text = [vc->textViews[view].text mutableCopy];
560 NSRange selectedRange = vc->textViews[view].selectedRange;
562 [new_text replaceCharactersInRange:selectedRange withString:str];
564 vc->textViews[view].text = new_text;
570 void set_webView_content(int view, NSString *str, NSString *base_url_path, BOOL enable_scaling, NSString *mime_type) {
572 ViewController *vc = theViewController;
576 loadData:[str dataUsingEncoding:NSUnicodeStringEncoding]
578 textEncodingName:@"UTF-8"
579 baseURL:[NSURL fileURLWithPath:(base_url_path != nil) ? base_url_path : [[NSBundle mainBundle] bundlePath]]
581 vc->webViews[0].scalesPageToFit = enable_scaling;
586 void set_webView_content_from_file(int view, NSString *path, NSString *base_url_path, BOOL enable_scaling, NSString *mime_type) {
588 ViewController *vc = theViewController;
591 NSData *data = [NSData dataWithContentsOfFile:path];
597 textEncodingName:@"UTF-8"
598 baseURL:[NSURL fileURLWithPath:(base_url_path != nil) ? base_url_path : [[NSBundle mainBundle] bundlePath]]
600 vc->webViews[view].scalesPageToFit = enable_scaling;
606 NSString *eval_js_in_webView(int view, NSString *script) {
608 ViewController *vc = theViewController;
611 return [vc->webViews[view] stringByEvaluatingJavaScriptFromString:script];
618 void open_URL(NSString *url) {
620 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
624 BOOL send_SMS(NSString *recipient, NSString *message) {
626 ViewController *vc = theViewController;
629 if ([MFMessageComposeViewController canSendText])
631 MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
633 controller.body = message;
634 controller.recipients = [NSArray arrayWithObjects:recipient,nil];
635 controller.messageComposeDelegate = vc;
636 [vc presentModalViewController:controller animated:YES];
646 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
650 [self dismissModalViewControllerAnimated:YES];
655 case MessageComposeResultFailed:
656 event = @"SMS-failed";
659 case MessageComposeResultCancelled:
660 event = @"SMS-cancelled";
663 case MessageComposeResultSent:
668 [self send_event:event];
674 ViewController *vc = theViewController;
677 if ([UIImagePickerController isCameraDeviceAvailable: UIImagePickerControllerCameraDeviceRear] ||
678 [UIImagePickerController isCameraDeviceAvailable: UIImagePickerControllerCameraDeviceFront])
680 UIImagePickerController *controller = [[[UIImagePickerController alloc] init] autorelease];
682 controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType: UIImagePickerControllerSourceTypeCamera];
684 controller.sourceType = UIImagePickerControllerSourceTypeCamera;
686 controller.delegate = vc;
688 [vc presentModalViewController:controller animated:YES];
698 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
700 [picker dismissModalViewControllerAnimated:YES];
702 [self send_event:@"pick-image:"];
706 void set_idle_timer(BOOL enable) {
708 [UIApplication sharedApplication].idleTimerDisabled = !enable;
712 void set_toolbar_alpha(double alpha) {
714 ViewController *vc = theViewController;
717 [vc->toolbar setAlpha: alpha];
721 void segm_ctrl_set_title(int segment, NSString *title) {
723 ViewController *vc = theViewController;
726 [vc->segmCtrl setTitle:title forSegmentAtIndex:segment];
731 void segm_ctrl_insert(int segment, NSString *title) {
733 ViewController *vc = theViewController;
736 [vc->segmCtrl insertSegmentWithTitle:title atIndex:segment animated:false];
741 void segm_ctrl_remove(int segment) {
743 ViewController *vc = theViewController;
746 [vc->segmCtrl removeSegmentAtIndex:segment animated:false];
751 void segm_ctrl_remove_all() {
753 ViewController *vc = theViewController;
756 [vc->segmCtrl removeAllSegments];
761 void set_pref(NSString *key, NSString *value) {
763 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
764 [prefs setObject:value forKey:key];
769 NSString *get_pref(NSString *key) {
771 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
772 return [prefs stringForKey:key];
776 void set_pasteboard(NSString *value) {
778 UIPasteboard *pb = [UIPasteboard generalPasteboard];
783 NSString *get_pasteboard() {
785 UIPasteboard *pb = [UIPasteboard generalPasteboard];
790 NSString *get_documents_dir() {
792 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
793 return [paths objectAtIndex:0];
797 void popup_alert(NSString *title, NSString *msg, NSString *cancel_button, NSString *accept_button) {
799 UIAlertView *alert = [[UIAlertView alloc]
802 delegate: theViewController
803 cancelButtonTitle: cancel_button
804 otherButtonTitles: accept_button, nil];
810 // Called when an alertview button is touched
811 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
815 switch (buttonIndex) {
818 event = @"popup-alert-accept";
823 event = @"popup-alert-cancel";
827 [self send_event:event];
832 #pragma mark Toolbar action
834 - (IBAction)navigation_changed:(id)sender {
835 int n = segmCtrl.selectedSegmentIndex;
837 [self send_event:[NSString stringWithFormat:@"NAV%d", n]];
842 #pragma mark Cancel button action
844 - (IBAction)touch_up_cancel:(id)sender {
845 [self send_event:@"cancel"];
849 - (BOOL)textView:(UITextView *)textView2 shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
851 if ([text hasSuffix:@"\n"])
854 int end = [textViews[0].text length];
856 int line_start = range.location+range.length;
858 while (line_start > 0 &&
859 (c = [textViews[0].text characterAtIndex:line_start-1]) != '\n' &&
860 c != 0x2007) // non breaking space
863 int line_end = range.location+range.length;
865 while (line_end < end &&
866 [textViews[0].text characterAtIndex:line_end] != '\n')
869 if (line_start == line_end)
871 [textViews[0] resignFirstResponder]; // Hide the keyboard after "return" key is pressed on empty line
875 NSString *line = [textViews[0].text substringWithRange:NSMakeRange(line_start, line_end-line_start)];
879 add_to_textView(0, text);
881 [self queue_action_asap:^{
882 send_input([line stringByAppendingString:text]);
886 add_to_textView(0, line);
896 - (IBAction)touch_up_Char:(id)sender withString:(NSString *)aString {
898 add_input_to_textView(0, aString);
903 #pragma mark Accessory view action
905 - (IBAction)touch_down:(id)sender {
907 if (keyboardSounds != 0)
909 if (keyboardSounds == -1) // delayed check of user preferences?
911 Boolean exists_and_valid;
913 CFPreferencesGetAppBooleanValue(CFSTR("keyboard"),
914 CFSTR("/var/mobile/Library/Preferences/com.apple.preferences.sounds"),
916 if (!exists_and_valid)
917 keyboardSounds = true; // by default turn on keyboard clicks
920 if (keyboardSounds != 0)
921 AudioServicesPlaySystemSound(1104); // keyboard "tock" sound
927 #pragma mark Accessory view action
929 - (IBAction)touch_up_F1:(id)sender {
930 [self send_key:@"F1"];
935 #pragma mark Accessory view action
937 - (IBAction)touch_up_F2:(id)sender {
938 [self send_key:@"F2"];
943 #pragma mark Accessory view action
945 - (IBAction)touch_up_F3:(id)sender {
946 [self send_key:@"F3"];
951 #pragma mark Accessory view action
953 - (IBAction)touch_up_F4:(id)sender {
954 [self send_key:@"F4"];
959 #pragma mark Accessory view action
961 - (IBAction)touch_up_F5:(id)sender {
962 [self send_key:@"F5"];
967 #pragma mark Accessory view action
969 - (IBAction)touch_up_F6:(id)sender {
970 [self send_key:@"F6"];
975 #pragma mark Accessory view action
977 - (IBAction)touch_up_F7:(id)sender {
978 [self send_key:@"F7"];
983 #pragma mark Accessory view action
985 - (IBAction)touch_up_F8:(id)sender {
986 [self send_key:@"F8"];
991 #pragma mark Accessory view action
993 - (IBAction)touch_up_F9:(id)sender {
994 [self send_key:@"F9"];
999 #pragma mark Accessory view action
1001 - (IBAction)touch_up_F10:(id)sender {
1002 [self send_key:@"F10"];
1007 #pragma mark Accessory view action
1009 - (IBAction)touch_up_F11:(id)sender {
1010 [self send_key:@"F11"];
1015 #pragma mark Accessory view action
1017 - (IBAction)touch_up_F12:(id)sender {
1018 [self send_key:@"F12"];
1023 #pragma mark Accessory view action
1025 - (IBAction)touch_up_F13:(id)sender {
1026 [self send_key:@"F13"];
1031 #pragma mark Accessory view action
1033 - (IBAction)touch_up_SHARP:(id)sender {
1034 [self send_key:@"#"];
1039 #pragma mark Accessory view action
1041 - (IBAction)touch_up_DQUOTE:(id)sender {
1042 [self send_key:@"\""];
1047 #pragma mark Accessory view action
1049 - (IBAction)touch_up_QUOTE:(id)sender {
1050 [self send_key:@"'"];
1055 #pragma mark Accessory view action
1057 - (IBAction)touch_up_COMMA:(id)sender {
1058 [self send_key:@","];
1063 #pragma mark Accessory view action
1065 - (IBAction)touch_up_PLUS:(id)sender {
1066 [self send_key:@"+"];
1071 #pragma mark Accessory view action
1073 - (IBAction)touch_up_MINUS:(id)sender {
1074 [self send_key:@"-"];
1079 #pragma mark Accessory view action
1081 - (IBAction)touch_up_STAR:(id)sender {
1082 [self send_key:@"*"];
1087 #pragma mark Accessory view action
1089 - (IBAction)touch_up_SLASH:(id)sender {
1090 [self send_key:@"/"];
1095 #pragma mark Accessory view action
1097 - (IBAction)touch_up_LPAREN:(id)sender {
1098 [self send_key:@"("];
1103 #pragma mark Accessory view action
1105 - (IBAction)touch_up_RPAREN:(id)sender {
1106 [self send_key:@")"];
1110 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
1112 NSString *url = [[request URL] relativeString];
1114 if ([url hasPrefix:@"event:"])
1116 [self send_event:url];
1125 void setup_location_updates(double desired_accuracy, double distance_filter)
1127 ViewController *vc = theViewController;
1130 if (vc->locationManager == nil)
1132 vc->locationManager = [[CLLocationManager alloc] init];
1133 vc->locationManager.delegate = vc;
1136 if (desired_accuracy < 0.0)
1137 [vc->locationManager stopUpdatingLocation];
1140 if (desired_accuracy == 0.0)
1141 vc->locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
1143 vc->locationManager.desiredAccuracy = desired_accuracy;
1145 vc->locationManager.distanceFilter = kCLDistanceFilterNone;
1147 if (distance_filter < 0.0)
1148 [vc->locationManager startMonitoringSignificantLocationChanges];
1151 if (distance_filter > 0.0)
1152 vc->locationManager.distanceFilter = distance_filter;
1153 [vc->locationManager startUpdatingLocation];
1160 // Delegate method from the CLLocationManagerDelegate protocol.
1162 - (void)locationManager:(CLLocationManager *)manager
1163 didUpdateToLocation:(CLLocation *)newLocation
1164 fromLocation:(CLLocation *)oldLocation
1166 NSString *event = [NSString stringWithFormat:@"location-update:%+.9f %+.9f %+.1f %+.1f %+.1f %+.1f %+.1f %+.6f",
1167 newLocation.coordinate.latitude,
1168 newLocation.coordinate.longitude,
1169 newLocation.horizontalAccuracy,
1170 newLocation.altitude,
1171 newLocation.verticalAccuracy,
1174 [newLocation.timestamp timeIntervalSince1970]];
1175 [self send_event:event];
1179 #pragma mark Memory management
1185 [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];
1189 for (i=0; i<NB_WEBVIEWS; i++)
1190 [webViews[i] release];
1192 for (i=0; i<NB_TEXTVIEWS; i++)
1193 [textViews[i] release];
1195 for (i=0; i<NB_IMAGEVIEWS; i++)
1196 [imageViews[i] release];
1198 [cancelButton release];