Skip to content
This repository
Newer
Older
100644 634 lines (557 sloc) 19.714 kb
76d2a5b8 » mstroeck
2011-08-28
1 //
2 // SearchFolder.m
3 // Vienna
4 //
5 // Created by Steve on Sun Apr 18 2004.
6 // Copyright (c) 2004-2005 Steve Palmer. All rights reserved.
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 // http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 //
20
21 #import "SearchFolder.h"
22 #import "StringExtensions.h"
23 #import "AppController.h"
24 #import "HelperFunctions.h"
25 #import "PopUpButtonExtensions.h"
26
27 // Tags for the three fields that define a criteria. We set these here
28 // rather than in IB to be consistent.
29 #define MA_SFEdit_FieldTag 1000
30 #define MA_SFEdit_OperatorTag 1001
31 #define MA_SFEdit_ValueTag 1002
32 #define MA_SFEdit_FlagValueTag 1003
33 #define MA_SFEdit_DateValueTag 1004
34 #define MA_SFEdit_NumberValueTag 1005
35 #define MA_SFEdit_AddTag 1006
36 #define MA_SFEdit_RemoveTag 1007
37 #define MA_SFEdit_FolderValueTag 1008
38
39 @interface SmartFolder (Private)
40 -(void)initFolderValueField:(int)parentId atIndent:(int)indentation;
41 -(void)initSearchSheet:(NSString *)folderName;
42 -(void)displaySearchSheet:(NSWindow *)window;
43 -(void)initForField:(NSString *)fieldName inRow:(NSView *)row;
44 -(void)setOperatorsPopup:(NSPopUpButton *)popUpButton, ...;
87178c03 » Salvatore Ansani
2011-12-06 64bit & Lion Full Screen support
45 -(void)addCriteria:(NSUInteger )index;
76d2a5b8 » mstroeck
2011-08-28
46 -(void)addDefaultCriteria:(int)index;
47 -(void)removeCriteria:(int)index;
48 -(void)removeAllCriteria;
49 -(void)resizeSearchWindow;
50 @end
51
52 @implementation SmartFolder
53
54 /* initWithDatabase
55 * Just init the search criteria class.
56 */
57 -(id)initWithDatabase:(Database *)newDb
58 {
59 if ((self = [super init]) != nil)
60 {
61 totalCriteria = 0;
62 smartFolderId = -1;
63 db = newDb;
64 firstRun = YES;
65 parentId = MA_Root_Folder;
66 arrayOfViews = [[NSMutableArray alloc] init];
67 }
68 return self;
69 }
70
71 /* newCriteria
72 * Initialises the smart folder panel with a single empty criteria to get
73 * started.
74 */
75 -(void)newCriteria:(NSWindow *)window underParent:(int)itemId
76 {
77 [self initSearchSheet:@""];
78 smartFolderId = -1;
79 parentId = itemId;
80 [smartFolderName setEnabled:YES];
81
82 // Add a default criteria.
83 [self addDefaultCriteria:0];
84 [self displaySearchSheet:window];
85 }
86
87 /* loadCriteria
88 * Loads the criteria for the specified folder.
89 */
90 -(void)loadCriteria:(NSWindow *)window folderId:(int)folderId
91 {
92 Folder * folder = [db folderFromID:folderId];
93 if (folder != nil)
94 {
95 int index = 0;
96
97 [self initSearchSheet:[folder name]];
98 smartFolderId = folderId;
99 [smartFolderName setEnabled:YES];
100
101 // Load the criteria into the fields.
102 CriteriaTree * criteriaTree = [db searchStringForSmartFolder:folderId];
103
104 // Set the criteria condition
105 [criteriaConditionPopup selectItemWithTag:[criteriaTree condition]];
106
107 for (Criteria * criteria in [criteriaTree criteriaEnumerator])
108 {
109 [self initForField:[criteria field] inRow:searchCriteriaView];
110
111 [fieldNamePopup selectItemWithTitle:NSLocalizedString([criteria field], nil)];
112 [operatorPopup selectItemWithTitle:NSLocalizedString([Criteria stringFromOperator:[criteria operator]], nil)];
113
114 Field * field = [nameToFieldMap valueForKey:[criteria field]];
115 switch ([field type])
116 {
117 case MA_FieldType_Flag: {
118 [flagValueField selectItemWithTitle:NSLocalizedString([criteria value], nil)];
119 break;
120 }
121
122 case MA_FieldType_Folder: {
123 Folder * folder = [db folderFromName:[criteria value]];
124 if (folder != nil)
125 [folderValueField selectItemWithTitle:[folder name]];
126 break;
127 }
128
129 case MA_FieldType_String: {
130 [valueField setStringValue:[criteria value]];
131 break;
132 }
133
134 case MA_FieldType_Integer: {
135 [numberValueField setStringValue:[criteria value]];
136 break;
137 }
138
139 case MA_FieldType_Date: {
140 [dateValueField selectItemAtIndex:[dateValueField indexOfItemWithRepresentedObject:[criteria value]]];
141 break;
142 }
143 }
144
145 [self addCriteria:index++];
146 }
147
148 // We defer sizing the window until all the criteria are
149 // added otherwise it looks crap.
150 [self displaySearchSheet:window];
151 [self resizeSearchWindow];
152 }
153 }
154
155 /* initSearchSheet
156 */
157 -(void)initSearchSheet:(NSString *)folderName
158 {
159 // Clean up from any last run.
160 if (totalCriteria > 0)
161 [self removeAllCriteria];
162
163 // Initialize UI
164 if (!searchWindow)
165 {
166 [NSBundle loadNibNamed:@"SearchFolder" owner:self];
167
168 // Register our notifications
169 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextDidChange:) name:NSControlTextDidChangeNotification object:smartFolderName];
170
171 // Create a mapping for field to column names
172 nameToFieldMap = [[NSMutableDictionary dictionary] retain];
173
174 // Initialize the search criteria view popups with all the
175 // fields in the database.
176
177 [fieldNamePopup removeAllItems];
178 for (Field * field in [db arrayOfFields])
179 {
180 if ([field tag] != MA_FieldID_Headlines &&
181 [field tag] != MA_FieldID_GUID &&
182 [field tag] != MA_FieldID_Link &&
183 [field tag] != MA_FieldID_Comments &&
184 [field tag] != MA_FieldID_Summary &&
185 [field tag] != MA_FieldID_Parent &&
186 [field tag] != MA_FieldID_Enclosure &&
187 [field tag] != MA_FieldID_EnclosureDownloaded)
188 {
189 [fieldNamePopup addItemWithRepresentedObject:[field displayName] object:field];
190 [nameToFieldMap setValue:field forKey:[field name]];
191 }
192 }
193
194 // Set Yes/No values on flag fields
195 [flagValueField removeAllItems];
196 [flagValueField addItemWithRepresentedObject:NSLocalizedString(@"Yes", nil) object:@"Yes"];
197 [flagValueField addItemWithRepresentedObject:NSLocalizedString(@"No", nil) object:@"No"];
198
199 // Set date popup values
200 [dateValueField removeAllItems];
201 [dateValueField addItemWithRepresentedObject:NSLocalizedString(@"Today", nil) object:@"today"];
202 [dateValueField addItemWithRepresentedObject:NSLocalizedString(@"Yesterday", nil) object:@"yesterday"];
203 [dateValueField addItemWithRepresentedObject:NSLocalizedString(@"Last Week", nil) object:@"last week"];
204
205 // Initialise the condition popup
206 NSString * anyString = NSLocalizedString([CriteriaTree conditionToString:MA_CritCondition_Any], nil);
207 NSString * allString = NSLocalizedString([CriteriaTree conditionToString:MA_CritCondition_All], nil);
208
209 [criteriaConditionPopup removeAllItems];
210 [criteriaConditionPopup addItemWithTag:anyString tag:MA_CritCondition_Any];
211 [criteriaConditionPopup addItemWithTag:allString tag:MA_CritCondition_All];
212
213 // Set the tags on the controls
214 [fieldNamePopup setTag:MA_SFEdit_FieldTag];
215 [operatorPopup setTag:MA_SFEdit_OperatorTag];
216 [valueField setTag:MA_SFEdit_ValueTag];
217 [flagValueField setTag:MA_SFEdit_FlagValueTag];
218 [dateValueField setTag:MA_SFEdit_DateValueTag];
219 [folderValueField setTag:MA_SFEdit_FolderValueTag];
220 [numberValueField setTag:MA_SFEdit_NumberValueTag];
221 [removeCriteriaButton setTag:MA_SFEdit_RemoveTag];
222 [addCriteriaButton setTag:MA_SFEdit_AddTag];
223 }
224
225 // Initialise the folder control with a list of all folders
226 // in the database.
227 [folderValueField removeAllItems];
228 [self initFolderValueField:MA_Root_Folder atIndent:0];
229
230 // Init the folder name field and disable the Save button if it is blank
231 [smartFolderName setStringValue:folderName];
232 [saveButton setEnabled:![folderName isBlank]];
233 }
234
235 /* initFolderValueField
236 * Fill the folder value field popup menu with a list of all RSS and group
237 * folders in the database under the specified folder ID. The indentation value
238 * is used to indent the items in the menu when they are part of a group. I've used
239 * an increment of 2 which looks clearer than 1 in the UI.
240 */
241 -(void)initFolderValueField:(int)fromId atIndent:(int)indentation
242 {
243 for (Folder * folder in [db arrayOfFolders:fromId])
244 {
245 if (IsRSSFolder(folder) || IsGroupFolder(folder))
246 {
247 [folderValueField addItemWithTitle:[folder name]];
248 NSMenuItem * menuItem = [folderValueField itemWithTitle:[folder name]];
249 [menuItem setImage:[folder image]];
250 [menuItem setIndentationLevel:indentation];
251 if (IsGroupFolder(folder))
252 [self initFolderValueField:[folder itemId] atIndent:indentation + 2];
253 }
254 }
255 }
256
257 /* displaySearchSheet
258 * Display the search sheet.
259 */
260 -(void)displaySearchSheet:(NSWindow *)window
261 {
262 // Begin the sheet
263 [NSApp beginSheet:searchWindow modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
264
265 // Remember the intial window size after it is first
266 // loaded and before any criteria are added that will
267 // cause it to be resized. We need to know this to shrink
268 // it back to it's default size.
269 if (firstRun)
270 {
271 searchWindowFrame = [NSWindow contentRectForFrameRect:[searchWindow frame] styleMask:[searchWindow styleMask]];
272 firstRun = NO;
273 }
274 }
275
276 /* removeCurrentCriteria
277 * Remove the current criteria row
278 */
279 -(IBAction)removeCurrentCriteria:(id)sender
280 {
281 int index = [arrayOfViews indexOfObject:[sender superview]];
282 NSAssert(index >= 0 && index < totalCriteria, @"Got an out of bounds index of view in superview");
283 [self removeCriteria:index];
284 [self resizeSearchWindow];
285 }
286
287 /* addNewCriteria
288 * Add another criteria row.
289 */
290 -(IBAction)addNewCriteria:(id)sender
291 {
292 int index = [arrayOfViews indexOfObject:[sender superview]];
293 NSAssert(index >= 0 && index < totalCriteria, @"Got an out of bounds index of view in superview");
294 [self addDefaultCriteria:index + 1];
295 [self resizeSearchWindow];
296 }
297
298 /* addDefaultCriteria
299 * Add a new default criteria row. For this we use the static defaultField declared at
300 * the start of this source and the default operator for that field, and an empty value.
301 */
302 -(void)addDefaultCriteria:(int)index
303 {
304 Field * defaultField = [db fieldByName:MA_Field_Read];
305
306 [self initForField:[defaultField name] inRow:searchCriteriaView];
307 [fieldNamePopup selectItemWithTitle:[defaultField displayName]];
308 [valueField setStringValue:@""];
309 [self addCriteria:index];
310 }
311
312 /* fieldChanged
313 * Handle the case where the field has changed. Update the valid list of
314 * operators for the selected field.
315 */
316 -(IBAction)fieldChanged:(id)sender
317 {
318 Field * field = [sender representedObjectForSelection];
319 [self initForField:[field name] inRow:[sender superview]];
320 }
321
322 /* initForField
323 * Initialise the operator and value fields for the specified field.
324 */
325 -(void)initForField:(NSString *)fieldName inRow:(NSView *)row
326 {
327 Field * field = [nameToFieldMap valueForKey:fieldName];
328 NSAssert1(field != nil, @"Got nil field for field '%@'", fieldName);
329
330 // Need to flip on the operator popup for the field that changed
331 NSPopUpButton * theOperatorPopup = [row viewWithTag:MA_SFEdit_OperatorTag];
332 [theOperatorPopup removeAllItems];
333 switch ([field type])
334 {
335 case MA_FieldType_Flag:
336 [self setOperatorsPopup:theOperatorPopup,
337 MA_CritOper_Is,
338 0];
339 break;
340
341 case MA_FieldType_Folder:
342 [self setOperatorsPopup:theOperatorPopup,
343 MA_CritOper_Is,
344 MA_CritOper_IsNot,
345 0];
346 break;
347
348 case MA_FieldType_String:
349 [self setOperatorsPopup:theOperatorPopup,
350 MA_CritOper_Is,
351 MA_CritOper_IsNot,
352 MA_CritOper_Contains,
353 MA_CritOper_NotContains,
354 0];
355 break;
356
357 case MA_FieldType_Integer:
358 [self setOperatorsPopup:theOperatorPopup,
359 MA_CritOper_Is,
360 MA_CritOper_IsNot,
361 MA_CritOper_IsGreaterThan,
362 MA_CritOper_IsGreaterThanOrEqual,
363 MA_CritOper_IsLessThan,
364 MA_CritOper_IsLessThanOrEqual,
365 0];
366 break;
367
368 case MA_FieldType_Date:
369 [self setOperatorsPopup:theOperatorPopup,
370 MA_CritOper_Is,
371 MA_CritOper_IsAfter,
372 MA_CritOper_IsBefore,
373 MA_CritOper_IsOnOrAfter,
374 MA_CritOper_IsOnOrBefore,
375 0];
376 break;
377 }
378
379 // Show and hide the value fields depending on the type
380 NSView * theValueField = [row viewWithTag:MA_SFEdit_ValueTag];
381 NSView * theFlagValueField = [row viewWithTag:MA_SFEdit_FlagValueTag];
382 NSView * theNumberValueField = [row viewWithTag:MA_SFEdit_NumberValueTag];
383 NSView * theDateValueField = [row viewWithTag:MA_SFEdit_DateValueTag];
384 NSView * theFolderValueField = [row viewWithTag:MA_SFEdit_FolderValueTag];
385
386 [theFlagValueField setHidden:[field type] != MA_FieldType_Flag];
387 [theValueField setHidden:[field type] != MA_FieldType_String];
388 [theDateValueField setHidden:[field type] != MA_FieldType_Date];
389 [theNumberValueField setHidden:[field type] != MA_FieldType_Integer];
390 [theFolderValueField setHidden:[field type] != MA_FieldType_Folder];
391 }
392
393 /* setOperatorsPopup
394 * Fills the specified pop up button field with a list of valid operators.
395 */
396 -(void)setOperatorsPopup:(NSPopUpButton *)popUpButton, ...
397 {
398 va_list arguments;
399 va_start(arguments, popUpButton);
400 CriteriaOperator operator;
401
402 while ((operator = va_arg(arguments, int)) != 0)
403 {
404 NSString * operatorString = NSLocalizedString([Criteria stringFromOperator:operator], nil);
405 [popUpButton addItemWithTag:operatorString tag:operator];
406 }
407 }
408
409 /* doSave
410 * Create a CriteriaTree from the criteria rows and save this to the
411 * database.
412 */
413 -(IBAction)doSave:(id)sender
414 {
415 NSString * folderName = [[smartFolderName stringValue] trim];
416 NSAssert(![folderName isBlank], @"doSave called with empty folder name");
87178c03 » Salvatore Ansani
2011-12-06 64bit & Lion Full Screen support
417 NSUInteger c;
76d2a5b8 » mstroeck
2011-08-28
418
419 // Check whether there is another folder with the same name.
420 Folder * folder = [db folderFromName:folderName];
421 if (folder != nil && [folder itemId] != smartFolderId)
422 {
423 runOKAlertPanel(NSLocalizedString(@"Cannot rename folder", nil), NSLocalizedString(@"A folder with that name already exists", nil));
424 return;
425 }
426
427 // Build the criteria string
428 CriteriaTree * criteriaTree = [[CriteriaTree alloc] init];
429 for (c = 0; c < [arrayOfViews count]; ++c)
430 {
431 NSView * row = [arrayOfViews objectAtIndex:c];
432 NSPopUpButton * theField = [row viewWithTag:MA_SFEdit_FieldTag];
433 NSPopUpButton * theOperator = [row viewWithTag:MA_SFEdit_OperatorTag];
434
435 Field * field = [theField representedObjectForSelection];
436 CriteriaOperator operator = [theOperator tagForSelection];
437 NSString * valueString;
438
439 if ([field type] == MA_FieldType_Flag)
440 {
441 NSPopUpButton * theValue = [row viewWithTag:MA_SFEdit_FlagValueTag];
442 valueString = [theValue representedObjectForSelection];
443 }
444 else if ([field type] == MA_FieldType_Date)
445 {
446 NSPopUpButton * theValue = [row viewWithTag:MA_SFEdit_DateValueTag];
447 valueString = [theValue representedObjectForSelection];
448 }
449 else if ([field type] == MA_FieldType_Folder)
450 {
451 NSPopUpButton * theValue = [row viewWithTag:MA_SFEdit_FolderValueTag];
452 valueString = [theValue titleOfSelectedItem];
453 }
454 else if ([field type] == MA_FieldType_Integer)
455 {
456 NSTextField * theValue = [row viewWithTag:MA_SFEdit_NumberValueTag];
457 valueString = [theValue stringValue];
458 }
459 else
460 {
461 NSTextField * theValue = [row viewWithTag:MA_SFEdit_ValueTag];
462 valueString = [theValue stringValue];
463 }
464
465 Criteria * newCriteria = [[Criteria alloc] initWithField:[field name] withOperator:operator withValue:valueString];
466 [criteriaTree addCriteria:newCriteria];
467 [newCriteria release];
468 }
469
470 // Set the criteria condition
471 [criteriaTree setCondition:[criteriaConditionPopup selectedTag]];
472
473 [db beginTransaction];
474 if (smartFolderId == -1)
475 {
476 AppController * controller = (AppController *)[NSApp delegate];
477 smartFolderId = [db addSmartFolder:folderName underParent:parentId withQuery:criteriaTree];
cf938769 » barijaona
2012-01-31 Fixed issue #16 : unbalanced "begin transaction" / "commit transactio…
478 [db commitTransaction];
76d2a5b8 » mstroeck
2011-08-28
479 [controller selectFolder:smartFolderId];
480 }
481 else
cf938769 » barijaona
2012-01-31 Fixed issue #16 : unbalanced "begin transaction" / "commit transactio…
482 {
76d2a5b8 » mstroeck
2011-08-28
483 [db updateSearchFolder:smartFolderId withFolder:folderName withQuery:criteriaTree];
cf938769 » barijaona
2012-01-31 Fixed issue #16 : unbalanced "begin transaction" / "commit transactio…
484 [db commitTransaction];
485 }
76d2a5b8 » mstroeck
2011-08-28
486
487 [criteriaTree release];
488
489 [NSApp endSheet:searchWindow];
490 [searchWindow orderOut:self];
491 }
492
493 /* doCancel
494 */
495 -(IBAction)doCancel:(id)sender
496 {
497 [NSApp endSheet:searchWindow];
498 [searchWindow orderOut:self];
499 }
500
501 /* handleTextDidChange [delegate]
502 * This function is called when the contents of the input field is changed.
503 * We disable the Save button if the input field is empty or enable it otherwise.
504 */
505 -(void)handleTextDidChange:(NSNotification *)aNotification
506 {
507 NSString * folderName = [smartFolderName stringValue];
508 [saveButton setEnabled:![folderName isBlank]];
509 }
510
511 /* removeAllCriteria
512 * Remove all existing criteria (i.e. reset the views back to defaults).
513 */
514 -(void)removeAllCriteria
515 {
516 int c;
517
518 NSArray * subviews = [searchCriteriaSuperview subviews];
519 for (c = [subviews count] - 1; c >= 0; --c)
520 {
521 NSView * row = [subviews objectAtIndex:c];
522 [row removeFromSuperview];
523 }
524 [arrayOfViews removeAllObjects];
525 totalCriteria = 0;
526 }
527
528 /* removeCriteria
529 * Remove the criteria at the specified index.
530 */
531 -(void)removeCriteria:(int)index
532 {
533 int rowHeight = [searchCriteriaView frame].size.height;
534 int c;
535
536 // Do nothing if there's just one criteria
537 if (totalCriteria <= 1)
538 return;
539
540 // Remove the view from the parent view
541 NSView * row = [arrayOfViews objectAtIndex:index];
542 [row removeFromSuperview];
543 [arrayOfViews removeObject:row];
544 --totalCriteria;
545
546 // Shift the subviews
547 for (c = 0; c < index; ++c)
548 {
549 NSView * row = [arrayOfViews objectAtIndex:c];
550 NSPoint origin = [row frame].origin;
551 [row setFrameOrigin:NSMakePoint(origin.x, origin.y - rowHeight)];
552 }
553 }
554
555 /* addCriteria
556 * Add a new criteria clause. Before calling this function, initialise the
557 * searchView with the settings to be added.
558 */
87178c03 » Salvatore Ansani
2011-12-06 64bit & Lion Full Screen support
559 -(void)addCriteria:(NSUInteger )index
76d2a5b8 » mstroeck
2011-08-28
560 {
561 NSData * archRow;
562 NSView * previousRow = nil;
563 int rowHeight = [searchCriteriaView frame].size.height;
87178c03 » Salvatore Ansani
2011-12-06 64bit & Lion Full Screen support
564 NSUInteger c;
76d2a5b8 » mstroeck
2011-08-28
565
566 // Bump up the criteria count
567 ++totalCriteria;
568 if (!firstRun)
569 [self resizeSearchWindow];
570
571 // Shift the existing subviews up by rowHeight
572 if (index > [arrayOfViews count])
573 index = [arrayOfViews count];
574 for (c = 0; c < index; ++c)
575 {
576 NSView * row = [arrayOfViews objectAtIndex:c];
577 NSPoint origin = [row frame].origin;
578 [row setFrameOrigin:NSMakePoint(origin.x, origin.y + rowHeight)];
579 previousRow = row;
580 }
581
582 // Now add the new subview
583 archRow = [NSArchiver archivedDataWithRootObject:searchCriteriaView];
584 NSRect bounds = [searchCriteriaSuperview bounds];
585 NSView * row = (NSView *)[NSUnarchiver unarchiveObjectWithData:archRow];
586 [row setFrameOrigin:NSMakePoint(bounds.origin.x, bounds.origin.y + (((totalCriteria - 1) - index) * rowHeight))];
587 [searchCriteriaSuperview addSubview:[row retain]];
588 [arrayOfViews insertObject:row atIndex:index];
589
590 // Link the previous row to the next one so that the Tab key behaves
591 // properly through the entire sheet.
592 // BUGBUG: This doesn't work and I can't figure out why not yet. This needs to be fixed.
593 if (previousRow)
594 {
595 NSView * lastKeyView = [previousRow nextKeyView];
596 [previousRow setNextKeyView:row];
597 [row setNextKeyView:lastKeyView];
598 }
599 [searchCriteriaSuperview display];
600 [row release];
601 }
602
603 /* resizeSearchWindow
604 * Resize the search window for the number of criteria
605 */
606 -(void)resizeSearchWindow
607 {
608 NSRect newFrame;
609
610 newFrame = searchWindowFrame;
611 if (totalCriteria > 0)
612 {
613 int rowHeight = [searchCriteriaView frame].size.height;
614 int newHeight = newFrame.size.height + rowHeight * (totalCriteria - 1);
615 newFrame.origin.y += newFrame.size.height;
616 newFrame.origin.y -= newHeight;
617 newFrame.size.height = newHeight;
618 newFrame = [NSWindow frameRectForContentRect:newFrame styleMask:[searchWindow styleMask]];
619 }
620 [searchWindow setFrame:newFrame display:YES animate:YES];
621 }
622
623 /* dealloc
624 * Clean up and release resources.
625 */
626 -(void)dealloc
627 {
628 [[NSNotificationCenter defaultCenter] removeObserver:self];
629 [arrayOfViews release];
630 [nameToFieldMap release];
631 [db release];
632 [super dealloc];
633 }
634 @end
Something went wrong with that request. Please try again.