Changeset 53 for trunk/Cocoa/Pester
- Timestamp:
- 01/02/03 05:30:03 (21 years ago)
- Location:
- trunk/Cocoa/Pester/Source
- Files:
-
- 21 added
- 1 deleted
- 56 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Cocoa/Pester/Source
- Property svn:ignore
-
old new 1 1 build 2 .gdb_history
-
- Property svn:ignore
-
trunk/Cocoa/Pester/Source/BDAlias.h
r39 r53 63 63 - (BOOL)isEqual:(id)object; 64 64 65 - (NSString *)displayNameWithKindString:(NSString **)outKindString; 66 65 67 - (NSString *)fullPath; 66 68 - (NSString *)fullPathRelativeToPath:(NSString *)relPath; -
trunk/Cocoa/Pester/Source/BDAlias.m
r39 r53 245 245 } 246 246 247 - (NSString *)displayNameWithKindString:(NSString **)outKindString; 248 { 249 AliasHandle alias = [self alias]; 250 FSRef ref; 251 Boolean wasChanged; 252 CFStringRef name; 253 254 if (alias == NULL) return nil; 255 if (FSResolveAlias(NULL, alias, &ref, &wasChanged) != noErr) return nil; 256 257 if (LSCopyDisplayNameForRef(&ref, &name) != noErr) return nil; 258 [(NSString *)name autorelease]; 259 260 if (outKindString != NULL) { 261 if (LSCopyKindStringForRef(&ref, (CFStringRef *)outKindString) != noErr) return nil; 262 [*outKindString autorelease]; 263 } 264 265 return (NSString *)name; 266 } 267 247 268 - (NSString *)fullPath 248 269 { -
trunk/Cocoa/Pester/Source/English.lproj/MainMenu.nib/classes.nib
r41 r53 17 17 {CLASS = NJRIntegerFilter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }, 18 18 { 19 CLASS = NJRIntervalField; 20 LANGUAGE = ObjC; 21 OUTLETS = {intervalUnits = NSPopUpButton; }; 22 SUPERCLASS = NSTextField; 23 }, 24 { 19 25 ACTIONS = {stopSoundPreview = id; }; 20 26 CLASS = NJRQTMediaPopUpButton; … … 23 29 SUPERCLASS = NSPopUpButton; 24 30 }, 31 {CLASS = NJRUnfocusableMovieView; LANGUAGE = ObjC; SUPERCLASS = NSMovieView; }, 25 32 { 26 33 ACTIONS = {stopVoicePreview = id; }; … … 29 36 SUPERCLASS = NSPopUpButton; 30 37 }, 38 {CLASS = NSDisclosureButtonCell; LANGUAGE = ObjC; SUPERCLASS = NSButtonCell; }, 31 39 {CLASS = NSObject; LANGUAGE = ObjC; }, 32 40 { … … 35 43 doScriptChanged = id; 36 44 doSpeakChanged = id; 45 editAlertChanged = id; 37 46 inAtChanged = id; 38 47 playSoundChanged = id; … … 45 54 LANGUAGE = ObjC; 46 55 OUTLETS = { 56 alertTabs = NSTabView; 57 alertView = NSTextField; 47 58 bounceDockIcon = NSButton; 59 cancelButton = NSButton; 48 60 displayMessage = NSButtonCell; 49 61 doScript = NSButtonCell; 50 62 doSpeak = NSButtonCell; 63 editAlert = NSButtonCell; 51 64 inAtMatrix = NSMatrix; 52 65 messageField = NSTextField; … … 67 80 timeSummary = NSTextField; 68 81 voice = NJRVoicePopUpButton; 82 wakeUp = NSButtonCell; 69 83 }; 70 84 SUPERCLASS = NSWindowController; -
trunk/Cocoa/Pester/Source/English.lproj/MainMenu.nib/info.nib
r45 r53 4 4 <dict> 5 5 <key>IBDocumentLocation</key> 6 <string> 73 38 356 240 0 0 1600 1178</string>6 <string>63 2 356 240 0 0 1280 832 </string> 7 7 <key>IBEditorPositions</key> 8 8 <dict> 9 9 <key>29</key> 10 <string> 94 343 273 44 0 0 1600 1178</string>10 <string>130 241 273 44 0 0 1280 832 </string> 11 11 </dict> 12 12 <key>IBFramework Version</key> 13 <string>2 86.0</string>13 <string>291.0</string> 14 14 <key>IBOpenObjects</key> 15 15 <array> … … 18 18 </array> 19 19 <key>IBSystem Version</key> 20 <string>6 D52</string>20 <string>6G30</string> 21 21 <key>IBUserGuides</key> 22 22 <dict> … … 25 25 <key>guideLocations</key> 26 26 <array> 27 <string>Horizontal:92.000000</string> 28 <string>Horizontal:148.000000</string> 29 <string>Horizontal:116.000000</string> 30 <string>Horizontal:64.000000</string> 27 <string>Horizontal:122.000000</string> 28 <string>Horizontal:178.000000</string> 29 <string>Horizontal:192.000000</string> 30 <string>Vertical:36.000000</string> 31 <string>Vertical:16.000000</string> 32 <string>Vertical:85.000000</string> 33 <string>Vertical:422.000000</string> 34 <string>Horizontal:151.000000</string> 31 35 </array> 32 36 <key>guidesLocked</key> -
trunk/Cocoa/Pester/Source/English.lproj/Movie alert.nib/classes.nib
r33 r53 9 9 SUPERCLASS = NSWindowController; 10 10 }, 11 {CLASS = java.lang.Object; LANGUAGE = Java; }11 {CLASS = "java.lang.Object"; LANGUAGE = Java; } 12 12 ); 13 13 IBVersion = 1; -
trunk/Cocoa/Pester/Source/English.lproj/Movie alert.nib/info.nib
r33 r53 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">3 <plist version=" 0.9">2 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 <plist version="1.0"> 4 4 <dict> 5 5 <key>IBFramework Version</key> 6 <string>2 63.2</string>6 <string>291.0</string> 7 7 <key>IBOpenObjects</key> 8 8 <array> … … 10 10 </array> 11 11 <key>IBSystem Version</key> 12 <string> 5S66</string>12 <string>6G30</string> 13 13 </dict> 14 14 </plist> -
trunk/Cocoa/Pester/Source/English.lproj/Notifier.nib/classes.nib
r21 r53 2 2 IBClasses = ( 3 3 {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 4 {CLASS = NJRIntegerFilter; LANGUAGE = ObjC; SUPERCLASS = NSNumberFormatter; }, 4 5 { 5 ACTIONS = {close = id; }; 6 CLASS = NJRIntervalField; 7 LANGUAGE = ObjC; 8 OUTLETS = {intervalUnits = NSPopUpButton; }; 9 SUPERCLASS = NSTextField; 10 }, 11 { 12 ACTIONS = {close = id; snooze = id; stopRepeating = id; }; 6 13 CLASS = PSAlarmNotifierController; 7 14 LANGUAGE = ObjC; 8 OUTLETS = {dateField = NSTextField; messageField = NSTextField; }; 15 OUTLETS = { 16 dateField = NSTextField; 17 intervalField = NSTextField; 18 messageField = NSTextField; 19 nextDateField = NSTextField; 20 okButton = NSButton; 21 snoozeButton = NSButton; 22 snoozeIntervalField = NJRIntervalField; 23 }; 9 24 SUPERCLASS = NSWindowController; 10 25 } -
trunk/Cocoa/Pester/Source/English.lproj/Notifier.nib/info.nib
r43 r53 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">3 <plist version=" 0.9">2 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 <plist version="1.0"> 4 4 <dict> 5 5 <key>IBDocumentLocation</key> 6 <string> 424 83 356 240 0 0 1280 832 </string>6 <string>122 13 356 240 0 0 1280 832 </string> 7 7 <key>IBFramework Version</key> 8 <string>2 63.2</string>8 <string>291.0</string> 9 9 <key>IBOpenObjects</key> 10 10 <array> … … 12 12 </array> 13 13 <key>IBSystem Version</key> 14 <string>5S66</string> 14 <string>6G30</string> 15 <key>IBUserGuides</key> 16 <dict> 17 <key>5</key> 18 <dict> 19 <key>guideLocations</key> 20 <array> 21 <string>Horizontal:87.000000</string> 22 <string>Horizontal:108.000000</string> 23 <string>Horizontal:66.000000</string> 24 <string>Vertical:92.000000</string> 25 <string>Horizontal:133.000000</string> 26 </array> 27 <key>guidesLocked</key> 28 <false/> 29 </dict> 30 </dict> 15 31 </dict> 16 32 </plist> -
trunk/Cocoa/Pester/Source/NJRFSObjectSelector.m
r43 r53 1 1 #import "NJRFSObjectSelector.h" 2 2 #import "NSImage-NJRExtensions.h" 3 #import "NSString-NJRExtensions.h" 3 4 #include <Carbon/Carbon.h> 4 5 6 static NSImage *PopupTriangleImage = nil; 7 static NSSize PopupTriangleSize; 8 5 9 @implementation NJRFSObjectSelector 6 10 7 11 - (void)_initSelector; 8 12 { 13 if (PopupTriangleImage == nil) { 14 PopupTriangleImage = [[NSImage imageNamed: @"Popup triangle"] retain]; 15 PopupTriangleSize = [PopupTriangleImage size]; 16 } 9 17 canChooseFiles = YES; canChooseDirectories = NO; 10 18 [self setAlias: nil]; … … 47 55 [NSBezierPath strokeRect: NSInsetRect(boundsRect, 2, 2)]; 48 56 } else if (selectedAlias != nil && [self isEnabled]) { 49 static NSImage *popupTriangle = nil;50 static NSSize imageSize;51 if (popupTriangle == nil) {52 popupTriangle = [[NSImage imageNamed: @"Popup triangle"] retain];53 imageSize = [popupTriangle size];54 }55 57 // equivalent to popup triangle location for large bezel in Carbon 56 [ popupTriangle compositeToPoint: NSMakePoint(NSMaxX(boundsRect) - imageSize.width - 5, NSMaxY(boundsRect) - 5) operation: NSCompositeSourceOver];58 [PopupTriangleImage compositeToPoint: NSMakePoint(NSMaxX(boundsRect) - PopupTriangleSize.width - 5, NSMaxY(boundsRect) - 5) operation: NSCompositeSourceOver]; 57 59 } 58 60 } … … 130 132 NSString *path = [alias fullPath]; 131 133 NSString *revealPath = nil; 132 NSString *targetName = [path lastPathComponent];133 134 NSMenu *menu = [[NSMenu alloc] initWithTitle: @""]; 134 135 NSFileManager *fmgr = [NSFileManager defaultManager]; … … 136 137 if (path != nil) { // can resolve alias 137 138 [self setImage: [[NSWorkspace sharedWorkspace] iconForFile: path]]; 138 [self setTitle: targetName]; 139 { // set image first so titleRectForBounds: returns the correct value 140 NSMutableString *title = [[fmgr displayNameAtPath: path] mutableCopy]; 141 NSDictionary *fontAttributes = [[self attributedTitle] fontAttributesInRange: NSMakeRange(0, 0)]; 142 [title truncateToWidth: [[self cell] titleRectForBounds: [self bounds]].size.width - PopupTriangleSize.width by: NSLineBreakByTruncatingMiddle withAttributes: fontAttributes]; 143 [self setTitle: title]; 144 [title release]; 145 } 139 146 do { 140 147 item = [menu addItemWithTitle: [fmgr displayNameAtPath: path] -
trunk/Cocoa/Pester/Source/NJRHistoryTrackingComboBox.m
r39 r53 60 60 NSString *newValue = [self stringValue]; 61 61 int oldIndex = [self indexOfItemWithObjectValue: newValue]; 62 if ([newValue length] == 0) return YES; // donÕt save empty entries 62 63 [self removeItemWithObjectValue: newValue]; 63 64 [self insertItemWithObjectValue: newValue atIndex: 0]; -
trunk/Cocoa/Pester/Source/NJRIntegerFilter.h
r21 r53 7 7 // 8 8 9 #import < AppKit/AppKit.h>9 #import <Foundation/Foundation.h> 10 10 11 11 -
trunk/Cocoa/Pester/Source/NJRIntegerFilter.m
r21 r53 7 7 // 8 8 9 // based on MyIntegerFilter 10 // Copyright © 2001 Bill Cheeseman. All rights reserved.9 // based on MyIntegerFilter, later VRIntegerNumberFilter 10 // Copyright © 2001-2002 Bill Cheeseman. All rights reserved. 11 11 12 12 #import "NJRIntegerFilter.h" … … 14 14 @implementation NJRIntegerFilter 15 15 16 // Input filter16 // Input validation 17 17 18 - (BOOL)isPartialStringValid:(NSString **)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString **)error { 19 20 // Override method to enable NSControl delegate method control:didFailToValidatePartialString:errorDescription: to 21 // reject invalid keypresses. Filters out keyboard input characters other than "1" .. "9". 18 - (BOOL)isPartialStringValid:(NSString **)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString **)error; 19 { 20 // Override method to enable NSControl delegate method control:didFailToValidatePartialString:errorDescription: to reject invalid keypresses. Filters out keyboard input characters other than 0..9. 22 21 if ([[*partialStringPtr substringWithRange:NSMakeRange(origSelRange.location, (*proposedSelRangePtr).location - origSelRange.location)] rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet] options:NSLiteralSearch].location != NSNotFound) { 23 *error = NSLocalizedString(@"Input is not an integer ", @"Presented when user value not a numeric digit");24 return NO; // Reject *partialStringPtr as typed, invoke delegate method 22 *error = NSLocalizedString(@"Input is not an integer.", @"Presented when user value not a numeric digit"); 23 return NO; // Reject *partialStringPtr as typed, invoke delegate method for error handling 25 24 } 26 27 if ([*partialStringPtr length] == 0) { 28 // Work around NSFormatter issue in Mac OS X 10.0. 29 [[[NSApp keyWindow] fieldEditor:NO forObject:nil] setSelectedRange:*proposedSelRangePtr]; 30 } 31 25 *error = nil; 32 26 return YES; // Accept *partialStringPtr as typed 33 27 } -
trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.h
r41 r53 22 22 23 23 - (BDAlias *)selectedAlias; 24 - (void)setAlias:(BDAlias *)alias; 25 24 26 - (BOOL)canRepeat; 27 25 28 - (IBAction)stopSoundPreview:(id)sender; 26 29 -
trunk/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m
r47 r53 11 11 #import "NSMovie-NJRExtensions.h" 12 12 #import "NSImage-NJRExtensions.h" 13 14 // XXX workaround for SoundFileManager log message in 10.2.3 and earlier 15 #include <stdio.h> 16 #include <unistd.h> 17 #include <fcntl.h> 18 // XXX end workaround 13 19 14 20 static const int NJRQTMediaPopUpButtonMaxRecentItems = 10; … … 103 109 #pragma mark initialize-release 104 110 105 - (void) awakeFromNib;111 - (void)_setUp; 106 112 { 107 113 NSMenu *menu; … … 145 151 } 146 152 153 - (id)initWithFrame:(NSRect)frame; 154 { 155 if ( (self = [super initWithFrame: frame]) != nil) { 156 [self _setUp]; 157 } 158 return self; 159 } 160 161 - (id)initWithCoder:(NSCoder *)coder; 162 { 163 if ( (self = [super initWithCoder: coder]) != nil) { 164 [self _setUp]; 165 } 166 return self; 167 } 168 147 169 - (void)dealloc; 148 170 { … … 171 193 } 172 194 195 - (void)setAlias:(BDAlias *)alias; 196 { 197 [self _setAlias: alias]; 198 if ([self _validateWithPreview: NO]) { 199 [self selectItem: [self _itemForAlias: selectedAlias]]; 200 } 201 } 202 173 203 - (void)_setPath:(NSString *)path; 174 204 { … … 186 216 // [self _validateRecentMedia]; 187 217 path = [alias fullPath]; 188 sf = [[SoundFileManager sharedSoundFileManager] soundFileFromPath: path]; 218 { // XXX suppress log message from Apple's code: 219 // 2002-12-14 14:09:58.740 Pester[26529] Could not find sound type for directory /Users/nicholas/Desktop 220 int errfd = dup(STDERR_FILENO), nullfd = open("/dev/null", O_WRONLY, 0); 221 // need to have something open in STDERR_FILENO because if it isn't, 222 // NSLog will log to /dev/console 223 dup2(nullfd, STDERR_FILENO); 224 close(nullfd); 225 sf = [[SoundFileManager sharedSoundFileManager] soundFileFromPath: path]; 226 dup2(errfd, STDERR_FILENO); 227 close(errfd); 228 } 189 229 // NSLog(@"_itemForAlias: %@", path); 190 230 … … 250 290 [preview setMovie: nil]; 251 291 if (movie == nil) { 252 NSBeginAlertSheet(@"Format not recognized", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"The item you selected isnÕt a sound or movie recognized by QuickTime. Please select a different item.");292 NSBeginAlertSheet(@"Format not recognized", nil, nil, nil, [self window], nil, nil, nil, nil, @"The item you selected isnÕt a sound or movie recognized by QuickTime. Please select a different item."); 253 293 [self _invalidateSelection]; 254 294 return NO; 255 295 } 256 296 if (![movie hasAudio] && ![movie hasVideo]) { 257 NSBeginAlertSheet(@"No video or audio", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"Ò%@Ó contains neither audio nor video content playable by QuickTime. Please select a different item.", [[NSFileManager defaultManager] displayNameAtPath: [selectedAlias fullPath]]);297 NSBeginAlertSheet(@"No video or audio", nil, nil, nil, [self window], nil, nil, nil, nil, @"Ò%@Ó contains neither audio nor video content playable by QuickTime. Please select a different item.", [[NSFileManager defaultManager] displayNameAtPath: [selectedAlias fullPath]]); 258 298 [self _invalidateSelection]; 259 299 [movie release]; … … 262 302 } 263 303 [movie release]; 264 [preview start: self];304 if (doPreview) [preview start: self]; 265 305 } 266 306 [[NSNotificationCenter defaultCenter] postNotificationName: NJRQTMediaPopUpButtonMovieChangedNotification object: self]; -
trunk/Cocoa/Pester/Source/NJRTableDelegate.m
r51 r53 179 179 NSRect columnRect = [superview convertRect: [tableView rectOfColumn: [tableView columnWithIdentifier: sortingKey]] fromView: tableView]; 180 180 // XXX support horizontal scroll bar/clipping (not for Pester, but eventually) 181 NSRect tableScrollFrame = [[tableView enclosingScrollView] frame];181 // NSRect tableScrollFrame = [[tableView enclosingScrollView] frame]; 182 182 NSRect selectFrame = [typeSelectControl frame]; 183 183 [superview setNeedsDisplayInRect: selectFrame]; // fix artifacts caused by moving view -
trunk/Cocoa/Pester/Source/NJRTableView.h
r51 r53 11 11 12 12 @interface NJRTableView : NSTableView { 13 NSMutableDictionary *toolTipRegionList; 13 14 NSMutableString *typed; 14 15 IBOutlet id typeSelectDisplay; … … 29 30 30 31 - (void)removeSelectedRowsFromTableView:(NSTableView *)tableView; 32 - (NSString *)tableView:(NSTableView *)aTableView toolTipForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; 31 33 32 34 @end -
trunk/Cocoa/Pester/Source/NJRTableView.m
r51 r53 17 17 18 18 @implementation NJRTableView 19 20 - (id)initWithCoder:(NSCoder *)aDecoder; 21 { 22 if ( (self = [super initWithCoder: aDecoder]) != nil) { 23 toolTipRegionList = [[NSMutableDictionary alloc] initWithCapacity: 20]; 24 } 25 return self; 26 } 27 28 - (void)dealloc; 29 { 30 [toolTipRegionList release]; 31 [super dealloc]; 32 } 33 34 #pragma mark tool tips 35 36 - (void)reloadData; 37 { 38 [toolTipRegionList removeAllObjects]; 39 [self removeAllToolTips]; 40 [super reloadData]; 41 } 42 43 - (void)noteNumberOfRowsChanged; 44 { 45 [toolTipRegionList removeAllObjects]; 46 [self removeAllToolTips]; 47 [super noteNumberOfRowsChanged]; 48 } 49 50 - (NSString *)_keyForColumn:(int)columnIndex row:(int)rowIndex; 51 { 52 return [NSString stringWithFormat:@"%d,%d", rowIndex, columnIndex]; 53 } 54 55 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data; 56 { 57 // ask our data source for the tool tip 58 if ([[self dataSource] respondsToSelector: @selector(tableView:toolTipForTableColumn:row:)]) { 59 if ([self rowAtPoint: point] >= 0) return [[self dataSource] tableView: self toolTipForTableColumn: [[self tableColumns] objectAtIndex: [self columnAtPoint: point]] row: [self rowAtPoint: point]]; 60 } 61 return nil; 62 } 63 64 - (NSRect)frameOfCellAtColumn:(int)columnIndex row:(int)rowIndex; 65 { 66 // this cell is apparently displayed, so we need to add a region for it 67 NSNumber *toolTipTag; 68 NSRect result = [super frameOfCellAtColumn: columnIndex row: rowIndex]; 69 // check if cell is already in the list 70 NSString *cellKey = [self _keyForColumn: columnIndex row: rowIndex]; 71 // remove old region 72 if (toolTipTag = [toolTipRegionList objectForKey: cellKey]) 73 [self removeToolTip: [toolTipTag intValue]]; 74 // add new region 75 [toolTipRegionList setObject: [NSNumber numberWithInt: [self addToolTipRect: result owner: self userData: cellKey]] forKey: cellKey]; 76 return [super frameOfCellAtColumn: columnIndex row: rowIndex]; 77 } 78 79 #pragma mark type selection 19 80 20 81 - (id)typeSelectDisplay; -
trunk/Cocoa/Pester/Source/NJRVoicePopUpButton.h
r42 r53 15 15 } 16 16 17 - (void)setVoice:(NSString *)voice; 18 19 - (id)delegate; 17 20 - (void)setDelegate:(id)delegate; 18 - (id)delegate;19 21 20 22 - (IBAction)stopVoicePreview:(id)sender; -
trunk/Cocoa/Pester/Source/NJRVoicePopUpButton.m
r43 r53 68 68 } 69 69 70 - (void)setVoice:(NSString *)voice; 71 { 72 int voiceIdx = [self indexOfItemWithTitle: voice]; 73 if (voiceIdx == -1) { 74 [self _invalidateVoiceSelection]; 75 } else { 76 [self selectItemAtIndex: voiceIdx]; 77 } 78 } 79 70 80 - (void)_previewVoice; 71 81 { … … 80 90 81 91 if ( (err = GetIndVoice(voiceIndex, &voice)) != noErr) { 82 NSBeginAlertSheet(@"Voice not available", @"OK", nil, nil, [self window], nil, nil, nil, nil, @"The voice Ò%@Ó you selected could not be used. An error of type %ld occurred while attempting to retrieve voice information.", voiceName, err);92 NSBeginAlertSheet(@"Voice not available", nil, nil, nil, [self window], nil, nil, nil, nil, @"The voice Ò%@Ó you selected could not be used. An error of type %ld occurred while attempting to retrieve voice information.", voiceName, err); 83 93 [self _invalidateVoiceSelection]; 84 94 return; -
trunk/Cocoa/Pester/Source/PSAlarm.h
r51 r53 8 8 9 9 #import <Foundation/Foundation.h> 10 #import "PSPropertyListSerialization.h" 10 11 11 12 typedef enum { 12 PSAlarmInvalid, PSAlarmInterval, PSAlarmDate, PSAlarmSet 13 PSAlarmInvalid, // incorrectly specified 14 PSAlarmInterval, // interval specified (possibly repeating) 15 PSAlarmDate, // date specified 16 PSAlarmSet, // pending, timer set 17 PSAlarmSnooze, // expired alarm with snooze interval set (possibly repeating) 18 PSAlarmExpired // expired alarm (possibly repeating) 13 19 } PSAlarmType; 14 20 15 21 extern NSString * const PSAlarmTimerSetNotification; 16 22 extern NSString * const PSAlarmTimerExpiredNotification; 23 extern NSString * const PSAlarmDiedNotification; 17 24 18 // XXX figure out how to support reading old alarms 25 @class PSAlert, PSAlerts; 19 26 20 @class PSAlert; 21 22 @interface PSAlarm : NSObject <NSCoding> { 23 PSAlarmType alarmType; 27 @interface PSAlarm : NSObject <NSCoding, PSPropertyListSerialization> { 28 PSAlarmType alarmType; // changes during lifetime of alarm; more like a state 24 29 NSCalendarDate *alarmDate; 25 30 NSTimeInterval alarmInterval; 31 NSTimeInterval snoozeInterval; 32 NSTimeInterval timeRemaining; 26 33 NSString *alarmMessage; 27 34 NSString *invalidMessage; 28 35 NSTimer *timer; 29 NSMutableArray *alerts; 36 PSAlerts *alerts; 37 BOOL repeating; 30 38 } 31 39 … … 34 42 - (void)setForDate:(NSDate *)date atTime:(NSDate *)time; 35 43 - (void)setMessage:(NSString *)aMessage; 36 - (void)addAlert:(PSAlert *)alert; 37 - (void)removeAlerts; 44 - (void)setAlerts:(PSAlerts *)theAlerts; 45 - (void)setRepeating:(BOOL)isRepeating; 46 - (void)setSnoozeInterval:(NSTimeInterval)anInterval; 38 47 39 48 - (NSCalendarDate *)date; 40 49 - (NSCalendarDate *)time; 41 50 - (NSTimeInterval)interval; 51 - (NSTimeInterval)timeRemaining; 42 52 - (NSString *)message; 43 - (NSArray *)alerts; 53 - (PSAlerts *)alerts; 54 - (BOOL)isRepeating; 55 - (NSTimeInterval)snoozeInterval; // most recent interval (nonzero return does not indicate alarm is snoozing or set to snooze) 44 56 45 57 - (NSString *)dateString; 46 58 - (NSString *)shortDateString; 47 59 - (NSString *)timeString; 60 - (NSString *)dateTimeString; // current or next alarm time 61 - (NSString *)nextDateTimeString; // next alarm time 62 - (NSString *)intervalString; 48 63 - (NSString *)timeRemainingString; 49 64 … … 51 66 - (NSString *)invalidMessage; 52 67 68 - (NSAttributedString *)prettyDescription; 69 53 70 - (NSComparisonResult)compareDate:(PSAlarm *)otherAlarm; 54 71 - (NSComparisonResult)compareMessage:(PSAlarm *)otherAlarm; 55 72 56 - (BOOL)setTimer; 73 - (BOOL)setTimer; // or die, if expired and no snooze/repeat 57 74 - (void)cancelTimer; 58 75 76 // 1.1 only, going away when we move to keyed archiving 77 - (NSDictionary *)propertyListRepresentation; 78 - (id)initWithPropertyList:(NSDictionary *)dict; 79 59 80 @end -
trunk/Cocoa/Pester/Source/PSAlarm.m
r51 r53 9 9 #import "PSAlarm.h" 10 10 #import "PSAlert.h" 11 #import "PSAlerts.h" 11 12 #import "NJRDateFormatter.h" 13 #import "NSCalendarDate-NJRExtensions.h" 14 #import "NSDictionary-NJRExtensions.h" 15 #import "NSString-NJRExtensions.h" 12 16 13 17 NSString * const PSAlarmTimerSetNotification = @"PSAlarmTimerSetNotification"; 14 18 NSString * const PSAlarmTimerExpiredNotification = @"PSAlarmTimerExpiredNotification"; 19 NSString * const PSAlarmDiedNotification = @"PSAlarmDiedNotification"; 20 21 // property list keys 22 static NSString * const PLAlarmType = @"type"; // NSString 23 static NSString * const PLAlarmDate = @"date"; // NSNumber 24 static NSString * const PLAlarmInterval = @"interval"; // NSNumber 25 static NSString * const PLAlarmSnoozeInterval = @"snooze interval"; // NSNumber 26 static NSString * const PLAlarmMessage = @"message"; // NSString 27 static NSString * const PLAlarmAlerts = @"alerts"; // NSDictionary 28 static NSString * const PLAlarmRepeating = @"repeating"; // NSNumber 15 29 16 30 static NSString *dateFormat, *shortDateFormat, *timeFormat; … … 72 86 invalidMessage = nil; 73 87 alarmType = type; 88 if (type != PSAlarmInterval) [self setRepeating: NO]; 74 89 } 75 90 76 91 - (void)_setDateFromInterval; 77 92 { 78 [alarmDate release]; alarmDate = nil; 79 alarmDate = [NSCalendarDate dateWithTimeIntervalSinceNow: alarmInterval]; 80 [alarmDate retain]; 93 [self _setAlarmDate: [NSCalendarDate dateWithTimeIntervalSinceNow: alarmInterval]]; 81 94 [self _beValidWithType: PSAlarmInterval]; 82 95 } … … 84 97 - (void)_setIntervalFromDate; 85 98 { 86 alarmInterval = [alarmDate timeIntervalSinceNow] + 1;99 alarmInterval = [alarmDate timeIntervalSinceNow]; 87 100 if (alarmInterval <= 0) { 88 101 [self _beInvalid: @"Please specify an alarm time in the future."]; … … 90 103 } 91 104 [self _beValidWithType: PSAlarmDate]; 105 } 106 107 - (PSAlarmType)_alarmTypeForString:(NSString *)string; 108 { 109 if ([string isEqualToString: @"PSAlarmDate"]) return PSAlarmDate; 110 if ([string isEqualToString: @"PSAlarmInterval"]) return PSAlarmInterval; 111 if ([string isEqualToString: @"PSAlarmSet"]) return PSAlarmSet; 112 if ([string isEqualToString: @"PSAlarmInvalid"]) return PSAlarmInvalid; 113 if ([string isEqualToString: @"PSAlarmSnooze"]) return PSAlarmSnooze; 114 if ([string isEqualToString: @"PSAlarmExpired"]) return PSAlarmExpired; 115 NSLog(@"unknown alarm type string: %@", string); 116 return nil; 92 117 } 93 118 … … 99 124 case PSAlarmSet: return @"PSAlarmSet"; 100 125 case PSAlarmInvalid: return @"PSAlarmInvalid"; 126 case PSAlarmSnooze: return @"PSAlarmSnooze"; 127 case PSAlarmExpired: return @"PSAlarmExpired"; 101 128 default: return [NSString stringWithFormat: @"<unknown: %u>", alarmType]; 102 129 } 103 130 } 104 131 132 - (NSString *)_stringForInterval:(unsigned long long)interval; 133 { 134 const unsigned long long minute = 60, hour = minute * 60, day = hour * 24, year = day * 365.26; 135 // +[NSString stringWithFormat:] in 10.1 does not support long longs: work around it by converting to unsigned ints or longs for display 136 if (interval == 0) return nil; 137 if (interval < minute) return [NSString stringWithFormat: @"%us", (unsigned)interval]; 138 if (interval < day) return [NSString stringWithFormat: @"%uh %um", (unsigned)(interval / hour), (unsigned)((interval % hour) / minute)]; 139 if (interval < 2 * day) return @"One day"; 140 if (interval < year) return [NSString stringWithFormat: @"%u days", (unsigned)(interval / day)]; 141 if (interval < 2 * year) return @"One year"; 142 return [NSString stringWithFormat: @"%lu years", (unsigned long)(interval / year)]; 143 } 144 105 145 - (void)_timerExpired:(NSTimer *)aTimer; 106 146 { 147 NSLog(@"expired: %@; now %@", [[aTimer fireDate] description], [[NSDate date] description]); 148 alarmType = PSAlarmExpired; 107 149 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self]; 108 150 [timer release]; timer = nil; … … 128 170 - (void)setForDate:(NSDate *)date atTime:(NSDate *)time; 129 171 { 130 NSCalendarDate * calTime, *calDate;172 NSCalendarDate *dateTime; 131 173 if (time == nil && date == nil) { 132 174 [self _beInvalid: @"Please specify an alarm date and time."]; return; … … 139 181 } 140 182 // XXX if calTime's date is different from the default date, complain 141 calTime = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: [time timeIntervalSinceReferenceDate]]; 142 calDate = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: [date timeIntervalSinceReferenceDate]]; 143 if (calTime == nil || calDate == nil) { 183 dateTime = [NSCalendarDate dateWithDate: date atTime: time]; 184 if (dateTime == nil) { 144 185 [self _beInvalid: @"Please specify a reasonable date and time."]; 145 186 } 146 [self setForDateAtTime: 147 [[[NSCalendarDate alloc] initWithYear: [calDate yearOfCommonEra] 148 month: [calDate monthOfYear] 149 day: [calDate dayOfMonth] 150 hour: [calTime hourOfDay] 151 minute: [calTime minuteOfHour] 152 second: [calTime secondOfMinute] 153 timeZone: nil] autorelease]]; 187 [self setForDateAtTime: dateTime]; 188 } 189 190 - (void)setRepeating:(BOOL)isRepeating; 191 { 192 repeating = isRepeating; 193 } 194 195 - (void)setSnoozeInterval:(NSTimeInterval)anInterval; 196 { 197 snoozeInterval = anInterval; 198 NSAssert(alarmType == PSAlarmExpired, @"CanÕt snooze an alarm that hasnÕt expired"); 199 alarmType = PSAlarmSnooze; 154 200 } 155 201 … … 175 221 { 176 222 if (alarmType == PSAlarmDate) [self _setIntervalFromDate]; 177 return (alarmType != PSAlarmInvalid); 223 if (alarmType == PSAlarmInvalid || 224 (alarmType == PSAlarmExpired && ![self isRepeating])) return NO; 225 return YES; 178 226 } 179 227 … … 204 252 - (NSTimeInterval)interval; 205 253 { 206 if (alarmType == PSAlarm Set || alarmType == PSAlarmDate) [self _setIntervalFromDate];254 if (alarmType == PSAlarmDate) [self _setIntervalFromDate]; 207 255 return alarmInterval; 208 256 } 209 257 210 - (void)addAlert:(PSAlert *)alert; 211 { 212 if (alerts == nil) alerts = [[NSMutableArray alloc] initWithCapacity: 4]; 213 [alerts addObject: alert]; 214 } 215 216 - (void)removeAlerts; 217 { 218 [alerts removeAllObjects]; 219 } 220 221 - (NSArray *)alerts; 222 { 223 return [[alerts copy] autorelease]; 258 - (NSTimeInterval)snoozeInterval; 259 { 260 return snoozeInterval; 261 } 262 263 - (NSTimeInterval)timeRemaining; 264 { 265 NSAssert1(alarmType == PSAlarmSet, @"CanÕt get time remaining on alarm with no timer set: %@", self); 266 return -[[NSDate date] timeIntervalSinceDate: alarmDate]; 267 } 268 269 - (void)setAlerts:(PSAlerts *)theAlerts; 270 { 271 [alerts release]; alerts = nil; 272 alerts = [theAlerts retain]; 273 } 274 275 - (PSAlerts *)alerts; 276 { 277 if (alerts == nil) alerts = [[PSAlerts alloc] init]; 278 return alerts; 279 } 280 281 - (BOOL)isRepeating; 282 { 283 return repeating; 224 284 } 225 285 … … 239 299 } 240 300 301 - (NSString *)dateTimeString; 302 { 303 return [NSString stringWithFormat: @"%@ at %@", [self dateString], [self timeString]]; 304 } 305 306 - (NSString *)nextDateTimeString; 307 { 308 if (![self isRepeating]) { 309 return nil; 310 } else { 311 NSCalendarDate *date = [[NSCalendarDate alloc] initWithTimeIntervalSinceNow: [self interval]]; 312 NSString *nextDateTimeString = [NSString stringWithFormat: @"%@ at %@", 313 [date descriptionWithCalendarFormat: dateFormat locale: locale], 314 [date descriptionWithCalendarFormat: timeFormat locale: locale]]; 315 [date release]; 316 return nextDateTimeString; 317 } 318 } 319 320 - (NSString *)intervalString; 321 { 322 const unsigned long long mval = 99, minute = 60, hour = minute * 60; 323 unsigned long long interval = [self interval]; 324 if (interval == 0) return nil; 325 if (interval == 1) return @"One second"; 326 if (interval == minute) return @"One minute"; 327 if (interval % minute == 0) return [NSString stringWithFormat: @"%u minutes", (unsigned)(interval / minute)]; 328 if (interval <= mval) return [NSString stringWithFormat: @"%u seconds", (unsigned)interval]; 329 if (interval == hour) return @"One hour"; 330 if (interval % hour == 0) return [NSString stringWithFormat: @"%u hours", (unsigned)(interval / hour)]; 331 if (interval <= mval * minute) return [NSString stringWithFormat: @"%u minutes", (unsigned)(interval / minute)]; 332 if (interval <= mval * hour) return [NSString stringWithFormat: @"%u hours", (unsigned)(interval / hour)]; 333 return [self _stringForInterval: interval]; 334 } 335 241 336 - (NSString *)timeRemainingString; 242 337 { 243 static const unsigned long long minute = 60, hour = minute * 60, day = hour * 24, year = day * 365.26; 244 unsigned long long interval = [self interval]; 245 // +[NSString stringWithFormat:] in 10.1 does not support long longs: work around it by converting to unsigned ints or longs for display 246 if (interval == 0) return @"ÇexpiredÈ"; 247 if (interval < minute) return [NSString stringWithFormat: @"%us", (unsigned)interval]; 248 if (interval < day) return [NSString stringWithFormat: @"%uh %um", (unsigned)(interval / hour), (unsigned)((interval % hour) / minute)]; 249 if (interval < year) return [NSString stringWithFormat: @"%u days", (unsigned)(interval / day)]; 250 if (interval < 2 * year) return @"One year"; 251 return [NSString stringWithFormat: @"%lu years", (unsigned long)(interval / year)]; 338 NSString *timeRemainingString = [self _stringForInterval: llround([self timeRemaining])]; 339 340 if (timeRemainingString == nil) return @"ÇexpiredÈ"; 341 return timeRemainingString; 342 } 343 344 - (NSAttributedString *)prettyDescription; 345 { 346 NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init]; 347 NSAttributedString *alertList = [alerts prettyList]; 348 349 [string appendAttributedString: 350 [[NSString stringWithFormat: @"At alarm time for Ò%@Ó:\n", [self message]] small]]; 351 if (alertList != nil) { 352 [string appendAttributedString: alertList]; 353 } else { 354 [string appendAttributedString: [@"Do nothing." small]]; 355 } 356 if ([self isRepeating]) { 357 [string appendAttributedString: 358 [[NSString stringWithFormat: @"\nAlarm repeats every %@.", [[self intervalString] lowercaseString]] small]]; 359 } 360 return [string autorelease]; 252 361 } 253 362 … … 256 365 - (BOOL)setTimer; 257 366 { 258 switch (alarmType) { 259 case PSAlarmDate: if (![self isValid]) return NO; 260 case PSAlarmInterval: 261 timer = [NSTimer scheduledTimerWithTimeInterval: alarmInterval target: self selector: @selector(_timerExpired:) userInfo: nil repeats: NO]; 262 if (timer != nil) { 263 [timer retain]; 264 alarmType = PSAlarmSet; 265 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerSetNotification object: self]; 266 return YES; 267 } 268 default: 367 if (alarmType == PSAlarmExpired) { 368 if ([self isRepeating]) { 369 [self _setDateFromInterval]; 370 } else { 371 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmDiedNotification object: self]; 269 372 return NO; 270 } 373 } 374 } else if (alarmType == PSAlarmDate) { 375 if (![self isValid]) return NO; 376 } else if (alarmType == PSAlarmSnooze) { 377 [self _setAlarmDate: [NSCalendarDate dateWithTimeIntervalSinceNow: snoozeInterval]]; 378 } else if (alarmType != PSAlarmInterval) { 379 return NO; 380 } 381 timer = [NSTimer scheduledTimerWithTimeInterval: (alarmType == PSAlarmSnooze ? snoozeInterval : alarmInterval) target: self selector: @selector(_timerExpired:) userInfo: nil repeats: NO]; 382 if (timer == nil) return NO; 383 [timer retain]; 384 alarmType = PSAlarmSet; 385 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerSetNotification object: self]; 386 // NSLog(@"set: %@; now %@; remaining %@", [[timer fireDate] description], [[NSDate date] description], [self timeRemainingString]); 387 return YES; 271 388 } 272 389 … … 274 391 { 275 392 [timer invalidate]; [timer release]; timer = nil; 393 [self setRepeating: NO]; 276 394 } 277 395 … … 300 418 } 301 419 302 #pragma mark archiving 420 #pragma mark property list serialization (Pester 1.1) 421 422 - (NSDictionary *)propertyListRepresentation; 423 { 424 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 5]; 425 if (![self isValid]) return nil; 426 [dict setObject: [self _alarmTypeString] forKey: PLAlarmType]; 427 switch (alarmType) { 428 case PSAlarmDate: 429 case PSAlarmSet: 430 [dict setObject: [NSNumber numberWithDouble: [alarmDate timeIntervalSinceReferenceDate]] forKey: PLAlarmDate]; 431 break; 432 case PSAlarmSnooze: 433 case PSAlarmInterval: 434 case PSAlarmExpired: 435 [dict setObject: [NSNumber numberWithDouble: alarmInterval] forKey: PLAlarmInterval]; 436 [dict setObject: [NSNumber numberWithBool: repeating] forKey: PLAlarmRepeating]; 437 break; 438 default: 439 NSAssert1(NO, @"CanÕt save alarm type %@", [self _alarmTypeString]); 440 break; 441 } 442 if (snoozeInterval != 0) 443 [dict setObject: [NSNumber numberWithDouble: snoozeInterval] forKey: PLAlarmSnoozeInterval]; 444 [dict setObject: alarmMessage forKey: PLAlarmMessage]; 445 if (alerts != nil) { 446 [dict setObject: [alerts propertyListRepresentation] forKey: PLAlarmAlerts]; 447 } 448 return dict; 449 } 450 451 - (id)initWithPropertyList:(NSDictionary *)dict; 452 { 453 if ( (self = [self init]) != nil) { 454 PSAlerts *alarmAlerts; 455 alarmType = [self _alarmTypeForString: [dict objectForRequiredKey: PLAlarmType]]; 456 switch (alarmType) { 457 case PSAlarmDate: 458 case PSAlarmSet: 459 { NSCalendarDate *date = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate: [[dict objectForRequiredKey: PLAlarmDate] doubleValue]]; 460 [self _setAlarmDate: date]; 461 [date release]; 462 } 463 break; 464 case PSAlarmSnooze: // snooze interval set but not confirmed; ignore 465 alarmType = PSAlarmExpired; 466 case PSAlarmInterval: 467 case PSAlarmExpired: 468 alarmInterval = [[dict objectForRequiredKey: PLAlarmInterval] doubleValue]; 469 repeating = [[dict objectForRequiredKey: PLAlarmRepeating] boolValue]; 470 break; 471 default: 472 NSAssert1(NO, @"CanÕt load alarm type %@", [self _alarmTypeString]); 473 break; 474 } 475 snoozeInterval = [[dict objectForKey: PLAlarmSnoozeInterval] doubleValue]; 476 [self setMessage: [dict objectForRequiredKey: PLAlarmMessage]]; 477 alarmAlerts = [[PSAlerts alloc] initWithPropertyList: [dict objectForRequiredKey: PLAlarmAlerts]]; 478 [self setAlerts: alarmAlerts]; 479 [alarmAlerts release]; 480 if (alarmType == PSAlarmSet) { 481 alarmType = PSAlarmDate; 482 [self setTimer]; 483 } 484 if (alarmType == PSAlarmExpired) { 485 [self setTimer]; 486 if (alarmType == PSAlarmExpired) { // failed to restart 487 [self release]; 488 self = nil; 489 } 490 } 491 } 492 return self; 493 } 494 495 #pragma mark archiving (Pester 1.0) 303 496 304 497 - (void)encodeWithCoder:(NSCoder *)coder; … … 324 517 - (id)initWithCoder:(NSCoder *)coder; 325 518 { 326 if ( (self = [super init]) != nil) { 519 if ( (self = [self init]) != nil) { 520 PSAlerts *legacyAlerts = [[PSAlerts alloc] initWithPesterVersion1Alerts]; 521 [self setAlerts: legacyAlerts]; 522 [legacyAlerts release]; 327 523 [coder decodeValueOfObjCType: @encode(PSAlarmType) at: &alarmType]; 328 524 switch (alarmType) { -
trunk/Cocoa/Pester/Source/PSAlarmAlertController.h
r34 r53 13 13 14 14 @interface PSAlarmAlertController : NSObject { 15 15 NSMutableSet *pendingAlerts; 16 ProcessSerialNumber frontmostApp; 17 BOOL appWasHidden; 16 18 } 17 19 -
trunk/Cocoa/Pester/Source/PSAlarmAlertController.m
r40 r53 8 8 9 9 #import "PSAlarmAlertController.h" 10 #import "PSAlert.h" 11 #import "PSAlerts.h" 10 12 11 13 NSString * const PSAlarmAlertStopNotification = @"PSAlarmAlertStopNotification"; … … 23 25 } 24 26 27 - (void)_resumeAlarm:(PSAlarm *)alarm; 28 { 29 [[NSNotificationCenter defaultCenter] removeObserver: self]; 30 [alarm setTimer]; // if snooze not set and not repeating, alarm will die 31 if (frontmostApp.highLongOfPSN != 0 || frontmostApp.lowLongOfPSN != 0) { 32 SetFrontProcess(&frontmostApp); 33 if (appWasHidden) 34 [NSApp hide: self]; 35 } 36 } 37 38 - (void)_alertCompleted:(NSNotification *)notification; 39 { 40 PSAlert *alert = [[notification userInfo] objectForKey: @"alert"]; 41 unsigned count = [pendingAlerts count]; 42 [pendingAlerts removeObject: alert]; 43 NSLog(@"removed: %@; still pending: %@", alert, [pendingAlerts description]); 44 NSLog(@"alarm: %@ retainCount %d", [notification object], [[notification object] retainCount]); 45 NSAssert2([pendingAlerts count] == count - 1, @"alert not in set: %@\n%@", alert, notification); 46 if ([pendingAlerts count] == 0) { 47 [self _resumeAlarm: [notification object]]; 48 [self release]; 49 } 50 } 51 25 52 - (id)initWithAlarm:(PSAlarm *)alarm; 26 53 { 27 54 if ( (self = [super init]) != nil) { 28 [[alarm alerts] makeObjectsPerformSelector: @selector(triggerForAlarm:) 29 withObject: alarm]; 30 [NSApp activateIgnoringOtherApps: YES]; 55 PSAlerts *alerts = [alarm alerts]; 56 NSArray *allAlerts = [alerts allAlerts]; 57 if ([allAlerts count] == 0) { 58 [self _resumeAlarm: alarm]; 59 } else { 60 pendingAlerts = [[NSMutableSet alloc] init]; 61 [pendingAlerts addObjectsFromArray: allAlerts]; 62 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alertCompleted:) 63 name: PSAlarmAlertCompletedNotification object: alarm]; 64 [self retain]; // release in _alertCompleted: 65 } 66 [alerts triggerForAlarm: alarm]; 67 if ([alerts requirePesterFrontmost] && ![NSApp isActive]) { // restore frontmost process afterward 68 NSDictionary *activeProcessInfo = [[NSWorkspace sharedWorkspace] activeApplication]; 69 frontmostApp.highLongOfPSN = [[activeProcessInfo objectForKey: @"NSApplicationProcessSerialNumberHigh"] longValue]; 70 frontmostApp.lowLongOfPSN = [[activeProcessInfo objectForKey: @"NSApplicationProcessSerialNumberLow"] longValue]; 71 appWasHidden = [NSApp isHidden]; 72 [NSApp activateIgnoringOtherApps: YES]; 73 } 31 74 } 32 75 return self; 33 76 } 34 77 78 - (void)dealloc; 79 { 80 NSLog(@"%@ dealloc", self); 81 [pendingAlerts release]; 82 [super dealloc]; 83 } 84 35 85 @end -
trunk/Cocoa/Pester/Source/PSAlarmNotifierController.h
r34 r53 9 9 #import <AppKit/AppKit.h> 10 10 11 @class NJRIntervalField; 11 12 @class PSAlarm; 12 13 … … 14 15 IBOutlet NSTextField *messageField; 15 16 IBOutlet NSTextField *dateField; 17 IBOutlet NSTextField *intervalField; 18 IBOutlet NSTextField *nextDateField; 19 IBOutlet NJRIntervalField *snoozeIntervalField; 20 IBOutlet NSButton *okButton; 21 IBOutlet NSButton *snoozeButton; 22 NSTimer *updateTimer; 23 PSAlarm *alarm; 24 BOOL canSnooze; 16 25 } 17 26 18 - (id)initWithAlarm:(PSAlarm *)a larm;27 - (id)initWithAlarm:(PSAlarm *)anAlarm; 19 28 20 - (IBAction)close:(NSButton *)sender; 29 - (IBAction)close:(id)sender; 30 - (IBAction)snooze:(NSButton *)sender; 31 - (IBAction)stopRepeating:(NSButton *)sender; 21 32 22 33 @end -
trunk/Cocoa/Pester/Source/PSAlarmNotifierController.m
r43 r53 10 10 #import "PSAlarmAlertController.h" 11 11 #import "PSAlarm.h" 12 #import "PSNotifierAlert.h" 13 #import "NJRIntervalField.h" 14 15 static NSString * const PSAlarmSnoozeInterval = @"Pester alarm snooze interval"; // NSUserDefaults key 16 17 @interface PSAlarmNotifierController (Private) 18 19 - (void)update:(id)sender; 20 - (void)updateNextDateDisplay:(id)sender; 21 22 @end 12 23 13 24 @implementation PSAlarmNotifierController … … 15 26 // XXX should use NSNonactivatingPanelMask on 10.2 16 27 17 - (id)initWithAlarm:(PSAlarm *)a larm;28 - (id)initWithAlarm:(PSAlarm *)anAlarm; 18 29 { 19 30 if ([self initWithWindowNibName: @"Notifier"]) { 20 [[self window] center]; 31 NSWindow *window = [self window]; 32 NSRect frameRect = [window frame]; 33 alarm = [anAlarm retain]; 21 34 [messageField setStringValue: [alarm message]]; 22 [dateField setStringValue: 23 [NSString stringWithFormat: @"%@ at %@", [alarm dateString], [alarm timeString]]]; 24 [[self window] makeKeyAndOrderFront: nil]; 25 [[self window] orderFrontRegardless]; 35 [dateField setStringValue: [alarm dateTimeString]]; 36 if (![snoozeIntervalField setInterval: [alarm snoozeInterval]] && 37 ![snoozeIntervalField setInterval: [[[NSUserDefaults standardUserDefaults] objectForKey: PSAlarmSnoozeInterval] doubleValue]]) 38 [snoozeIntervalField setInterval: 15 * 60]; // 15 minutes 39 if ([alarm isRepeating]) { 40 [intervalField setStringValue: 41 [NSString stringWithFormat: @"every %@", [[alarm intervalString] lowercaseString]]]; 42 [self updateNextDateDisplay: nil]; 43 updateTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateNextDateDisplay:) userInfo: nil repeats: YES]; 44 frameRect.size = [window maxSize]; 45 } else { 46 frameRect.size = [window minSize]; 47 } 48 [window setFrame: frameRect display: NO]; 49 [window center]; 50 [window makeKeyAndOrderFront: nil]; 51 [window orderFrontRegardless]; 26 52 } 27 53 return self; 54 } 55 56 - (void)dealloc; 57 { 58 [alarm release]; 59 [updateTimer invalidate]; updateTimer = nil; 60 [super dealloc]; 61 } 62 63 - (void)updateNextDateDisplay:(id)sender; 64 { 65 if (!canSnooze) { 66 NSString *nextDateTimeString = [alarm nextDateTimeString]; 67 if (nextDateTimeString == nil) { // no longer repeating 68 [updateTimer invalidate]; updateTimer = nil; 69 } else { 70 [nextDateField setStringValue: nextDateTimeString]; 71 } 72 } 73 } 74 75 - (void)update:(id)sender; 76 { 77 canSnooze = [snoozeIntervalField interval] != 0; 78 if (canSnooze) [nextDateField setStringValue: @"after snooze"]; 79 [snoozeButton setEnabled: canSnooze]; 80 [canSnooze ? snoozeButton : okButton setKeyEquivalent: @"\r"]; 81 [canSnooze ? okButton : snoozeButton setKeyEquivalent: @""]; 28 82 } 29 83 … … 32 86 [PSAlarmAlertController stopAlerts: sender]; 33 87 [self close]; 88 [[PSNotifierAlert alert] completedForAlarm: alarm]; 89 } 90 91 - (IBAction)snooze:(NSButton *)sender; 92 { 93 NSTimeInterval snoozeInterval = [snoozeIntervalField interval]; 94 [alarm setSnoozeInterval: snoozeInterval]; 95 [[NSUserDefaults standardUserDefaults] setObject: [NSNumber numberWithDouble: snoozeInterval] forKey: PSAlarmSnoozeInterval]; 96 [self close: sender]; 97 } 98 99 - (IBAction)stopRepeating:(NSButton *)sender; 100 { 101 NSWindow *window = [self window]; 102 NSRect frameRect = [window frame]; 103 NSSize newSize = [window minSize]; 104 105 [alarm setRepeating: NO]; 106 [sender setEnabled: NO]; 107 frameRect.origin.y += frameRect.size.height - newSize.height; 108 frameRect.size = newSize; 109 [window setFrame: frameRect display: YES animate: YES]; 34 110 } 35 111 36 112 @end 113 114 @implementation PSAlarmNotifierController (NSControlSubclassDelegate) 115 116 - (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string errorDescription:(NSString *)error; 117 { 118 if (control == snoozeIntervalField) 119 [snoozeIntervalField handleDidFailToFormatString: string errorDescription: error label: @"snooze interval"]; 120 return NO; 121 } 122 123 - (void)control:(NSControl *)control didFailToValidatePartialString:(NSString *)string errorDescription:(NSString *)error; 124 { 125 // NSLog(@"UPDATING FROM validation"); 126 [self update: control]; // switch to snooze if someone types something weird... 127 } 128 129 - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector; 130 { 131 // NSLog(@"UPDATING from textView: %@", NSStringFromSelector(commandSelector)); 132 if (commandSelector == @selector(cancel:)) { 133 // if someone just wants the stupid thing to go away and presses escape, donÕt hinder them 134 [self close: control]; 135 return YES; 136 } 137 // if someone invokes the default button or switches fields, donÕt override it 138 if (commandSelector == @selector(insertNewline:) || 139 commandSelector == @selector(insertTab:) || 140 commandSelector == @selector(insertBacktab:)) return NO; 141 [self update: control]; // ...or if they type a navigation key... 142 return NO; // we donÕt handle it 143 } 144 145 @end 146 147 @implementation PSAlarmNotifierController (NSControlSubclassNotifications) 148 149 - (void)controlTextDidChange:(NSNotification *)notification; 150 { 151 // NSLog(@"UPDATING FROM controlTextDidChange: %@", [notification object]); 152 [self update: [notification object]]; // ...or if they modify the snooze interval 153 } 154 155 @end 156 157 @implementation PSAlarmNotifierController (NSWindowNotifications) 158 159 - (void)windowWillClose:(NSNotification *)notification; 160 { 161 // canÕt rely on dealloc to invalidate the timer, because it retains this object 162 [updateTimer invalidate]; updateTimer = nil; 163 [self release]; // in non-document-based apps, this is needed; see docs 164 } 165 166 @end -
trunk/Cocoa/Pester/Source/PSAlarmSetController.h
r41 r53 11 11 12 12 @class NJRFSObjectSelector; 13 @class NJRIntervalField; 13 14 @class NJRQTMediaPopUpButton; 14 15 @class NJRVoicePopUpButton; … … 17 18 IBOutlet NSTextField *messageField; 18 19 IBOutlet NSMatrix *inAtMatrix; 19 IBOutlet N STextField *timeInterval;20 IBOutlet NJRIntervalField *timeInterval; 20 21 IBOutlet NSPopUpButton *timeIntervalUnits; 21 22 IBOutlet NSButton *timeIntervalRepeats; … … 23 24 IBOutlet NSTextField *timeDate; 24 25 IBOutlet NSPopUpButton *timeDateCompletions; // XXX should go away when bug preventing both formatters and popup menus from existing is fixed 26 IBOutlet NSButtonCell *editAlert; 27 IBOutlet NSTextField *alertView; 28 IBOutlet NSTabView *alertTabs; 25 29 IBOutlet NSButtonCell *displayMessage; 26 30 IBOutlet NSButton *bounceDockIcon; … … 35 39 IBOutlet NJRVoicePopUpButton *voice; 36 40 IBOutlet NSButton *scriptSelectButton; 41 IBOutlet NSButtonCell *wakeUp; 37 42 IBOutlet NSTextField *timeSummary; 43 IBOutlet NSButton *cancelButton; 38 44 IBOutlet NSButton *setButton; 39 45 NSString *status; … … 46 52 - (IBAction)dateCompleted:(NSPopUpButton *)sender; 47 53 - (IBAction)inAtChanged:(id)sender; 54 - (IBAction)editAlertChanged:(id)sender; 48 55 - (IBAction)playSoundChanged:(id)sender; 49 56 - (IBAction)doScriptChanged:(id)sender; -
trunk/Cocoa/Pester/Source/PSAlarmSetController.m
r51 r53 9 9 #import "PSAlarmSetController.h" 10 10 #import "PSAlarmAlertController.h" 11 #import "PSPowerManager.h" 11 12 #import "NJRDateFormatter.h" 12 13 #import "NJRFSObjectSelector.h" 14 #import "NJRIntervalField.h" 13 15 #import "NJRQTMediaPopUpButton.h" 14 16 #import "NJRVoicePopUpButton.h" 17 #import "NSString-NJRExtensions.h" 18 #import "NSAttributedString-NJRExtensions.h" 19 #import "NSCalendarDate-NJRExtensions.h" 15 20 #import <Carbon/Carbon.h> 16 21 22 #import "PSAlerts.h" 17 23 #import "PSDockBounceAlert.h" 18 24 #import "PSScriptAlert.h" … … 38 44 ¥ If you feed NSCalendarDate dateWithNaturalLanguageString: an " AM"/" PM" locale, it doesn't accept that date format. 39 45 ¥ descriptions for %X and %x are reversed (time zone is in %X, not %x) 46 ¥ NSComboBox data source issues, canÕt have it appear as ÒtodayÓ because the formatter doesnÕt like that. Should be able to enter text into the data source and have the formatter process it without altering it. 40 47 ¥ too hard to implement date-only or time-only formatters 41 48 ¥ should be able to specify that natural language favors date or time (10 = 10th of month, not 10am) … … 44 51 */ 45 52 53 static NSString * const PSAlertsSelected = @"Pester alerts selected"; // NSUserDefaults key 54 static NSString * const PSAlertsEditing = @"Pester alerts editing"; // NSUserDefaults key 55 46 56 @interface PSAlarmSetController (Private) 47 57 58 - (void)_readAlerts:(PSAlerts *)alerts; 59 - (BOOL)_setAlerts; 48 60 - (void)_stopUpdateTimer; 49 61 … … 54 66 - (void)awakeFromNib; 55 67 { 68 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 56 69 alarm = [[PSAlarm alloc] init]; 57 70 [[self window] center]; … … 60 73 [timeDate setFormatter: [[NJRDateFormatter alloc] initWithDateFormat: [NJRDateFormatter localizedDateFormatIncludingWeekday: NO] allowNaturalLanguage: YES]]; 61 74 { 62 NSArray *dayNames = [ [NSUserDefaults standardUserDefaults]arrayForKey:75 NSArray *dayNames = [defaults arrayForKey: 63 76 NSWeekDayNameArray]; 64 77 NSArray *completions = [timeDateCompletions itemTitles]; … … 83 96 } 84 97 } 98 [editAlert setIntValue: [defaults boolForKey: PSAlertsEditing]]; 99 { 100 NSDictionary *plAlerts = [defaults dictionaryForKey: PSAlertsSelected]; 101 PSAlerts *alerts; 102 if (plAlerts == nil) { 103 alerts = [[PSAlerts alloc] initWithPesterVersion1Alerts]; 104 } else { 105 NS_DURING 106 alerts = [[PSAlerts alloc] initWithPropertyList: plAlerts]; 107 NS_HANDLER 108 NSRunAlertPanel(@"Unable to restore alerts", @"Pester could not restore recent alert information for one or more alerts in the Set Alarm window. The default set of alerts will be used instead.\n\n%@", nil, nil, nil, [localException reason]); 109 alerts = [[PSAlerts alloc] initWithPesterVersion1Alerts]; 110 NS_ENDHANDLER 111 } 112 [self _readAlerts: alerts]; 113 } 85 114 [timeDate setObjectValue: [NSDate date]]; 86 [self inAtChanged: nil]; 115 [self inAtChanged: nil]; // by convention, if sender is nil, we're initializing 87 116 [self playSoundChanged: nil]; 88 117 [self doScriptChanged: nil]; 89 118 [self doSpeakChanged: nil]; 119 [self editAlertChanged: nil]; 90 120 [script setFileTypes: [NSArray arrayWithObjects: @"applescript", @"script", NSFileTypeForHFSTypeCode(kOSAFileType), NSFileTypeForHFSTypeCode('TEXT'), nil]]; 91 121 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(silence:) name: PSAlarmAlertStopNotification object: nil]; 92 122 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playSoundChanged:) name: NJRQTMediaPopUpButtonMovieChangedNotification object: sound]; 93 [voice setDelegate: self]; 94 // XXX still broken under 10.2, check 10.1 behavior and see if subclassing NSComboBox will help 95 // if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) { 96 // XXX workaround for 10.1.x bug which sets the first responder to the wrong field, but it works if I set the initial first responder to nil... go figure. 97 [[self window] setInitialFirstResponder: nil]; 98 // } 123 [voice setDelegate: self]; // XXX why don't we do this in IB? It should use the accessor... 124 [wakeUp setEnabled: [PSPowerManager autoWakeSupported]]; 125 // XXX workaround for 10.1.x and 10.2.x bug which sets the first responder to the wrong field alternately, but it works if I set the initial first responder to nil... go figure. 126 [[self window] setInitialFirstResponder: nil]; 99 127 [[self window] makeKeyAndOrderFront: nil]; 100 128 } … … 110 138 } 111 139 140 // XXX with -[NSControl currentEditor] don't need to compare? Also check -[NSControl validateEditing] 112 141 - (id)objectValueForTextField:(NSTextField *)field whileEditing:(id)sender; 113 142 { … … 124 153 } 125 154 155 #pragma mark date/interval setting 156 126 157 - (void)setAlarmDateAndInterval:(id)sender; 127 158 { 128 159 if (isInterval) { 129 [alarm setInterval: 130 [[self objectValueForTextField: timeInterval whileEditing: sender] intValue] * 131 [timeIntervalUnits selectedTag]]; 160 [alarm setInterval: [timeInterval interval]]; 132 161 } else { 133 162 [alarm setForDate: [self objectValueForTextField: timeDate whileEditing: sender] … … 141 170 } 142 171 143 // XXX use OACalendar ?172 // XXX use OACalendar in popup like Palm Desktop? 144 173 145 174 - (IBAction)updateDateDisplay:(id)sender; … … 193 222 [timeDateCompletions setEnabled: !isInterval]; 194 223 if (sender != nil) 195 [[self window] makeFirstResponder: isInterval ? timeInterval : timeOfDay];224 [[self window] makeFirstResponder: isInterval ? (NSTextField *)timeInterval : timeOfDay]; 196 225 // NSLog(@"UPDATING FROM inAtChanged"); 197 226 [self update: nil]; 198 227 } 228 229 - (IBAction)dateCompleted:(NSPopUpButton *)sender; 230 { 231 [timeDate setStringValue: [sender titleOfSelectedItem]]; 232 [self update: sender]; 233 } 234 235 #pragma mark alert editing 236 237 - (IBAction)editAlertChanged:(id)sender; 238 { 239 BOOL editAlertSelected = [editAlert intValue]; 240 NSView *editAlertControl = [editAlert controlView]; 241 NSWindow *window = [self window]; 242 NSRect frame = [window frame]; 243 if (editAlertSelected) { 244 NSSize editWinSize = [window maxSize]; 245 [editAlertControl setNextKeyView: [displayMessage controlView]]; 246 frame.origin.y += frame.size.height - editWinSize.height; 247 frame.size = editWinSize; 248 [window setFrame: frame display: (sender != nil) animate: (sender != nil)]; 249 [self updateDateDisplay: sender]; 250 [alertTabs selectTabViewItemWithIdentifier: @"edit"]; 251 } else { 252 NSSize viewWinSize = [window minSize]; 253 NSRect textFrame = [alertView frame]; 254 float textHeight; 255 if (![self _setAlerts]) { 256 [alertView setStringValue: [NSString stringWithFormat: @"CouldnÕt process alert information.\n%@", status]]; 257 } else { 258 NSAttributedString *string = [[alarm alerts] prettyList]; 259 if (string == nil) { 260 [alertView setStringValue: @"Do nothing. Click the button labeled ÒEditÓ to add an alert."]; 261 } else { 262 [alertView setAttributedStringValue: string]; 263 [self updateDateDisplay: sender]; 264 } 265 } 266 if (sender != nil) { // nil == we're initializing, don't mess with focus 267 NSResponder *oldResponder = [window firstResponder]; 268 // make sure focus doesn't get stuck in the edit tab: it is confusing and leaves behind artifacts 269 if (oldResponder == editAlertControl || [oldResponder isKindOfClass: [NSView class]] && [(NSView *)oldResponder isDescendantOf: alertTabs]) 270 [window makeFirstResponder: messageField]; // would use editAlertControl, but can't get it to display anomaly-free. 271 [self silence: sender]; 272 } 273 // allow height to expand, though not arbitrarily (should still fit on an 800x600 screen) 274 textHeight = [[alertView cell] cellSizeForBounds: NSMakeRect(0, 0, textFrame.size.width, 400)].height; 275 textFrame.origin.y += textFrame.size.height - textHeight; 276 textFrame.size.height = textHeight; 277 [alertView setFrame: textFrame]; 278 viewWinSize.height += textHeight; 279 [alertTabs selectTabViewItemWithIdentifier: @"view"]; 280 frame.origin.y += frame.size.height - viewWinSize.height; 281 frame.size = viewWinSize; 282 [window setFrame: frame display: (sender != nil) animate: (sender != nil)]; 283 [editAlertControl setNextKeyView: cancelButton]; 284 } 285 if (sender != nil) { 286 [[NSUserDefaults standardUserDefaults] setBool: editAlertSelected forKey: PSAlertsEditing]; 287 } 288 } 289 199 290 200 291 - (IBAction)playSoundChanged:(id)sender; … … 206 297 [soundRepetitionStepper setEnabled: canRepeat]; 207 298 [soundRepetitionsLabel setTextColor: canRepeat ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]]; 208 if (playSoundSelected && sender != nil)299 if (playSoundSelected && sender == playSound) { 209 300 [[self window] makeFirstResponder: sound]; 301 } 210 302 } 211 303 … … 234 326 [script setEnabled: doScriptSelected]; 235 327 [scriptSelectButton setEnabled: doScriptSelected]; 236 if (doScriptSelected && sender != nil) 328 if (doScriptSelected && sender != nil) { 237 329 [[self window] makeFirstResponder: scriptSelectButton]; 330 if ([script alias] == nil) [scriptSelectButton performClick: sender]; 331 } 238 332 } 239 333 240 334 - (IBAction)doSpeakChanged:(id)sender; 241 335 { 242 BOOL doSpeakSelected = [doSpeak intValue];336 BOOL doSpeakSelected = [doSpeak state] == NSOnState; 243 337 [voice setEnabled: doSpeakSelected]; 244 338 if (doSpeakSelected && sender != nil) … … 246 340 } 247 341 248 - (IBAction)dateCompleted:(NSPopUpButton *)sender; 249 { 250 [timeDate setStringValue: [sender titleOfSelectedItem]]; 251 [self update: sender]; 252 } 342 - (void)_readAlerts:(PSAlerts *)alerts; 343 { 344 NSEnumerator *e = [alerts alertEnumerator]; 345 PSAlert *alert; 346 347 [alarm setAlerts: alerts]; 348 349 // turn off all alerts 350 [bounceDockIcon setState: NSOffState]; 351 [doScript setIntValue: NO]; 352 [displayMessage setIntValue: NO]; 353 [playSound setIntValue: NO]; 354 [doSpeak setIntValue: NO]; 355 356 while ( (alert = [e nextObject]) != nil) { 357 if ([alert isKindOfClass: [PSDockBounceAlert class]]) { 358 [bounceDockIcon setState: NSOnState]; 359 } else if ([alert isKindOfClass: [PSScriptAlert class]]) { 360 [doScript setIntValue: YES]; 361 [script setAlias: [(PSScriptAlert *)alert scriptFileAlias]]; 362 } else if ([alert isKindOfClass: [PSNotifierAlert class]]) { 363 [displayMessage setIntValue: YES]; 364 } else if ([alert isKindOfClass: [PSBeepAlert class]]) { 365 unsigned int repetitions = [(PSBeepAlert *)alert repetitions]; 366 [playSound setIntValue: YES]; 367 [sound setAlias: nil]; 368 [soundRepetitions setIntValue: repetitions]; 369 [soundRepetitionStepper setIntValue: repetitions]; 370 } else if ([alert isKindOfClass: [PSMovieAlert class]]) { 371 unsigned int repetitions = [(PSMovieAlert *)alert repetitions]; 372 [playSound setIntValue: YES]; 373 [sound setAlias: [(PSMovieAlert *)alert movieFileAlias]]; 374 [soundRepetitions setIntValue: repetitions]; 375 [soundRepetitionStepper setIntValue: repetitions]; 376 } else if ([alert isKindOfClass: [PSSpeechAlert class]]) { 377 [doSpeak setIntValue: YES]; 378 [voice setVoice: [(PSSpeechAlert *)alert voice]]; 379 } 380 } 381 } 382 383 - (BOOL)_setAlerts; 384 { 385 PSAlerts *alerts = [alarm alerts]; 386 387 [alerts removeAlerts]; 388 NS_DURING 389 // dock bounce alert 390 if ([bounceDockIcon state] == NSOnState) 391 [alerts addAlert: [PSDockBounceAlert alert]]; 392 // script alert 393 if ([doScript intValue]) { 394 BDAlias *scriptFileAlias = [script alias]; 395 if (scriptFileAlias == nil) { 396 [self setStatus: @"Unable to set script alert (no script specified?)"]; 397 return NO; 398 } 399 [alerts addAlert: [PSScriptAlert alertWithScriptFileAlias: scriptFileAlias]]; 400 } 401 // notifier alert 402 if ([displayMessage intValue]) 403 [alerts addAlert: [PSNotifierAlert alert]]; 404 // sound alerts 405 if ([playSound intValue]) { 406 BDAlias *soundAlias = [sound selectedAlias]; 407 unsigned short numReps = [soundRepetitions intValue]; 408 if (soundAlias == nil) // beep alert 409 [alerts addAlert: [PSBeepAlert alertWithRepetitions: numReps]]; 410 else // movie alert 411 [alerts addAlert: [PSMovieAlert alertWithMovieFileAlias: soundAlias repetitions: numReps]]; 412 } 413 // speech alert 414 if ([doSpeak intValue]) 415 [alerts addAlert: [PSSpeechAlert alertWithVoice: [voice titleOfSelectedItem]]]; 416 [[NSUserDefaults standardUserDefaults] setObject: [alerts propertyListRepresentation] forKey: PSAlertsSelected]; 417 NS_HANDLER 418 [self setStatus: [localException reason]]; 419 NS_VALUERETURN(NO, BOOL); 420 NS_ENDHANDLER 421 return YES; 422 } 423 424 #pragma mark actions 253 425 254 426 // to ensure proper updating of interval, this should be the only method by which the window is shown (e.g. from the Alarm menu) … … 256 428 { 257 429 if (![[self window] isVisible]) { 430 NSDate *today = [NSCalendarDate dateForDay: [NSDate date]]; 431 if ([(NSDate *)[timeDate objectValue] compare: today] == NSOrderedAscending) { 432 [timeDate setObjectValue: today]; 433 } 258 434 [self update: self]; 259 // XXX otherwise, first responder appears to alternate every time the window is shown?!And if you set the initial first responder, you can't tab in the window. :(435 // XXX bug workaround - otherwise, first responder appears to alternate every time the window is shown. And if you set the initial first responder, you can't tab in the window. :( 260 436 [[self window] makeFirstResponder: [[self window] initialFirstResponder]]; 261 437 } … … 266 442 { 267 443 // set alerts before setting alarm... 268 [alarm removeAlerts]; 269 // dock bounce alert 270 if ([bounceDockIcon state] == NSOnState) 271 [alarm addAlert: [PSDockBounceAlert alert]]; 272 // script alert 273 if ([doScript intValue]) { 274 BDAlias *scriptFileAlias = [script alias]; 275 if (scriptFileAlias == nil) { 276 [self setStatus: @"Unable to set script alert (no script specified?)"]; 277 return; 278 } 279 [alarm addAlert: [PSScriptAlert alertWithScriptFileAlias: scriptFileAlias]]; 280 } 281 // notifier alert 282 if ([displayMessage intValue]) 283 [alarm addAlert: [PSNotifierAlert alert]]; 284 // sound alerts 285 if ([playSound intValue]) { 286 BDAlias *soundAlias = [sound selectedAlias]; 287 unsigned short numReps = [soundRepetitions intValue]; 288 if (soundAlias == nil) // beep alert 289 [alarm addAlert: [PSBeepAlert alertWithRepetitions: numReps]]; 290 else // movie alert 291 [alarm addAlert: [PSMovieAlert alertWithMovieFileAlias: soundAlias repetitions: numReps]]; 292 } 293 // speech alert 294 if ([doSpeak intValue]) 295 [alarm addAlert: [PSSpeechAlert alertWithVoice: [voice titleOfSelectedItem]]]; 444 if (![self _setAlerts]) return; 296 445 297 446 // set alarm 298 447 [self setAlarmDateAndInterval: sender]; 448 [alarm setRepeating: [timeIntervalRepeats state] == NSOnState]; 299 449 [alarm setMessage: [messageField stringValue]]; 300 450 if (![alarm setTimer]) { … … 319 469 @implementation PSAlarmSetController (NSControlSubclassDelegate) 320 470 471 - (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string errorDescription:(NSString *)error; 472 { 473 if (control == timeInterval) 474 [timeInterval handleDidFailToFormatString: string errorDescription: error label: @"alarm interval"]; 475 return NO; 476 } 477 321 478 - (void)control:(NSControl *)control didFailToValidatePartialString:(NSString *)string errorDescription:(NSString *)error; 322 479 { 323 unichar c;324 int tag;325 unsigned length = [string length];326 if (control != timeInterval || length == 0) return;327 c = [string characterAtIndex: length - 1];328 switch (c) {329 case 's': case 'S': tag = 1; break;330 case 'm': case 'M': tag = 60; break;331 case 'h': case 'H': tag = 60 * 60; break;332 default: return;333 }334 [timeIntervalUnits selectItemAtIndex:335 [timeIntervalUnits indexOfItemWithTag: tag]];336 480 // NSLog(@"UPDATING FROM validation"); 337 [self update: timeInterval]; // make sure we still examine the field editor, otherwise if the existing numeric string is invalid, it'll be cleared481 if (control == timeInterval) [self update: timeInterval]; // make sure we still examine the field editor, otherwise if the existing numeric string is invalid, it'll be cleared 338 482 } 339 483 … … 347 491 [self silence: nil]; 348 492 [self _stopUpdateTimer]; 493 [self _setAlerts]; 349 494 } 350 495 … … 367 512 - (NSString *)voicePopUpButton:(NJRVoicePopUpButton *)sender previewStringForVoice:(NSString *)voice; 368 513 { 369 return [messageField stringValue]; 514 NSString *message = [messageField stringValue]; 515 if (message == nil || [message length] == 0) 516 message = [alarm message]; 517 return message; 370 518 } 371 519 -
trunk/Cocoa/Pester/Source/PSAlarms.h
r51 r53 8 8 9 9 #import <Cocoa/Cocoa.h> 10 #import "PSPropertyListSerialization.h" 10 11 11 12 extern NSString * const PSAlarmsDidChangeNotification; … … 14 15 @class PSAlarm; 15 16 16 @interface PSAlarms : NSObject {17 @interface PSAlarms : NSObject <PSPropertyListSerialization> { 17 18 NSMutableArray *alarms; 19 NSMutableSet *expiredAlarms; 18 20 PSAlarm *nextAlarm; 19 21 } … … 22 24 + (PSAlarms *)allAlarms; 23 25 26 - (unsigned)countOfVersion1Alarms; 27 - (void)importVersion1Alarms; 28 - (void)discardVersion1Alarms; 29 24 30 - (NSArray *)alarms; 31 25 32 - (PSAlarm *)nextAlarm; 26 33 - (int)alarmCount; -
trunk/Cocoa/Pester/Source/PSAlarms.m
r51 r53 9 9 #import "PSAlarms.h" 10 10 #import "PSAlarm.h" 11 #import "NSDictionary-NJRExtensions.h" 12 13 NSString * const PSAlarmImportException = @"PSAlarmImportException"; 11 14 12 15 NSString * const PSAlarmsDidChangeNotification = @"PSAlarmsDidChangeNotification"; 13 16 NSString * const PSAlarmsNextAlarmDidChangeNotification = @"PSAlarmsNextAlarmDidChangeNotification"; 14 17 15 static NSString * const PSPendingAlarms = @"Pester pending alarms"; // NSUserDefaults key 18 // NSUserDefaults key 19 static NSString * const PSPendingAlarms = @"Pester pending alarms"; // 1.0 Ð 1.1a3 20 static NSString * const PSAllAlarms = @"Pester alarms"; // 1.1a4 Ð 21 22 // property list keys 23 static NSString * const PLAlarmsPending = @"pending"; 24 static NSString * const PLAlarmsExpired = @"expired"; 16 25 17 26 static PSAlarms *PSAlarmsAllAlarms = nil; … … 28 37 { 29 38 if (PSAlarmsAllAlarms == nil) { 30 PSAlarmsAllAlarms = [[self alloc] init]; 39 NSDictionary *plAlarms = [[NSUserDefaults standardUserDefaults] objectForKey: PSAllAlarms]; 40 if (plAlarms == nil) { 41 PSAlarmsAllAlarms = [[self alloc] init]; 42 } else { 43 PSAlarmsAllAlarms = [[self alloc] initWithPropertyList: plAlarms]; 44 } 31 45 [PSAlarmsAllAlarms _updateNextAlarm]; // only generate notifications after singleton established 32 46 } … … 37 51 NSAssert(PSAlarmsAllAlarms != nil, @"Attempt to use +[PSAlarms allAlarms] before setup complete"); 38 52 return PSAlarmsAllAlarms; 53 } 54 55 #pragma mark private 56 57 - (void)_changed; 58 { 59 NSMutableArray *alarmsData = [[NSMutableArray alloc] init]; 60 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 61 [self _updateNextAlarm]; 62 // NSLog(@"PSAlarms _changed:\n%@", alarms); 63 [defaults setObject: [self propertyListRepresentation] forKey: PSAllAlarms]; 64 [defaults synchronize]; 65 [alarmsData release]; 66 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsDidChangeNotification object: self]; 67 } 68 69 - (void)_alarmTimerExpired:(NSNotification *)notification; 70 { 71 PSAlarm *alarm = [notification object]; 72 NSLog(@"timer expired: %@ retainCount %d", alarm, [alarm retainCount]); 73 [expiredAlarms addObject: alarm]; 74 NSLog(@"expired alarms: %@", [expiredAlarms description]); 75 [alarms removeObject: alarm]; 76 [self _changed]; 77 } 78 79 - (void)_alarmTimerSet:(NSNotification *)notification; 80 { 81 PSAlarm *alarm = [notification object]; 82 NSLog(@"timer set: %@ retainCount %d", alarm, [alarm retainCount]); 83 [alarms addObject: alarm]; 84 [expiredAlarms removeObject: alarm]; 85 [self _changed]; 86 } 87 88 - (void)_alarmDied:(NSNotification *)notification; 89 { 90 PSAlarm *alarm = [notification object]; 91 NSLog(@"alarm died: %@ retainCount %d", alarm, [alarm retainCount]); 92 [alarms removeObject: alarm]; 93 [expiredAlarms removeObject: alarm]; 94 [self _changed]; 39 95 } 40 96 … … 59 115 } 60 116 117 - (void)_setUpNotifications; 118 { 119 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerSet:) name: PSAlarmTimerSetNotification object: nil]; 120 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerExpired:) name: PSAlarmTimerExpiredNotification object: nil]; 121 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmDied:) name: PSAlarmDiedNotification object: nil]; 122 } 123 124 #pragma mark initialize-release 125 61 126 - (id)init; 62 127 { 63 128 if ( (self = [super init]) != nil) { 64 129 alarms = [[NSMutableArray alloc] init]; 65 NS_DURING 66 NSArray *alarmsData = [[NSUserDefaults standardUserDefaults] arrayForKey: PSPendingAlarms]; 67 NSEnumerator *e = [alarmsData objectEnumerator]; 68 NSData *alarmData; 69 PSAlarm *alarm; 70 while ( (alarmData = [e nextObject]) != nil) { 71 alarm = [NSUnarchiver unarchiveObjectWithData: alarmData]; 72 if (alarm != nil) 73 [alarms addObject: alarm]; 74 } 75 NS_HANDLER 76 // XXX need better error handling here, don't stomp on data 77 NSLog(@"An error occurred while attempting to restore the alarm list: %@", localException); 78 NS_ENDHANDLER 79 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerSet:) name: PSAlarmTimerSetNotification object: nil]; 80 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerExpired:) name: PSAlarmTimerExpiredNotification object: nil]; 130 expiredAlarms = [[NSMutableSet alloc] init]; 131 [self _setUpNotifications]; 81 132 } 82 133 return self; … … 86 137 { 87 138 [alarms release]; 139 [expiredAlarms release]; 88 140 [[NSNotificationCenter defaultCenter] removeObserver: self]; 89 141 [super dealloc]; 90 142 } 91 143 92 - (void)_changed; 93 { 94 NSMutableArray *alarmsData = [[NSMutableArray alloc] init]; 95 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 96 NSEnumerator *e; 97 PSAlarm *alarm; 98 [self _updateNextAlarm]; 99 // NSLog(@"PSAlarms _changed:\n%@", alarms); 100 // archive 101 e = [alarms objectEnumerator]; 102 while ( (alarm = [e nextObject]) != nil) { 103 [alarmsData addObject: [NSArchiver archivedDataWithRootObject: alarm]]; 104 } 105 [defaults setObject: alarmsData forKey: PSPendingAlarms]; 106 [defaults synchronize]; 107 [alarmsData release]; 108 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsDidChangeNotification object: self]; 109 } 110 111 - (void)_alarmTimerExpired:(NSNotification *)notification; 112 { 113 [alarms removeObject: [notification object]]; 114 [self _changed]; 115 } 116 117 - (void)_alarmTimerSet:(NSNotification *)notification; 118 { 119 [alarms addObject: [notification object]]; 120 [self _changed]; 144 #pragma mark accessing 145 146 - (NSArray *)alarms; 147 { 148 return alarms; 121 149 } 122 150 … … 124 152 { 125 153 return nextAlarm; 126 }127 128 - (NSArray *)alarms;129 {130 return alarms;131 154 } 132 155 … … 185 208 } 186 209 210 #pragma mark property list serialization (Pester 1.1) 211 212 - (NSDictionary *)propertyListRepresentation; 213 { 214 NSMutableArray *plPendingAlarms = [[NSMutableArray alloc] initWithCapacity: [alarms count]]; 215 NSMutableArray *plExpiredAlarms = [[NSMutableArray alloc] initWithCapacity: [expiredAlarms count]]; 216 NSDictionary *plAllAlarms, *plAlarm; 217 NSEnumerator *e; 218 PSAlarm *alarm; 219 220 e = [alarms objectEnumerator]; 221 while ( (alarm = [e nextObject]) != nil) { 222 plAlarm = [alarm propertyListRepresentation]; 223 if (plAlarm != nil) 224 [plPendingAlarms addObject: plAlarm]; 225 } 226 227 e = [expiredAlarms objectEnumerator]; 228 while ( (alarm = [e nextObject]) != nil) { 229 plAlarm = [alarm propertyListRepresentation]; 230 if (plAlarm != nil) 231 [plExpiredAlarms addObject: plAlarm]; 232 } 233 234 plAllAlarms = [NSDictionary dictionaryWithObjectsAndKeys: 235 plPendingAlarms, PLAlarmsPending, plExpiredAlarms, PLAlarmsExpired, nil]; 236 [plPendingAlarms release]; 237 [plExpiredAlarms release]; 238 239 return plAllAlarms; 240 } 241 242 - (id)initWithPropertyList:(NSDictionary *)dict; 243 { 244 if ( (self = [super init]) != nil) { 245 NSArray *plPendingAlarms = [dict objectForRequiredKey: PLAlarmsPending]; 246 NSArray *plExpiredAlarms = [dict objectForRequiredKey: PLAlarmsExpired]; 247 NSEnumerator *e; 248 NSDictionary *plAlarm; 249 PSAlarm *alarm; 250 251 alarms = [[NSMutableArray alloc] initWithCapacity: [plPendingAlarms count]]; 252 e = [plPendingAlarms objectEnumerator]; 253 while ( (plAlarm = [e nextObject]) != nil) { 254 [alarms addObject: [[PSAlarm alloc] initWithPropertyList: plAlarm]]; 255 } 256 257 e = [plExpiredAlarms objectEnumerator]; 258 while ( (plAlarm = [e nextObject]) != nil) { 259 // expired alarms may be just that, or they may have outstanding repeats - if the latter, PSAlarm will reschedule the alarm. 260 if ( (alarm = [[PSAlarm alloc] initWithPropertyList: plAlarm]) != nil) 261 [alarms addObject: alarm]; 262 } 263 expiredAlarms = [[NSMutableSet alloc] init]; 264 265 [self _setUpNotifications]; 266 } 267 return self; 268 } 269 270 #pragma mark archiving (Pester 1.0) 271 272 - (unsigned)countOfVersion1Alarms; 273 { 274 return [[[NSUserDefaults standardUserDefaults] objectForKey: PSPendingAlarms] count]; 275 } 276 277 - (void)discardVersion1Alarms; 278 { 279 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 280 [defaults removeObjectForKey: PSPendingAlarms]; 281 [defaults synchronize]; 282 } 283 284 - (void)importVersion1Alarms; 285 { 286 NSArray *alarmsData = [[NSUserDefaults standardUserDefaults] arrayForKey: PSPendingAlarms]; 287 NSEnumerator *e = [alarmsData objectEnumerator]; 288 NSData *alarmData; 289 PSAlarm *alarm; 290 while ( (alarmData = [e nextObject]) != nil) { 291 NS_DURING 292 alarm = [NSUnarchiver unarchiveObjectWithData: alarmData]; 293 NS_HANDLER 294 alarm = nil; 295 // XXX 296 NS_ENDHANDLER 297 if (alarm != nil) 298 [alarms addObject: alarm]; 299 } 300 } 301 187 302 @end -
trunk/Cocoa/Pester/Source/PSAlarmsController.m
r51 r53 9 9 #import "PSAlarmsController.h" 10 10 #import "PSAlarm.h" 11 #import "PSAlerts.h" 11 12 #import "NSTableView-NJRExtensions.h" 12 13 #import "NJRTableView.h" … … 82 83 } 83 84 85 - (NSString *)tableView:(NSTableView *)aTableView toolTipForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; 86 { 87 PSAlarm *alarm = [reorderedAlarms objectAtIndex: rowIndex]; 88 89 return [[alarm prettyDescription] string]; 90 } 91 84 92 @end 85 93 -
trunk/Cocoa/Pester/Source/PSAlert.h
r34 r53 9 9 #import <Foundation/Foundation.h> 10 10 #import "PSAlarm.h" 11 #import "PSPropertyListSerialization.h" 12 #import "NSString-NJRExtensions.h" 11 13 12 @interface PSAlert : NSObject { 14 extern NSString * const PSAlertCreationException; 13 15 16 extern NSString * const PSAlarmAlertCompletedNotification; // userInfo key: "alert" -> PSAlert 17 18 @interface PSAlert : NSObject <PSPropertyListSerialization> { 19 14 20 } 15 16 // XXX need archiving support17 21 18 22 // subclasses should implement these methods 19 23 + (PSAlert *)alert; 20 24 - (void)triggerForAlarm:(PSAlarm *)alarm; 25 - (BOOL)requiresPesterFrontmost; 26 27 - (NSAttributedString *)actionDescription; 28 29 // after alert completes, invoke method of superclass 30 - (void)completedForAlarm:(PSAlarm *)alarm; 21 31 22 32 @end -
trunk/Cocoa/Pester/Source/PSAlert.m
r34 r53 8 8 9 9 #import "PSAlert.h" 10 #import "NSDictionary-NJRExtensions.h" 10 11 12 NSString * const PSAlertCreationException = @"PSAlertCreationException"; 13 14 NSString * const PSAlarmAlertCompletedNotification = @"PSAlarmAlertCompletedNotification"; 15 16 // property list keys 17 static NSString * const PLAlertClass = @"class"; // NSString 11 18 12 19 @implementation PSAlert … … 23 30 } 24 31 32 - (BOOL)requiresPesterFrontmost; 33 { 34 return NO; 35 } 36 37 - (void)completedForAlarm:(PSAlarm *)alarm; 38 { 39 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmAlertCompletedNotification object: alarm userInfo: [NSDictionary dictionaryWithObject: self forKey: @"alert"]]; 40 } 41 42 - (NSAttributedString *)actionDescription; 43 { 44 NSAssert(NO, @"Class is abstract"); 45 return nil; 46 } 47 48 #pragma mark property list serialization (Pester 1.1) 49 50 - (NSDictionary *)propertyListRepresentation; 51 { 52 return [NSDictionary dictionaryWithObject: NSStringFromClass([self class]) forKey: PLAlertClass]; 53 } 54 55 - (id)initWithPropertyList:(NSDictionary *)dict; 56 { 57 if ( (self = [self init]) != nil) { 58 IMP myImp = [self methodForSelector: _cmd]; 59 NSString *clsString = [dict objectForRequiredKey: PLAlertClass]; 60 Class cls = NSClassFromString(clsString); 61 NSAssert1(cls != nil, @"Alert class %@ is not available", clsString); 62 [super release]; 63 self = [cls alloc]; 64 if (self != nil) { 65 IMP subImp = [self methodForSelector: @selector(initWithPropertyList:)]; 66 NSAssert1(subImp != myImp, @"No implementation of initWithPropertyList: for alert class %@", clsString); 67 self = [self initWithPropertyList: dict]; 68 } 69 } 70 return self; 71 } 72 25 73 @end -
trunk/Cocoa/Pester/Source/PSApplication.m
r34 r53 21 21 [[NSNotificationCenter defaultCenter] addObserver: [PSAlarmAlertController class] selector: @selector(controllerWithTimerExpiredNotification:) name: PSAlarmTimerExpiredNotification object: nil]; 22 22 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(nextAlarmDidChange:) name: PSAlarmsNextAlarmDidChangeNotification object: nil]; 23 // XXX exception handling 23 24 [PSAlarms setUp]; 24 25 [self setDelegate: self]; … … 71 72 { 72 73 PSAlarm *alarm = [timer userInfo]; 73 NSTimeInterval alarmInterval;74 NSTimeInterval timeRemaining; 74 75 NSString *tileString; 75 76 if (timer == nil) alarm = [[PSAlarms allAlarms] nextAlarm]; 76 77 if (alarm == nil) return; 77 78 tileString = [alarm timeRemainingString]; 79 timeRemaining = [alarm timeRemaining]; // want to err on the side of timeRemaining being smaller, otherwise ÇexpiredÈ can appear 78 80 { 79 81 NSMutableDictionary *atts = [NSMutableDictionary dictionary]; … … 117 119 [tile release]; 118 120 } 119 alarmInterval = [alarm interval]; 120 // NSLog(@"_updateDockTile > time remaining %@ (%.0lf), last time interval %.0lf", tileString, alarmInterval, dockUpdateInterval); 121 if (alarmInterval > 61) { 122 NSTimeInterval nextUpdate = ((unsigned long long)alarmInterval) % 60; 121 // NSLog(@"_updateDockTile > time remaining %@ (%.6lf), last time interval %.6lf", tileString, timeRemaining, dockUpdateInterval); 122 if (timeRemaining > 61) { 123 NSTimeInterval nextUpdate = ((unsigned long long)timeRemaining) % 60; 123 124 if (nextUpdate <= 1) nextUpdate = 60; 124 125 [self _resetUpdateTimer]; … … 126 127 // NSLog(@"_updateDockTile > set timer for %.0lf seconds", nextUpdate); 127 128 } else if (timer == nil || dockUpdateInterval > 1) { 128 [self _resetUpdateTimer]; 129 [self _resetUpdateTimer]; 129 130 [self _setUpdateTimerForInterval: 1 alarm: alarm repeats: YES]; 130 131 // NSLog(@"_updateDockTile > set timer for 1 second"); 131 } else if ( alarmInterval < 2) {132 } else if (timeRemaining <= 1) { 132 133 [self _resetUpdateTimer]; 133 134 } … … 182 183 @implementation PSApplication (NSApplicationNotifications) 183 184 185 - (void)applicationDidFinishLaunching:(NSNotification *)notification; 186 { 187 // XXX import panel will not be frontmost window if you switch to another app while Pester is launching; Mac OS X bug? 188 PSAlarms *allAlarms = [PSAlarms allAlarms]; 189 unsigned version1AlarmCount = [allAlarms countOfVersion1Alarms]; 190 if (version1AlarmCount > 0) { 191 int answer = NSRunAlertPanel(@"Import alarms from older Pester version?", @"Pester found %u alarm%@ created with an older version. These alarms must be converted for use with this version of Pester, and will be unavailable in previous versions after conversion. New alarms created with this version of Pester will not appear in Pester version 1.1a3 or earlier.", 192 @"Import", @"Discard", @"DonÕt Import", 193 version1AlarmCount, version1AlarmCount == 1 ? @"" : @"s"); 194 switch (answer) { 195 case NSAlertDefaultReturn: 196 NS_DURING 197 [allAlarms importVersion1Alarms]; 198 NS_HANDLER 199 NSRunAlertPanel(@"Error occurred importing alarms", @"Pester was unable to convert some alarms created with an older version. Those alarms which could be read have been converted. The previous-format alarms have been retained; try using an older version of Pester to read them.\n\n%@", nil, nil, nil, [localException reason]); 200 NS_VOIDRETURN; 201 NS_ENDHANDLER 202 case NSAlertAlternateReturn: 203 NSLog(@"discard"); 204 // [allAlarms discardVersion1Alarms]; 205 break; 206 case NSAlertOtherReturn: 207 NSLog(@"donÕt import"); 208 break; 209 } 210 } 211 } 212 184 213 - (void)applicationWillTerminate:(NSNotification *)notification; 185 214 { -
trunk/Cocoa/Pester/Source/PSBeepAlert.h
r34 r53 9 9 #import "PSAlert.h" 10 10 11 12 11 @interface PSBeepAlert : PSAlert { 12 PSAlarm *alarm; 13 13 unsigned short repetitions; 14 unsigned short repetitionsRemaining; 14 unsigned short repetitionsRemaining; 15 15 } 16 16 … … 18 18 - (id)initWithRepetitions:(unsigned short)numReps; 19 19 20 - (unsigned short)repetitions; 21 20 22 @end -
trunk/Cocoa/Pester/Source/PSBeepAlert.m
r34 r53 10 10 #import "PSBeepAlert.h" 11 11 #import "PSAlarmAlertController.h" 12 #import "NSDictionary-NJRExtensions.h" 13 14 // property list keys 15 static NSString * const PLAlertRepetitions = @"times"; // NSNumber 12 16 13 17 @implementation PSBeepAlert … … 32 36 } 33 37 38 - (unsigned short)repetitions; 39 { 40 return repetitions; 41 } 42 34 43 - (void)beep; 35 44 { … … 37 46 repetitionsRemaining--; 38 47 if (repetitionsRemaining == 0) { 48 [self completedForAlarm: alarm]; 39 49 [self release]; 40 50 return; … … 48 58 } 49 59 50 - (void)triggerForAlarm:(PSAlarm *)a larm;60 - (void)triggerForAlarm:(PSAlarm *)anAlarm; 51 61 { 62 alarm = anAlarm; 52 63 repetitionsRemaining = repetitions; 53 64 [self retain]; … … 56 67 } 57 68 69 - (NSAttributedString *)actionDescription; 70 { 71 return [[@"Play the system alert sound" stringByAppendingString: 72 repetitions == 1 ? @"" : [NSString stringWithFormat: @" %hu times", repetitions]] small]; 73 } 74 75 #pragma mark property list serialization (Pester 1.1) 76 77 - (NSDictionary *)propertyListRepresentation; 78 { 79 NSMutableDictionary *plAlert = [[super propertyListRepresentation] mutableCopy]; 80 [plAlert setObject: [NSNumber numberWithUnsignedShort: repetitions] forKey: PLAlertRepetitions]; 81 return [plAlert autorelease]; 82 } 83 84 - (id)initWithPropertyList:(NSDictionary *)dict; 85 { 86 return [self initWithRepetitions: [[dict objectForRequiredKey: PLAlertRepetitions] unsignedShortValue]]; 87 } 88 58 89 @end -
trunk/Cocoa/Pester/Source/PSDockBounceAlert.m
r40 r53 30 30 [NSApp requestUserAttention: NSInformationalRequest]; 31 31 [[self class] performSelector: @selector(stopBouncing) withObject: nil afterDelay: 1 inModes: [NSArray arrayWithObject: NSDefaultRunLoopMode]]; 32 [self completedForAlarm: alarm]; 32 33 } 33 34 35 - (NSAttributedString *)actionDescription; 36 { 37 return [@"Bounce dock icon" small]; 38 } 39 40 #pragma mark property list serialization (Pester 1.1) 41 42 - (id)initWithPropertyList:(NSDictionary *)dict; 43 { 44 [self release]; 45 return [[PSDockBounceAlert alert] retain]; 46 } 47 34 48 @end -
trunk/Cocoa/Pester/Source/PSMovieAlert.h
r34 r53 9 9 #import <AppKit/AppKit.h> 10 10 #import "PSAlert.h" 11 #import "BDAlias.h"12 11 12 @class BDAlias; 13 13 14 14 @interface PSMovieAlert : PSAlert { … … 22 22 + (PSMovieAlert *)alertWithMovieFileAlias:(BDAlias *)anAlias repetitions:(unsigned short)numReps; 23 23 24 - (id)initWith Alias:(BDAlias *)anAlias repetitions:(unsigned int) numReps;24 - (id)initWithMovieFileAlias:(BDAlias *)anAlias repetitions:(unsigned int) numReps; 25 25 26 26 - (BOOL)hasVideo; 27 27 - (NSMovie *)movie; 28 - (BDAlias *)movieFileAlias; 28 29 - (unsigned short)repetitions; 29 30 -
trunk/Cocoa/Pester/Source/PSMovieAlert.m
r45 r53 10 10 #import "PSMovieAlert.h" 11 11 #import "PSMovieAlertController.h" 12 #import "NSDictionary-NJRExtensions.h" 12 13 #import "NSMovie-NJRExtensions.h" 14 #import "BDAlias.h" 15 16 // property list keys 17 static NSString * const PLAlertRepetitions = @"times"; // NSString 18 static NSString * const PLAlertAlias = @"alias"; // NSData 13 19 14 20 @implementation PSMovieAlert … … 16 22 + (PSMovieAlert *)alertWithMovieFileAlias:(BDAlias *)anAlias repetitions:(unsigned short)numReps; 17 23 { 18 return [[[self alloc] initWith Alias: anAlias repetitions: numReps] autorelease];24 return [[[self alloc] initWithMovieFileAlias: anAlias repetitions: numReps] autorelease]; 19 25 } 20 26 21 - (id)initWith Alias:(BDAlias *)anAlias repetitions:(unsigned int) numReps;27 - (id)initWithMovieFileAlias:(BDAlias *)anAlias repetitions:(unsigned int) numReps; 22 28 { 23 29 if ( (self = [super init]) != nil) { 30 NSString *path = [anAlias fullPath]; 31 if (path == nil) { 32 [self release]; 33 [NSException raise: PSAlertCreationException format: @"CanÕt locate media to play as alert."]; 34 } 24 35 alias = [anAlias retain]; 25 36 repetitions = numReps; 26 movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: [anAlias fullPath]] byReference: YES];37 movie = [[NSMovie alloc] initWithURL: [NSURL fileURLWithPath: path] byReference: YES]; 27 38 if (movie == nil) { 28 39 [self release]; … … 46 57 } 47 58 59 - (BOOL)requiresPesterFrontmost; 60 { 61 return hasVideo; 62 } 63 48 64 - (NSMovie *)movie; 49 65 { 50 66 return movie; 67 } 68 69 - (BDAlias *)movieFileAlias; 70 { 71 return alias; 51 72 } 52 73 … … 73 94 } 74 95 96 - (NSAttributedString *)actionDescription; 97 { 98 BOOL isStatic = [movie isStatic]; 99 NSMutableAttributedString *string = [[(isStatic ? @"Show " : @"Play ") small] mutableCopy]; 100 NSString *kindString = nil, *name = [alias displayNameWithKindString: &kindString]; 101 if (name == nil) name = @"ÇcanÕt locate media fileÈ"; 102 else [string appendAttributedString: [[NSString stringWithFormat: @"%@ ", kindString] small]]; 103 [string appendAttributedString: [name underlined]]; 104 if (repetitions > 1 && !isStatic) { 105 [string appendAttributedString: [[NSString stringWithFormat: @" %hu times", repetitions] small]]; 106 } 107 return [string autorelease]; 108 } 109 110 #pragma mark property list serialization (Pester 1.1) 111 112 - (NSDictionary *)propertyListRepresentation; 113 { 114 NSMutableDictionary *plAlert = [[super propertyListRepresentation] mutableCopy]; 115 [plAlert setObject: [NSNumber numberWithUnsignedShort: repetitions] forKey: PLAlertRepetitions]; 116 [plAlert setObject: [alias aliasData] forKey: PLAlertAlias]; 117 return [plAlert autorelease]; 118 } 119 120 - (id)initWithPropertyList:(NSDictionary *)dict; 121 { 122 return [self initWithMovieFileAlias: [BDAlias aliasWithData: [dict objectForRequiredKey: PLAlertAlias]] 123 repetitions: [[dict objectForRequiredKey: PLAlertRepetitions] unsignedShortValue]]; 124 } 125 75 126 @end -
trunk/Cocoa/Pester/Source/PSMovieAlertController.h
r34 r53 13 13 14 14 @interface PSMovieAlertController : NSWindowController { 15 PSAlarm *alarm; 16 PSMovieAlert *alert; 15 17 IBOutlet NSMovieView *movieView; 16 18 void *theMovie; /* Movie */ … … 19 21 } 20 22 21 + (PSMovieAlertController *)controllerWithAlarm:(PSAlarm *)a larm movieAlert:(PSMovieAlert *)alert;23 + (PSMovieAlertController *)controllerWithAlarm:(PSAlarm *)anAlarm movieAlert:(PSMovieAlert *)anAlert; 22 24 23 - (id)initWithAlarm:(PSAlarm *)a larm movieAlert:(PSMovieAlert *)alert;25 - (id)initWithAlarm:(PSAlarm *)anAlarm movieAlert:(PSMovieAlert *)anAlert; 24 26 25 27 @end -
trunk/Cocoa/Pester/Source/PSMovieAlertController.m
r45 r53 17 17 @implementation PSMovieAlertController 18 18 19 + (PSMovieAlertController *)controllerWithAlarm:(PSAlarm *)a larm movieAlert:(PSMovieAlert *)alert;19 + (PSMovieAlertController *)controllerWithAlarm:(PSAlarm *)anAlarm movieAlert:(PSMovieAlert *)anAlert; 20 20 { 21 return [[self alloc] initWithAlarm: a larm movieAlert: alert];21 return [[self alloc] initWithAlarm: anAlarm movieAlert: anAlert]; 22 22 } 23 23 … … 39 39 } 40 40 41 - (id)initWithAlarm:(PSAlarm *)a larm movieAlert:(PSMovieAlert *)alert;41 - (id)initWithAlarm:(PSAlarm *)anAlarm movieAlert:(PSMovieAlert *)anAlert; 42 42 { 43 43 if ([self initWithWindowNibName: @"Movie alert"]) { 44 NSMovie *movie = [a lert movie];44 NSMovie *movie = [anAlert movie]; 45 45 NSWindow *window = [self window]; // connect outlets 46 alarm = anAlarm; 47 alert = anAlert; 46 48 [movieView setMovie: movie]; 47 49 theMovie = [movie QTMovie]; … … 67 69 [window setFrame: frame display: NO]; 68 70 [window setTitle: [alarm message]]; 71 { // XXX workaround for (IMO) ugly appearance of Cocoa utility windows 72 NSView *miniButton = [window standardWindowButton: NSWindowMiniaturizeButton], 73 *zoomButton = [window standardWindowButton: NSWindowZoomButton]; 74 // NOTE: this will not work if the window is resizable: when the frame is reset, the standard buttons reappear 75 [miniButton setFrameOrigin: NSMakePoint(-100, -100)]; 76 [zoomButton setFrameOrigin: NSMakePoint(-100, -100)]; 77 [[miniButton superview] setNeedsDisplay: YES]; 78 [[zoomButton superview] setNeedsDisplay: YES]; 79 } 69 80 [[self window] orderFrontRegardless]; 70 81 } … … 91 102 repetitions = 0; 92 103 [movieView stop: self]; 93 [self release]; 104 [alert completedForAlarm: alarm]; 105 [self autorelease]; 94 106 // note: there may still be a retained copy of this object until the runloop timer has let go of us at the end of the current movie playback cycle; donÕt worry about it. 95 107 } -
trunk/Cocoa/Pester/Source/PSNotifierAlert.m
r34 r53 26 26 } 27 27 28 - (BOOL)requiresPesterFrontmost; 29 { 30 return YES; 31 } 32 33 - (NSAttributedString *)actionDescription; 34 { 35 return [@"Display message and time" small]; 36 } 37 38 #pragma mark property list serialization (Pester 1.1) 39 40 - (id)initWithPropertyList:(NSDictionary *)dict; 41 { 42 [self release]; 43 return [[PSNotifierAlert alert] retain]; 44 } 45 28 46 @end -
trunk/Cocoa/Pester/Source/PSScriptAlert.h
r34 r53 18 18 - (id)initWithScriptFileAlias:(BDAlias *)anAlias; 19 19 20 - (BDAlias *)scriptFileAlias; 21 20 22 @end -
trunk/Cocoa/Pester/Source/PSScriptAlert.m
r34 r53 9 9 #import "PSScriptAlert.h" 10 10 #import "BDAlias.h" 11 #import "NDAppleScriptObject.h" 11 // XXX remove #import "NDAppleScriptObject.h" 12 #import "NSDictionary-NJRExtensions.h" 13 14 // property list keys 15 static NSString * const PLAlertAlias = @"alias"; // NSData 12 16 13 17 @implementation PSScriptAlert … … 26 30 } 27 31 32 - (BDAlias *)scriptFileAlias; 33 { 34 return alias; 35 } 36 28 37 - (void)triggerForAlarm:(PSAlarm *)alarm; 29 38 { 30 N DAppleScriptObject *as = [NDAppleScriptObject appleScriptObjectWithContentsOfFile: [alias fullPath]];39 NSString *scriptPath = [alias fullPath]; 31 40 32 if (as != nil) { 33 [as execute]; 41 if (scriptPath == nil) { 42 NSRunAlertPanel(@"CanÕt find script", @"Pester couldnÕt find the script for the alarm Ò%@Ó.", 43 nil, nil, nil, [alarm message]); 44 } else { 45 NSDictionary *errorInfo; 46 NSAppleScript *script = [[NSAppleScript alloc] initWithContentsOfURL: [NSURL fileURLWithPath: scriptPath] error: &errorInfo]; 47 if (script == nil) { 48 NSString *errorMessage = [errorInfo objectForKey: NSAppleScriptErrorMessage]; 49 NSNumber *errorNumber = [errorInfo objectForKey: NSAppleScriptErrorNumber]; 50 NSString *appName = [errorInfo objectForKey: NSAppleScriptErrorAppName]; 51 if (errorMessage == nil) errorMessage = [errorInfo objectForKey: NSAppleScriptErrorBriefMessage]; 52 NSRunAlertPanel(@"Script loading error", 53 @"Pester encountered an error while attempting to load Ò%@Ó%@ %@", 54 nil, nil, nil, 55 [[NSFileManager defaultManager] displayNameAtPath: scriptPath], 56 errorMessage == nil ? @"" : [NSString stringWithFormat: @":\n\n%@%@", appName == nil ? @"" : @"Ò%@Ó reported an error: ", errorMessage], 57 errorNumber == nil ? @"" : [NSString stringWithFormat: @"(%@)", errorNumber]); 58 } else { 59 NSAppleEventDescriptor *scriptResult = [script executeAndReturnError: &errorInfo]; 60 if (scriptResult == nil) { 61 NSString *errorMessage = [errorInfo objectForKey: NSAppleScriptErrorMessage]; 62 NSNumber *errorNumber = [errorInfo objectForKey: NSAppleScriptErrorNumber]; 63 NSString *appName = [errorInfo objectForKey: NSAppleScriptErrorAppName]; 64 if (errorMessage == nil) errorMessage = [errorInfo objectForKey: NSAppleScriptErrorBriefMessage]; 65 NSRunAlertPanel(@"Script execution error", 66 @"Pester encountered an error while attempting to execute the script Ò%@Ó%@ %@", 67 nil, nil, nil, 68 [[NSFileManager defaultManager] displayNameAtPath: scriptPath], 69 errorMessage == nil ? @"" : [NSString stringWithFormat: @":\n\n%@%@", appName == nil ? @"" : @"Ò%@Ó reported an error: ", errorMessage], 70 errorNumber == nil ? @"" : [NSString stringWithFormat: @"(%@)", errorNumber]); 71 } 72 } 34 73 } 74 [self completedForAlarm: alarm]; 35 75 } 76 77 - (NSAttributedString *)actionDescription; 78 { 79 NSMutableAttributedString *string = [[@"Do script " small] mutableCopy]; 80 NSString *scriptName = [alias displayNameWithKindString: NULL]; 81 if (scriptName == nil) scriptName = @"ÇcanÕt locate scriptÈ"; 82 [string appendAttributedString: [scriptName underlined]]; 83 return [string autorelease]; 84 } 85 86 #pragma mark property list serialization (Pester 1.1) 87 88 - (NSDictionary *)propertyListRepresentation; 89 { 90 NSMutableDictionary *plAlert = [[super propertyListRepresentation] mutableCopy]; 91 [plAlert setObject: [alias aliasData] forKey: PLAlertAlias]; 92 return [plAlert autorelease]; 93 } 94 95 - (id)initWithPropertyList:(NSDictionary *)dict; 96 { 97 return [self initWithScriptFileAlias: [BDAlias aliasWithData: [dict objectForRequiredKey: PLAlertAlias]]]; 98 } 99 36 100 @end -
trunk/Cocoa/Pester/Source/PSSpeechAlert.h
r34 r53 8 8 9 9 #import "PSAlert.h" 10 #import "SUSpeaker.h" 10 11 @class SUSpeaker; 11 12 12 13 @interface PSSpeechAlert : PSAlert { 13 14 SUSpeaker *speaker; 14 15 NSString *voice; 16 PSAlarm *alarm; 15 17 } 16 18 … … 19 21 - (id)initWithVoice:(NSString *)aVoice; 20 22 23 - (NSString *)voice; 24 21 25 @end -
trunk/Cocoa/Pester/Source/PSSpeechAlert.m
r34 r53 4 4 // 5 5 // Created by Nicholas Riley on Sat Oct 26 2002. 6 // Copyright (c) 2002 __MyCompanyName__. All rights reserved.6 // Copyright (c) 2002 Nicholas Riley. All rights reserved. 7 7 // 8 8 9 9 #import "PSSpeechAlert.h" 10 10 #import "PSAlarmAlertController.h" 11 #import "NSDictionary-NJRExtensions.h" 12 #import "SUSpeaker.h" 13 14 // property list keys 15 static NSString * const PLAlertVoice = @"voice"; // NSString 11 16 12 17 @implementation PSSpeechAlert … … 20 25 { 21 26 if ( (self = [super init]) != nil) { 22 voice = aVoice;27 voice = [aVoice retain]; 23 28 } 24 29 return self; … … 33 38 } 34 39 40 - (NSString *)voice; 41 { 42 return voice; 43 } 44 35 45 - (void)_stopSpeaking:(NSNotification *)notification; 36 46 { 37 [speaker stopSpeaking]; 38 // don't release here, we'll still get the didFinishSpeaking: message as a delegate 47 [speaker stopSpeaking]; // triggers didFinishSpeaking: 39 48 } 40 49 41 - (void)triggerForAlarm:(PSAlarm *)a larm;50 - (void)triggerForAlarm:(PSAlarm *)anAlarm; 42 51 { 43 52 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_stopSpeaking:) name: PSAlarmAlertStopNotification object: nil]; 44 53 45 54 if ( (speaker = [[SUSpeaker alloc] init]) == nil) return; 55 alarm = anAlarm; 46 56 [speaker setDelegate: self]; 47 57 [speaker setVoice: [[SUSpeaker voiceNames] indexOfObject: voice] + 1]; 48 58 [speaker speakText: [alarm message]]; 49 50 [self retain]; 59 } 60 61 - (NSAttributedString *)actionDescription; 62 { 63 NSMutableAttributedString *string = [[@"Speak message with voice " small] mutableCopy]; 64 [string appendAttributedString: [voice underlined]]; 65 return [string autorelease]; 66 } 67 68 #pragma mark property list serialization (Pester 1.1) 69 70 - (NSDictionary *)propertyListRepresentation; 71 { 72 NSMutableDictionary *plAlert = [[super propertyListRepresentation] mutableCopy]; 73 [plAlert setObject: voice forKey: PLAlertVoice]; 74 return [plAlert autorelease]; 75 } 76 77 - (id)initWithPropertyList:(NSDictionary *)dict; 78 { 79 if ( (self = [self init]) != nil) { 80 voice = [dict objectForRequiredKey: PLAlertVoice]; 81 } 82 return self; 51 83 } 52 84 … … 55 87 @implementation PSSpeechAlert (SUSpeakerDelegate) 56 88 57 - (void)didFinishSpeaking:(SUSpeaker *)speaker;89 - (void)didFinishSpeaking:(SUSpeaker *)aSpeaker; 58 90 { 59 [self release]; 91 [self completedForAlarm: alarm]; 92 [speaker release]; speaker = nil; 60 93 } 61 94 -
trunk/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser
r51 r53 2 2 { 3 3 29B97313FDCFA39411CA2CEA = { 4 activeBuildStyle = 4A9504C DFFE6A4B311CA0CBA;4 activeBuildStyle = 4A9504CCFFE6A4B311CA0CBA; 5 5 activeExecutable = F59B967103538BE201154278; 6 6 activeTarget = 29B97326FDCFA39411CA2CEA; … … 12 12 F500E5370359719B01AEEDB1, 13 13 F5B15F74037E42EB01AEEDB1, 14 E1A9DEE703BF3C110089E8B2, 15 E17AED7003C0F4D600B89ACF, 16 E1156BFA03C148E2006717DC, 17 E1156C2C03C394D6006717DC, 18 E117A4AB03C3E2FD00E10BA2, 14 19 ); 15 20 executables = ( … … 17 22 ); 18 23 perUserDictionary = { 19 PBXPerProjectTemplateStateSaveDate = 59271904;20 "PBXTemplateGeometry-F5 314676015831810DCA290F" = {21 ContentSize = "{6 18, 257}";24 PBXPerProjectTemplateStateSaveDate = 63172038; 25 "PBXTemplateGeometry-F5CA7ECB015C094F0DCA290F" = { 26 ContentSize = "{668, 621}"; 22 27 LeftSlideOut = { 23 28 Collapsed = NO; 24 Frame = "{{0, 23}, {618, 234}}";29 Frame = "{{0, 0}, {668, 621}}"; 25 30 Split0 = { 26 ActiveTab = 2; 27 Collapsed = YES; 28 Frame = "{{0, 0}, {618, 234}}"; 31 Collapsed = NO; 32 Frame = "{{0, 0}, {668, 621}}"; 29 33 Split0 = { 30 Frame = "{{ 1e+06, 1e+06}, {618, 0}}";34 Frame = "{{0, 0}, {668, 621}}"; 31 35 }; 32 36 SplitCount = 1; 33 37 Tab0 = { 38 Frame = "{{0, 0}, {484, 208}}"; 39 }; 40 Tab1 = { 34 41 Debugger = { 35 42 Collapsed = NO; 36 Frame = "{{0, 0}, { 952, 321}}";43 Frame = "{{0, 0}, {664, 208}}"; 37 44 Split0 = { 38 Frame = "{{0, 24}, { 952, 297}}";45 Frame = "{{0, 24}, {664, 184}}"; 39 46 Split0 = { 40 Frame = "{{0, 0}, { 468, 297}}";47 Frame = "{{0, 0}, {325, 184}}"; 41 48 }; 42 49 Split1 = { 43 50 DebugVariablesTableConfiguration = ( 44 51 Name, 45 12 6.803,52 123, 46 53 Value, 47 150.074,54 85, 48 55 Summary, 49 172.123,56 96.123, 50 57 ); 51 Frame = "{{ 477, 0}, {475, 297}}";58 Frame = "{{334, 0}, {330, 184}}"; 52 59 }; 53 60 SplitCount = 2; … … 63 70 TabsVisible = YES; 64 71 }; 65 Frame = "{{0, 0}, { 952, 321}}";72 Frame = "{{0, 0}, {664, 208}}"; 66 73 LauncherConfigVersion = 7; 67 74 }; 68 Tab 1= {69 Frame = "{{0, 0}, { 781, 452}}";75 Tab2 = { 76 Frame = "{{0, 0}, {664, 50}}"; 70 77 LauncherConfigVersion = 3; 71 78 Runner = { 72 Frame = "{{0, 0}, { 781, 452}}";79 Frame = "{{0, 0}, {664, 50}}"; 73 80 }; 74 81 }; 75 Tab2 = {76 BuildMessageFrame = "{{0, 0}, {620, 123}}";77 BuildTranscriptFrame = "{{0, 132}, {620, 98}}";78 Frame = "{{0, 0}, {618, 228}}";79 };80 82 Tab3 = { 83 BuildMessageFrame = "{{0, 0}, {614, 262}}"; 84 BuildTranscriptFrame = "{{0, 271}, {614, 2}}"; 85 BuildTranscriptFrameExpanded = YES; 81 86 Frame = "{{0, 0}, {612, 295}}"; 82 87 }; 83 TabCount = 4; 84 TabsVisible = NO; 85 }; 86 SplitCount = 1; 87 Tab0 = { 88 Frame = "{{0, 0}, {300, 533}}"; 89 GroupTreeTableConfiguration = ( 90 TargetStatusColumn, 91 18, 92 MainColumn, 93 267, 94 ); 95 }; 96 Tab1 = { 97 ClassesFrame = "{{0, 0}, {280, 398}}"; 98 ClassesTreeTableConfiguration = ( 99 PBXBookColumnIdentifier, 100 20, 101 PBXClassColumnIdentifier, 102 237, 103 ); 104 Frame = "{{0, 0}, {278, 659}}"; 105 MembersFrame = "{{0, 407}, {280, 252}}"; 106 MembersTreeTableConfiguration = ( 107 PBXBookColumnIdentifier, 108 20, 109 PBXMethodColumnIdentifier, 110 236, 111 ); 112 }; 113 Tab2 = { 114 Frame = "{{0, 0}, {200, 100}}"; 115 }; 116 Tab3 = { 117 Frame = "{{0, 0}, {200, 100}}"; 118 Split0 = { 119 Frame = "{{0, 0}, {200, 45}}"; 120 TargetTreeTableConfiguration = ( 121 ActiveTarget, 122 16, 123 TargetName, 124 168, 125 ); 88 Tab4 = { 89 Frame = "{{0, 0}, {612, 295}}"; 126 90 }; 127 Split1 = { 128 BuildStyleTreeTableConfiguration = ( 129 IsActive, 130 16, 131 Name, 132 169, 133 ); 134 Frame = "{{0, 54}, {200, 46}}"; 135 }; 136 SplitCount = 2; 137 }; 138 Tab4 = { 139 ExecutableTreeTableConfiguration = ( 140 ActiveExecutable, 141 16, 142 ExecutableName, 143 217, 144 ); 145 Frame = "{{0, 0}, {250, 100}}"; 146 }; 147 Tab5 = { 148 BreakpointsTreeTableConfiguration = ( 149 breakpointColumn, 150 197, 151 enabledColumn, 152 31, 153 ); 154 Frame = "{{0, 0}, {250, 100}}"; 155 }; 156 TabCount = 6; 157 TabsVisible = NO; 158 }; 159 StatusViewVisible = YES; 160 Template = F5314676015831810DCA290F; 161 ToolbarVisible = YES; 162 WindowLocation = "{460, 270}"; 163 }; 164 "PBXTemplateGeometry-F5CA7EC9015C08ED0DCA290F" = { 165 ContentSize = "{665, 594}"; 166 LeftSlideOut = { 167 Collapsed = NO; 168 Frame = "{{0, 0}, {665, 594}}"; 169 Split0 = { 170 ActiveTab = 3; 171 Collapsed = NO; 172 Frame = "{{0, 0}, {665, 594}}"; 173 Split0 = { 174 Frame = "{{0, 304}, {665, 290}}"; 175 }; 176 SplitCount = 1; 177 Tab0 = { 178 Debugger = { 179 Collapsed = NO; 180 Frame = "{{0, 0}, {484, 208}}"; 181 Split0 = { 182 Frame = "{{0, 24}, {484, 184}}"; 183 Split0 = { 184 Frame = "{{0, 0}, {236, 184}}"; 185 }; 186 Split1 = { 187 DebugVariablesTableConfiguration = ( 188 Name, 189 48.80299, 190 Value, 191 71.07401, 192 Summary, 193 93.123, 194 ); 195 Frame = "{{245, 0}, {239, 184}}"; 196 }; 197 SplitCount = 2; 198 }; 199 SplitCount = 1; 200 Tab0 = { 201 Frame = "{{0, 0}, {100, 50}}"; 202 }; 203 Tab1 = { 204 Frame = "{{0, 0}, {100, 50}}"; 205 }; 206 TabCount = 2; 207 TabsVisible = YES; 208 }; 209 Frame = "{{0, 0}, {484, 208}}"; 210 LauncherConfigVersion = 7; 211 }; 212 Tab1 = { 213 Frame = "{{0, 0}, {664, 208}}"; 214 LauncherConfigVersion = 3; 215 Runner = { 216 Frame = "{{0, 0}, {664, 208}}"; 217 }; 218 }; 219 Tab2 = { 220 BuildMessageFrame = "{{0, 0}, {666, 43}}"; 221 BuildTranscriptFrame = "{{0, 52}, {666, 0}}"; 222 Frame = "{{0, 0}, {664, 50}}"; 223 }; 224 Tab3 = { 225 Frame = "{{0, 0}, {665, 298}}"; 226 }; 227 TabCount = 4; 91 TabCount = 5; 228 92 TabsVisible = NO; 229 93 }; … … 260 124 Tab3 = { 261 125 Frame = "{{0, 0}, {200, 557}}"; 262 Split0 = { 263 Frame = "{{0, 0}, {200, 270}}"; 264 TargetTreeTableConfiguration = ( 265 ActiveTarget, 266 16, 267 TargetName, 268 168, 269 ); 270 }; 271 Split1 = { 272 BuildStyleTreeTableConfiguration = ( 273 IsActive, 274 16, 275 Name, 276 169, 277 ); 278 Frame = "{{0, 279}, {200, 278}}"; 279 }; 280 SplitCount = 2; 126 TargetTableConfiguration = ( 127 ActiveObject, 128 16, 129 ObjectNames, 130 202.296, 131 ); 281 132 }; 282 133 Tab4 = { 283 ExecutableTreeTableConfiguration = (284 ActiveExecutable,285 16,286 ExecutableName,287 217,288 );289 Frame = "{{0, 0}, {250, 100}}";290 };291 Tab5 = {292 134 BreakpointsTreeTableConfiguration = ( 293 135 breakpointColumn, … … 298 140 Frame = "{{0, 0}, {250, 100}}"; 299 141 }; 300 TabCount = 6;142 TabCount = 5; 301 143 TabsVisible = NO; 302 144 }; 303 StatusViewVisible = NO; 304 Template = F5CA7EC9015C08ED0DCA290F; 305 ToolbarVisible = NO; 306 WindowLocation = "{69, 216}"; 307 }; 308 "PBXTemplateGeometry-F5CA7ECB015C094F0DCA290F" = { 309 ContentSize = "{668, 621}"; 310 LeftSlideOut = { 311 Collapsed = NO; 312 Frame = "{{0, 0}, {668, 621}}"; 313 Split0 = { 314 Collapsed = NO; 315 Frame = "{{0, 0}, {668, 621}}"; 316 Split0 = { 317 Frame = "{{0, 0}, {668, 621}}"; 318 }; 319 SplitCount = 1; 320 Tab0 = { 321 Debugger = { 322 Collapsed = NO; 323 Frame = "{{0, 0}, {484, 208}}"; 324 Split0 = { 325 Frame = "{{0, 24}, {484, 184}}"; 326 Split0 = { 327 Frame = "{{0, 0}, {236, 184}}"; 328 }; 329 Split1 = { 330 DebugVariablesTableConfiguration = ( 331 Name, 332 123, 333 Value, 334 85, 335 Summary, 336 62.123, 337 ); 338 Frame = "{{245, 0}, {239, 184}}"; 339 }; 340 SplitCount = 2; 341 }; 342 SplitCount = 1; 343 Tab0 = { 344 Frame = "{{0, 0}, {100, 50}}"; 345 }; 346 Tab1 = { 347 Frame = "{{0, 0}, {100, 50}}"; 348 }; 349 TabCount = 2; 350 TabsVisible = YES; 351 }; 352 Frame = "{{0, 0}, {484, 208}}"; 353 LauncherConfigVersion = 7; 354 }; 355 Tab1 = { 356 Frame = "{{0, 0}, {664, 208}}"; 357 LauncherConfigVersion = 3; 358 Runner = { 359 Frame = "{{0, 0}, {664, 208}}"; 360 }; 361 }; 362 Tab2 = { 363 BuildMessageFrame = "{{0, 0}, {666, 43}}"; 364 BuildTranscriptFrame = "{{0, 52}, {666, 0}}"; 365 Frame = "{{0, 0}, {664, 50}}"; 366 }; 367 Tab3 = { 368 Frame = "{{0, 0}, {612, 295}}"; 369 }; 370 TabCount = 4; 371 TabsVisible = NO; 372 }; 373 SplitCount = 1; 374 Tab0 = { 375 Frame = "{{0, 0}, {313, 531}}"; 376 GroupTreeTableConfiguration = ( 377 TargetStatusColumn, 378 18, 379 MainColumn, 380 280, 381 ); 382 }; 383 Tab1 = { 384 ClassesFrame = "{{0, 0}, {280, 398}}"; 385 ClassesTreeTableConfiguration = ( 386 PBXBookColumnIdentifier, 387 20, 388 PBXClassColumnIdentifier, 389 237, 390 ); 391 Frame = "{{0, 0}, {278, 659}}"; 392 MembersFrame = "{{0, 407}, {280, 252}}"; 393 MembersTreeTableConfiguration = ( 394 PBXBookColumnIdentifier, 395 20, 396 PBXMethodColumnIdentifier, 397 236, 398 ); 399 }; 400 Tab2 = { 401 Frame = "{{0, 0}, {200, 100}}"; 402 }; 403 Tab3 = { 404 Frame = "{{0, 0}, {200, 557}}"; 405 Split0 = { 406 Frame = "{{0, 0}, {200, 270}}"; 407 TargetTreeTableConfiguration = ( 408 ActiveTarget, 409 16, 410 TargetName, 411 168, 412 ); 413 }; 414 Split1 = { 415 BuildStyleTreeTableConfiguration = ( 416 IsActive, 417 16, 418 Name, 419 169, 420 ); 421 Frame = "{{0, 279}, {200, 278}}"; 422 }; 423 SplitCount = 2; 424 }; 425 Tab4 = { 426 ExecutableTreeTableConfiguration = ( 427 ActiveExecutable, 428 16, 429 ExecutableName, 430 217, 431 ); 432 Frame = "{{0, 0}, {250, 100}}"; 433 }; 434 Tab5 = { 435 BreakpointsTreeTableConfiguration = ( 436 breakpointColumn, 437 197, 438 enabledColumn, 439 31, 440 ); 441 Frame = "{{0, 0}, {250, 100}}"; 442 }; 443 TabCount = 6; 444 TabsVisible = NO; 445 }; 145 NavBarShownByDefault = YES; 446 146 StatusViewVisible = NO; 447 147 Template = F5CA7ECB015C094F0DCA290F; 448 148 ToolbarVisible = NO; 449 WindowLocation = "{361, 189}"; 450 }; 451 "PBXTemplateGeometry-F5CA7ECC015C09990DCA290F" = { 452 ContentSize = "{773, 558}"; 453 LeftSlideOut = { 454 Collapsed = NO; 455 Frame = "{{0, 23}, {773, 535}}"; 456 Split0 = { 457 ActiveTab = 0; 458 Collapsed = NO; 459 Frame = "{{24, 0}, {749, 535}}"; 460 Split0 = { 461 Frame = "{{0, 337}, {749, 198}}"; 462 }; 463 SplitCount = 1; 464 Tab0 = { 465 Debugger = { 466 ActiveTab = 1; 467 Collapsed = NO; 468 Frame = "{{0, 0}, {749, 331}}"; 469 Split0 = { 470 Frame = "{{0, 127}, {749, 204}}"; 471 Split0 = { 472 Frame = "{{0, 0}, {366, 204}}"; 473 }; 474 Split1 = { 475 DebugVariablesTableConfiguration = ( 476 Name, 477 120.803, 478 Value, 479 116.074, 480 Summary, 481 111.123, 482 ); 483 Frame = "{{375, 0}, {374, 204}}"; 484 }; 485 SplitCount = 2; 486 }; 487 SplitCount = 1; 488 Tab0 = { 489 Frame = "{{0, 0}, {100, 50}}"; 490 }; 491 Tab1 = { 492 Frame = "{{0, 0}, {749, 103}}"; 493 }; 494 TabCount = 2; 495 TabsVisible = YES; 496 }; 497 Frame = "{{0, 0}, {749, 331}}"; 498 LauncherConfigVersion = 7; 499 }; 500 Tab1 = { 501 Frame = "{{0, 0}, {664, 208}}"; 502 LauncherConfigVersion = 3; 503 Runner = { 504 Frame = "{{0, 0}, {664, 208}}"; 505 }; 506 }; 507 Tab2 = { 508 BuildMessageFrame = "{{0, 0}, {666, 43}}"; 509 BuildTranscriptFrame = "{{0, 52}, {666, 0}}"; 510 Frame = "{{0, 0}, {664, 50}}"; 511 }; 512 Tab3 = { 513 Frame = "{{0, 0}, {612, 295}}"; 514 }; 515 TabCount = 4; 516 TabsVisible = NO; 517 }; 518 SplitCount = 1; 519 Tab0 = { 520 Frame = "{{0, 0}, {313, 531}}"; 521 GroupTreeTableConfiguration = ( 522 TargetStatusColumn, 523 18, 524 MainColumn, 525 280, 526 ); 527 }; 528 Tab1 = { 529 ClassesFrame = "{{0, 0}, {280, 398}}"; 530 ClassesTreeTableConfiguration = ( 531 PBXBookColumnIdentifier, 532 20, 533 PBXClassColumnIdentifier, 534 237, 535 ); 536 Frame = "{{0, 0}, {278, 659}}"; 537 MembersFrame = "{{0, 407}, {280, 252}}"; 538 MembersTreeTableConfiguration = ( 539 PBXBookColumnIdentifier, 540 20, 541 PBXMethodColumnIdentifier, 542 236, 543 ); 544 }; 545 Tab2 = { 546 Frame = "{{0, 0}, {200, 100}}"; 547 }; 548 Tab3 = { 549 Frame = "{{0, 0}, {200, 557}}"; 550 Split0 = { 551 Frame = "{{0, 0}, {200, 270}}"; 552 TargetTreeTableConfiguration = ( 553 ActiveTarget, 554 16, 555 TargetName, 556 168, 557 ); 558 }; 559 Split1 = { 560 BuildStyleTreeTableConfiguration = ( 561 IsActive, 562 16, 563 Name, 564 169, 565 ); 566 Frame = "{{0, 279}, {200, 278}}"; 567 }; 568 SplitCount = 2; 569 }; 570 Tab4 = { 571 ExecutableTreeTableConfiguration = ( 572 ActiveExecutable, 573 16, 574 ExecutableName, 575 217, 576 ); 577 Frame = "{{0, 0}, {250, 100}}"; 578 }; 579 Tab5 = { 580 BreakpointsTreeTableConfiguration = ( 581 breakpointColumn, 582 197, 583 enabledColumn, 584 31, 585 ); 586 Frame = "{{0, 0}, {250, 100}}"; 587 }; 588 TabCount = 6; 589 TabsVisible = YES; 590 }; 591 StatusViewVisible = YES; 592 Template = F5CA7ECC015C09990DCA290F; 593 ToolbarVisible = YES; 594 WindowLocation = "{13, 212}"; 595 }; 596 "PBXTemplateGeometry-F5E465990156DFB90DCA290F" = { 597 ContentSize = "{352, 553}"; 598 LeftSlideOut = { 599 ActiveTab = 0; 600 Collapsed = YES; 601 Frame = "{{0, 23}, {352, 530}}"; 602 Split0 = { 603 Collapsed = NO; 604 Frame = "{{1e+06, 1e+06}, {0, 530}}"; 605 Split0 = { 606 Frame = "{{0, 0}, {0, 530}}"; 607 }; 608 SplitCount = 1; 609 Tab0 = { 610 Debugger = { 611 Collapsed = NO; 612 Frame = "{{0, 0}, {484, 208}}"; 613 Split0 = { 614 Frame = "{{0, 24}, {484, 184}}"; 615 Split0 = { 616 Frame = "{{0, 0}, {236, 184}}"; 617 }; 618 Split1 = { 619 DebugVariablesTableConfiguration = ( 620 Name, 621 123, 622 Value, 623 85, 624 Summary, 625 62.123, 626 ); 627 Frame = "{{245, 0}, {239, 184}}"; 628 }; 629 SplitCount = 2; 630 }; 631 SplitCount = 1; 632 Tab0 = { 633 Frame = "{{0, 0}, {100, 50}}"; 634 }; 635 Tab1 = { 636 Frame = "{{0, 0}, {100, 50}}"; 637 }; 638 TabCount = 2; 639 TabsVisible = YES; 640 }; 641 Frame = "{{0, 0}, {484, 208}}"; 642 LauncherConfigVersion = 7; 643 }; 644 Tab1 = { 645 Frame = "{{0, 0}, {664, 208}}"; 646 LauncherConfigVersion = 3; 647 Runner = { 648 Frame = "{{0, 0}, {664, 208}}"; 649 }; 650 }; 651 Tab2 = { 652 BuildMessageFrame = "{{0, 0}, {666, 43}}"; 653 BuildTranscriptFrame = "{{0, 52}, {666, 0}}"; 654 Frame = "{{0, 0}, {664, 50}}"; 655 }; 656 Tab3 = { 657 Frame = "{{0, 0}, {612, 295}}"; 658 }; 659 TabCount = 4; 660 TabsVisible = NO; 661 }; 662 SplitCount = 1; 663 Tab0 = { 664 Frame = "{{0, 0}, {328, 530}}"; 665 GroupTreeTableConfiguration = ( 666 TargetStatusColumn, 667 18, 668 MainColumn, 669 295, 670 ); 671 }; 672 Tab1 = { 673 ClassesFrame = "{{0, 0}, {343, 348}}"; 674 ClassesTreeTableConfiguration = ( 675 PBXBookColumnIdentifier, 676 20, 677 PBXClassColumnIdentifier, 678 300, 679 ); 680 Frame = "{{0, 0}, {341, 578}}"; 681 MembersFrame = "{{0, 357}, {343, 221}}"; 682 MembersTreeTableConfiguration = ( 683 PBXBookColumnIdentifier, 684 20, 685 PBXMethodColumnIdentifier, 686 299, 687 ); 688 }; 689 Tab2 = { 690 Frame = "{{0, 0}, {319, 576}}"; 691 }; 692 Tab3 = { 693 Frame = "{{0, 0}, {341, 578}}"; 694 Split0 = { 695 Frame = "{{0, 0}, {341, 281}}"; 696 TargetTreeTableConfiguration = ( 697 ActiveTarget, 698 16, 699 TargetName, 700 309, 701 ); 702 }; 703 Split1 = { 704 BuildStyleTreeTableConfiguration = ( 705 IsActive, 706 16, 707 Name, 708 310, 709 ); 710 Frame = "{{0, 290}, {341, 288}}"; 711 }; 712 SplitCount = 2; 713 }; 714 Tab4 = { 715 ExecutableTreeTableConfiguration = ( 716 ActiveExecutable, 717 16, 718 ExecutableName, 719 286, 720 ); 721 Frame = "{{0, 0}, {319, 576}}"; 722 }; 723 Tab5 = { 724 BreakpointsTreeTableConfiguration = ( 725 breakpointColumn, 726 197, 727 enabledColumn, 728 31, 729 ); 730 Frame = "{{0, 0}, {250, 100}}"; 731 }; 732 TabCount = 6; 733 TabsVisible = YES; 734 }; 735 StatusViewVisible = YES; 736 Template = F5E465990156DFB90DCA290F; 737 ToolbarVisible = YES; 738 WindowLocation = "{2, 217}"; 149 WindowLocation = "{420, 75}"; 739 150 }; 740 151 PBXWorkspaceContents = ( … … 743 154 Split0 = { 744 155 Split0 = { 156 NavContent0 = { 157 bookmark = E1096EC203C3F504009B92C1; 158 history = ( 159 E1D2937503BD418200F9204E, 160 E1D2937B03BD418200F9204E, 161 E1D2937C03BD418200F9204E, 162 E1D2937E03BD418200F9204E, 163 E1D2938303BD418200F9204E, 164 E1D2938403BD418200F9204E, 165 E1D2938503BD418200F9204E, 166 E1D2938603BD418200F9204E, 167 E1D2938903BD418200F9204E, 168 E195A26303BE251F00186F9B, 169 E195A26403BE251F00186F9B, 170 E195A26503BE251F00186F9B, 171 E195A26603BE251F00186F9B, 172 E195A26703BE251F00186F9B, 173 E195A26803BE251F00186F9B, 174 E195A26C03BE251F00186F9B, 175 E195A26D03BE251F00186F9B, 176 E195A26E03BE251F00186F9B, 177 E195A26F03BE251F00186F9B, 178 E195A27603BE251F00186F9B, 179 E195A27A03BE251F00186F9B, 180 E195A27B03BE251F00186F9B, 181 E195A27D03BE251F00186F9B, 182 E195A27E03BE251F00186F9B, 183 E195A28003BE251F00186F9B, 184 E195A28F03BE251F00186F9B, 185 E19DCB6C03BE4A0A00B934BF, 186 E19DCB7803BE4A0A00B934BF, 187 E19DCB8203BE4A0A00B934BF, 188 E19DCB8303BE4A0A00B934BF, 189 E19DCC8703BE900300B934BF, 190 E19DCC8803BE900300B934BF, 191 E19DCC8903BE900300B934BF, 192 E19DCC8A03BE900300B934BF, 193 E19DCC8B03BE900300B934BF, 194 E19DCC8C03BE900300B934BF, 195 E19DCC8E03BE900300B934BF, 196 E19DCC8F03BE900300B934BF, 197 E19DCC9203BE900300B934BF, 198 E19DCC9603BE900300B934BF, 199 E19DCC9703BE900300B934BF, 200 E19DCC9C03BE900300B934BF, 201 E19DCC9E03BE900300B934BF, 202 E1A9DEEB03BF480F0089E8B2, 203 E1A9DEEE03BF480F0089E8B2, 204 E1A9DEF003BF480F0089E8B2, 205 E1A9DEF103BF480F0089E8B2, 206 E1A9DEF203BF480F0089E8B2, 207 E11CD2CA03BF9B3300C49BEF, 208 E11CD2D003BF9B3300C49BEF, 209 E11CD2D103BF9B3300C49BEF, 210 E11CD2D203BF9B3300C49BEF, 211 E11CD2D303BF9B3300C49BEF, 212 E11CD2D403BF9B3300C49BEF, 213 E11CD2D503BF9B3300C49BEF, 214 E11CD2D603BF9B3300C49BEF, 215 E11CD2D703BF9B3300C49BEF, 216 E11CD2D803BF9B3300C49BEF, 217 E11CD2E003BF9B3300C49BEF, 218 E17AED7203C0F5D300B89ACF, 219 E17AED7303C0F5D300B89ACF, 220 E17AED7403C0F5D300B89ACF, 221 E17AED7503C0F5D300B89ACF, 222 E17AED7603C0F5D300B89ACF, 223 E17AED7703C0F5D300B89ACF, 224 E17AED7803C0F5D300B89ACF, 225 E17AED7903C0F5D300B89ACF, 226 E17AED7A03C0F5D300B89ACF, 227 E17AED7B03C0F5D300B89ACF, 228 E17AED7C03C0F5D300B89ACF, 229 E17AED7D03C0F5D300B89ACF, 230 E17AED7E03C0F5D300B89ACF, 231 E17AED7F03C0F5D300B89ACF, 232 E17AED8003C0F5D300B89ACF, 233 E17AED8103C0F5D300B89ACF, 234 E17AED8203C0F5D300B89ACF, 235 E17AED8303C0F5D300B89ACF, 236 E17AED8403C0F5D300B89ACF, 237 E17AED8503C0F5D300B89ACF, 238 E17AED8603C0F5D300B89ACF, 239 E17AED8703C0F5D300B89ACF, 240 E17AED8803C0F5D300B89ACF, 241 E17AED8903C0F5D300B89ACF, 242 E117A4AC03C3E9C600E10BA2, 243 E117A4AD03C3E9C600E10BA2, 244 E117A4AE03C3E9C600E10BA2, 245 E117A4AF03C3E9C600E10BA2, 246 E117A4B003C3E9C600E10BA2, 247 E1096EB603C3EDB0009B92C1, 248 E1096EB903C3EDB0009B92C1, 249 ); 250 prevStack = ( 251 E1D2939103BD418200F9204E, 252 E1D2939203BD418200F9204E, 253 E1D2939303BD418200F9204E, 254 E1D2939403BD418200F9204E, 255 E1D2939503BD418200F9204E, 256 E1D2939603BD418200F9204E, 257 E1D2939703BD418200F9204E, 258 E1D2939803BD418200F9204E, 259 E1D2939903BD418200F9204E, 260 E1D2939A03BD418200F9204E, 261 E1D2939B03BD418200F9204E, 262 E1D2939C03BD418200F9204E, 263 E1D2939D03BD418200F9204E, 264 E1D2939E03BD418200F9204E, 265 E1D2939F03BD418200F9204E, 266 E1D293A003BD418200F9204E, 267 E1D293A103BD418200F9204E, 268 E1D293A203BD418200F9204E, 269 E1D293A303BD418200F9204E, 270 E1D293A403BD418200F9204E, 271 E1D293A503BD418200F9204E, 272 E1D293A603BD418200F9204E, 273 E1D293A703BD418200F9204E, 274 E1D293A803BD418200F9204E, 275 E1D293A903BD418200F9204E, 276 E1D293AA03BD418200F9204E, 277 E1D293AB03BD418200F9204E, 278 E1D293AC03BD418200F9204E, 279 E1D293AD03BD418200F9204E, 280 E1D293AE03BD418200F9204E, 281 E1D293AF03BD418200F9204E, 282 E1D293B003BD418200F9204E, 283 E1D293B203BD418200F9204E, 284 E1D293B403BD418200F9204E, 285 E1D293B503BD418200F9204E, 286 E1D293B703BD418200F9204E, 287 E1D293B903BD418200F9204E, 288 E1D293BA03BD418200F9204E, 289 E1D293BB03BD418200F9204E, 290 E1D293BC03BD418200F9204E, 291 E1D293BD03BD418200F9204E, 292 E1D293BE03BD418200F9204E, 293 E1D293BF03BD418200F9204E, 294 E1D293C003BD418200F9204E, 295 E1D293C103BD418200F9204E, 296 E1D293C203BD418200F9204E, 297 E1D293C403BD418200F9204E, 298 E1D293C503BD418200F9204E, 299 E1D293C603BD418200F9204E, 300 E1D293C703BD418200F9204E, 301 E1D293C803BD418200F9204E, 302 E1D293C903BD418200F9204E, 303 E1D293CA03BD418200F9204E, 304 E1D293CB03BD418200F9204E, 305 E1D293CC03BD418200F9204E, 306 E1D293CD03BD418200F9204E, 307 E1D293CE03BD418200F9204E, 308 E1D293CF03BD418200F9204E, 309 E1D293D003BD418200F9204E, 310 E1D293D103BD418200F9204E, 311 E1D293D203BD418200F9204E, 312 E1D293D303BD418200F9204E, 313 E1D293D403BD418200F9204E, 314 E1D293D503BD418200F9204E, 315 E1D293D603BD418200F9204E, 316 E1D293D703BD418200F9204E, 317 E1D293D803BD418200F9204E, 318 E1D293D903BD418200F9204E, 319 E1D293DA03BD418200F9204E, 320 E1D293DB03BD418200F9204E, 321 E1D293DC03BD418200F9204E, 322 E1D293DD03BD418200F9204E, 323 E1D293DE03BD418200F9204E, 324 E1D293DF03BD418200F9204E, 325 E1D293E003BD418200F9204E, 326 E1D293E103BD418200F9204E, 327 E1D293E203BD418200F9204E, 328 E1D293E303BD418200F9204E, 329 E1D293E403BD418200F9204E, 330 E1D293E503BD418200F9204E, 331 E1D293E603BD418200F9204E, 332 E1D293E703BD418200F9204E, 333 E1D293E803BD418200F9204E, 334 E1D293E903BD418200F9204E, 335 E1D293EA03BD418200F9204E, 336 E1D293EB03BD418200F9204E, 337 E1D293EC03BD418200F9204E, 338 E1D293EE03BD418200F9204E, 339 E1D293F003BD418200F9204E, 340 E1D293F103BD418200F9204E, 341 E1D293F203BD418200F9204E, 342 E1D293F303BD418200F9204E, 343 E1D293F403BD418200F9204E, 344 E1D293F503BD418200F9204E, 345 E1D293F703BD418200F9204E, 346 E1D293F803BD418200F9204E, 347 E1D293F903BD418200F9204E, 348 E1D293FB03BD418200F9204E, 349 E1D293FC03BD418200F9204E, 350 E1D293FD03BD418200F9204E, 351 E1D293FE03BD418200F9204E, 352 E1D293FF03BD418200F9204E, 353 E1D2940003BD418200F9204E, 354 E1D2940103BD418200F9204E, 355 E1D2940203BD418200F9204E, 356 E1D2940303BD418200F9204E, 357 E1D2940403BD418200F9204E, 358 E1D2940503BD418200F9204E, 359 E1D2940603BD418200F9204E, 360 E1D2940703BD418200F9204E, 361 E1D2940803BD418200F9204E, 362 E1D2940903BD418200F9204E, 363 E1D2940A03BD418200F9204E, 364 E1D2940B03BD418200F9204E, 365 E1D2940C03BD418200F9204E, 366 E1D2940D03BD418200F9204E, 367 E1D2940E03BD418200F9204E, 368 E1D2940F03BD418200F9204E, 369 E1D2941003BD418200F9204E, 370 E1D2941103BD418200F9204E, 371 E1D2941203BD418200F9204E, 372 E1D2941303BD418200F9204E, 373 E1D2941403BD418200F9204E, 374 E1D2941503BD418200F9204E, 375 E1D2941603BD418200F9204E, 376 E1D2941703BD418200F9204E, 377 E1D2941803BD418200F9204E, 378 E1D2941903BD418200F9204E, 379 E1D2941A03BD418200F9204E, 380 E1D2941B03BD418200F9204E, 381 E1D2941C03BD418200F9204E, 382 E1D2941D03BD418200F9204E, 383 E1D2941E03BD418200F9204E, 384 E1D2941F03BD418200F9204E, 385 E1D2942003BD418200F9204E, 386 E1D2942103BD418200F9204E, 387 E1D2942203BD418200F9204E, 388 E1D2942303BD418200F9204E, 389 E1D2942403BD418200F9204E, 390 E1D2942503BD418200F9204E, 391 E1D2942603BD418200F9204E, 392 E1D2942703BD418200F9204E, 393 E1D2942803BD418200F9204E, 394 E1D2942903BD418200F9204E, 395 E1D2942A03BD418200F9204E, 396 E1D2942B03BD418200F9204E, 397 E1D2942C03BD418200F9204E, 398 E1D2942D03BD418200F9204E, 399 E1D2942E03BD418200F9204E, 400 E1D2942F03BD418200F9204E, 401 E1D2943003BD418200F9204E, 402 E1D2943103BD418200F9204E, 403 E1D2943203BD418200F9204E, 404 E1D2943303BD418200F9204E, 405 E1D2943403BD418200F9204E, 406 E1D2943503BD418200F9204E, 407 E1D2943603BD418200F9204E, 408 E1D2943703BD418200F9204E, 409 E1D2943803BD418200F9204E, 410 E1D2943903BD418200F9204E, 411 E195A29103BE251F00186F9B, 412 E195A29203BE251F00186F9B, 413 E195A29503BE251F00186F9B, 414 E195A29603BE251F00186F9B, 415 E195A29703BE251F00186F9B, 416 E195A29803BE251F00186F9B, 417 E195A29903BE251F00186F9B, 418 E195A29A03BE251F00186F9B, 419 E195A29D03BE251F00186F9B, 420 E195A29E03BE251F00186F9B, 421 E195A29F03BE251F00186F9B, 422 E195A2A003BE251F00186F9B, 423 E195A2A103BE251F00186F9B, 424 E195A2A203BE251F00186F9B, 425 E195A2A303BE251F00186F9B, 426 E195A2A503BE251F00186F9B, 427 E195A2A603BE251F00186F9B, 428 E195A2A703BE251F00186F9B, 429 E195A2A803BE251F00186F9B, 430 E195A2A903BE251F00186F9B, 431 E195A2AA03BE251F00186F9B, 432 E195A2AC03BE251F00186F9B, 433 E195A2AD03BE251F00186F9B, 434 E195A2AE03BE251F00186F9B, 435 E195A2AF03BE251F00186F9B, 436 E195A2B003BE251F00186F9B, 437 E195A2B103BE251F00186F9B, 438 E195A2B203BE251F00186F9B, 439 E195A2B303BE251F00186F9B, 440 E195A2B403BE251F00186F9B, 441 E195A2B503BE251F00186F9B, 442 E195A2B603BE251F00186F9B, 443 E195A2B703BE251F00186F9B, 444 E195A2B803BE251F00186F9B, 445 E195A2B903BE251F00186F9B, 446 E195A2BA03BE251F00186F9B, 447 E195A2BB03BE251F00186F9B, 448 E195A2BC03BE251F00186F9B, 449 E195A2BD03BE251F00186F9B, 450 E195A2BE03BE251F00186F9B, 451 E195A2C103BE251F00186F9B, 452 E195A2C203BE251F00186F9B, 453 E195A2C303BE251F00186F9B, 454 E195A2C403BE251F00186F9B, 455 E195A2C503BE251F00186F9B, 456 E195A2C603BE251F00186F9B, 457 E195A2C703BE251F00186F9B, 458 E195A2C803BE251F00186F9B, 459 E195A2C903BE251F00186F9B, 460 E195A2CA03BE251F00186F9B, 461 E195A2CB03BE251F00186F9B, 462 E195A2CD03BE251F00186F9B, 463 E195A2CF03BE251F00186F9B, 464 E195A2D103BE251F00186F9B, 465 E195A2D303BE251F00186F9B, 466 E195A2D503BE251F00186F9B, 467 E195A2D703BE251F00186F9B, 468 E195A2D903BE251F00186F9B, 469 E195A2DB03BE251F00186F9B, 470 E195A2DD03BE251F00186F9B, 471 E195A2DF03BE251F00186F9B, 472 E195A2E003BE251F00186F9B, 473 E195A2E103BE251F00186F9B, 474 E195A2E203BE251F00186F9B, 475 E195A2E303BE251F00186F9B, 476 E195A2E403BE251F00186F9B, 477 E195A2E503BE251F00186F9B, 478 E195A2E603BE251F00186F9B, 479 E195A2E803BE251F00186F9B, 480 E195A2E903BE251F00186F9B, 481 E195A2EA03BE251F00186F9B, 482 E195A2EB03BE251F00186F9B, 483 E195A2EC03BE251F00186F9B, 484 E195A2ED03BE251F00186F9B, 485 E195A2EE03BE251F00186F9B, 486 E195A2F003BE251F00186F9B, 487 E195A2F103BE251F00186F9B, 488 E195A2F303BE251F00186F9B, 489 E195A2F403BE251F00186F9B, 490 E195A2F503BE251F00186F9B, 491 E195A2F603BE251F00186F9B, 492 E195A2F703BE251F00186F9B, 493 E195A2F803BE251F00186F9B, 494 E195A2F903BE251F00186F9B, 495 E195A2FA03BE251F00186F9B, 496 E195A2FC03BE251F00186F9B, 497 E195A2FE03BE251F00186F9B, 498 E19DCB8503BE4A0A00B934BF, 499 E19DCB8603BE4A0A00B934BF, 500 E19DCB8703BE4A0A00B934BF, 501 E19DCB8903BE4A0A00B934BF, 502 E19DCB8A03BE4A0A00B934BF, 503 E19DCB8B03BE4A0A00B934BF, 504 E19DCB8C03BE4A0A00B934BF, 505 E19DCB8E03BE4A0A00B934BF, 506 E19DCB9003BE4A0A00B934BF, 507 E19DCB9103BE4A0A00B934BF, 508 E19DCB9303BE4A0A00B934BF, 509 E19DCB9403BE4A0A00B934BF, 510 E19DCB9503BE4A0A00B934BF, 511 E19DCB9603BE4A0A00B934BF, 512 E19DCB9703BE4A0A00B934BF, 513 E19DCB9803BE4A0A00B934BF, 514 E19DCB9903BE4A0A00B934BF, 515 E19DCB9A03BE4A0A00B934BF, 516 E19DCB9B03BE4A0A00B934BF, 517 E19DCB9C03BE4A0A00B934BF, 518 E19DCB9D03BE4A0A00B934BF, 519 E19DCB9E03BE4A0A00B934BF, 520 E19DCB9F03BE4A0A00B934BF, 521 E19DCBA003BE4A0A00B934BF, 522 E19DCBA103BE4A0A00B934BF, 523 E19DCBA203BE4A0A00B934BF, 524 E19DCBA303BE4A0A00B934BF, 525 E19DCBA403BE4A0A00B934BF, 526 E19DCBA503BE4A0A00B934BF, 527 E19DCBA603BE4A0A00B934BF, 528 E19DCBA703BE4A0A00B934BF, 529 E19DCBA803BE4A0A00B934BF, 530 E19DCBA903BE4A0A00B934BF, 531 E19DCBAA03BE4A0A00B934BF, 532 E19DCBAB03BE4A0A00B934BF, 533 E19DCBAC03BE4A0A00B934BF, 534 E19DCBAD03BE4A0A00B934BF, 535 E19DCBAE03BE4A0A00B934BF, 536 E19DCBAF03BE4A0A00B934BF, 537 E19DCBB003BE4A0A00B934BF, 538 E19DCBB103BE4A0A00B934BF, 539 E19DCBB203BE4A0A00B934BF, 540 E19DCBB603BE4A0A00B934BF, 541 E19DCBB703BE4A0A00B934BF, 542 E19DCBB803BE4A0A00B934BF, 543 E19DCBB903BE4A0A00B934BF, 544 E19DCBBA03BE4A0A00B934BF, 545 E19DCBBB03BE4A0A00B934BF, 546 E19DCBBC03BE4A0A00B934BF, 547 E19DCBBD03BE4A0A00B934BF, 548 E19DCCA203BE900300B934BF, 549 E19DCCA303BE900300B934BF, 550 E19DCCA403BE900300B934BF, 551 E19DCCA503BE900300B934BF, 552 E19DCCA603BE900300B934BF, 553 E19DCCA703BE900300B934BF, 554 E19DCCA803BE900300B934BF, 555 E19DCCA903BE900300B934BF, 556 E19DCCAB03BE900300B934BF, 557 E19DCCAC03BE900300B934BF, 558 E19DCCAE03BE900300B934BF, 559 E19DCCAF03BE900300B934BF, 560 E19DCCB003BE900300B934BF, 561 E19DCCB103BE900300B934BF, 562 E19DCCB203BE900300B934BF, 563 E19DCCB303BE900300B934BF, 564 E19DCCB403BE900300B934BF, 565 E19DCCB503BE900300B934BF, 566 E19DCCB603BE900300B934BF, 567 E19DCCB703BE900300B934BF, 568 E19DCCB903BE900300B934BF, 569 E19DCCBA03BE900300B934BF, 570 E19DCCBB03BE900300B934BF, 571 E19DCCBC03BE900300B934BF, 572 E19DCCBD03BE900300B934BF, 573 E19DCCBE03BE900300B934BF, 574 E19DCCBF03BE900300B934BF, 575 E19DCCC003BE900300B934BF, 576 E19DCCC103BE900300B934BF, 577 E19DCCC203BE900300B934BF, 578 E19DCCC303BE900300B934BF, 579 E19DCCC403BE900300B934BF, 580 E19DCCC503BE900300B934BF, 581 E19DCCC603BE900300B934BF, 582 E19DCCC703BE900300B934BF, 583 E19DCCC803BE900300B934BF, 584 E19DCCC903BE900300B934BF, 585 E19DCCCA03BE900300B934BF, 586 E19DCCCB03BE900300B934BF, 587 E19DCCCD03BE900300B934BF, 588 E19DCCCE03BE900300B934BF, 589 E19DCCCF03BE900300B934BF, 590 E19DCCD103BE900300B934BF, 591 E19DCCD203BE900300B934BF, 592 E19DCCD403BE900300B934BF, 593 E19DCCD503BE900300B934BF, 594 E19DCCD603BE900300B934BF, 595 E19DCCD703BE900300B934BF, 596 E19DCCD803BE900300B934BF, 597 E19DCCD903BE900300B934BF, 598 E19DCCDA03BE900300B934BF, 599 E19DCCDB03BE900300B934BF, 600 E1A9DEF703BF480F0089E8B2, 601 E1A9DEF903BF480F0089E8B2, 602 E1A9DEFB03BF480F0089E8B2, 603 E1A9DEFC03BF480F0089E8B2, 604 E1A9DEFD03BF480F0089E8B2, 605 E1A9DEFE03BF480F0089E8B2, 606 E1A9DF0003BF480F0089E8B2, 607 E1A9DF0203BF480F0089E8B2, 608 E1A9DF0303BF480F0089E8B2, 609 E1A9DF0403BF480F0089E8B2, 610 E1A9DF0503BF480F0089E8B2, 611 E1A9DF0603BF480F0089E8B2, 612 E1A9DF0703BF480F0089E8B2, 613 E1A9DF0803BF480F0089E8B2, 614 E1A9DF0A03BF480F0089E8B2, 615 E11CD2E303BF9B3300C49BEF, 616 E11CD2E503BF9B3300C49BEF, 617 E11CD2E603BF9B3300C49BEF, 618 E11CD2E703BF9B3300C49BEF, 619 E11CD2E803BF9B3300C49BEF, 620 E11CD2E903BF9B3300C49BEF, 621 E11CD2EA03BF9B3300C49BEF, 622 E11CD2EB03BF9B3300C49BEF, 623 E11CD2EC03BF9B3300C49BEF, 624 E11CD2ED03BF9B3300C49BEF, 625 E11CD2EE03BF9B3300C49BEF, 626 E11CD2EF03BF9B3300C49BEF, 627 E11CD2F603BF9B3300C49BEF, 628 E11CD2F803BF9B3300C49BEF, 629 E11CD2FB03BF9B3300C49BEF, 630 E17AED8B03C0F5D300B89ACF, 631 E17AED8C03C0F5D300B89ACF, 632 E17AED8D03C0F5D300B89ACF, 633 E17AED8E03C0F5D300B89ACF, 634 E17AED8F03C0F5D300B89ACF, 635 E17AED9003C0F5D300B89ACF, 636 E17AED9103C0F5D300B89ACF, 637 E17AED9203C0F5D300B89ACF, 638 E17AED9303C0F5D300B89ACF, 639 E17AED9403C0F5D300B89ACF, 640 E17AED9503C0F5D300B89ACF, 641 E17AED9603C0F5D300B89ACF, 642 E17AED9703C0F5D300B89ACF, 643 E17AED9803C0F5D300B89ACF, 644 E17AED9903C0F5D300B89ACF, 645 E17AED9A03C0F5D300B89ACF, 646 E17AED9B03C0F5D300B89ACF, 647 E17AED9C03C0F5D300B89ACF, 648 E17AED9D03C0F5D300B89ACF, 649 E17AED9E03C0F5D300B89ACF, 650 E17AED9F03C0F5D300B89ACF, 651 E17AEDA003C0F5D300B89ACF, 652 E17AEDA103C0F5D300B89ACF, 653 E17AEDA203C0F5D300B89ACF, 654 E17AEDA303C0F5D300B89ACF, 655 E17AEDA403C0F5D300B89ACF, 656 E17AEDA503C0F5D300B89ACF, 657 E17AEDA603C0F5D300B89ACF, 658 E17AEDA703C0F5D300B89ACF, 659 E17AEDA803C0F5D300B89ACF, 660 E17AEDA903C0F5D300B89ACF, 661 E17AEDAA03C0F5D300B89ACF, 662 E17AEDAB03C0F5D300B89ACF, 663 E17AEDAC03C0F5D300B89ACF, 664 E17AEDAD03C0F5D300B89ACF, 665 E17AEDAE03C0F5D300B89ACF, 666 E17AEDAF03C0F5D300B89ACF, 667 E17AEDB003C0F5D300B89ACF, 668 E17AEDB103C0F5D300B89ACF, 669 E17AEDB203C0F5D300B89ACF, 670 E17AEDB303C0F5D300B89ACF, 671 E17AEDB403C0F5D300B89ACF, 672 E17AEDB503C0F5D300B89ACF, 673 E17AEDB603C0F5D300B89ACF, 674 E17AEDB703C0F5D300B89ACF, 675 E17AEDB803C0F5D300B89ACF, 676 E17AEDB903C0F5D300B89ACF, 677 E17AEDBA03C0F5D300B89ACF, 678 E17AEDBB03C0F5D300B89ACF, 679 E17AEDBC03C0F5D300B89ACF, 680 E17AEDBD03C0F5D300B89ACF, 681 E17AEDBE03C0F5D300B89ACF, 682 E17AEDBF03C0F5D300B89ACF, 683 E17AEDC003C0F5D300B89ACF, 684 E17AEDC103C0F5D300B89ACF, 685 E17AEDC203C0F5D300B89ACF, 686 E17AEDC303C0F5D300B89ACF, 687 E17AEDC403C0F5D300B89ACF, 688 E17AEDC503C0F5D300B89ACF, 689 E17AEDC603C0F5D300B89ACF, 690 E17AEDC703C0F5D300B89ACF, 691 E17AEDC803C0F5D300B89ACF, 692 E17AEDC903C0F5D300B89ACF, 693 E117A4B203C3E9C600E10BA2, 694 E117A4B303C3E9C600E10BA2, 695 E117A4B403C3E9C600E10BA2, 696 E1096EB803C3EDB0009B92C1, 697 ); 698 }; 745 699 NavCount = 1; 746 700 NavGeometry0 = { 747 Frame = "{{0, 0}, { 150, 530}}";701 Frame = "{{0, 0}, {689, 635}}"; 748 702 NavBarVisible = YES; 749 703 }; 704 NavSplitVertical = NO; 750 705 }; 751 706 SplitCount = 1; 752 Tab 0= {707 Tab1 = { 753 708 Debugger = { 754 709 Split0 = { … … 760 715 LauncherConfigVersion = 7; 761 716 }; 762 Tab 1= {717 Tab2 = { 763 718 LauncherConfigVersion = 3; 764 719 Runner = { 765 720 }; 766 721 }; 767 TabCount = 4; 722 TabCount = 5; 723 }; 724 SplitCount = 1; 725 Tab1 = { 726 OptionsSetName = "Flat, project classes"; 727 }; 728 TabCount = 5; 729 }; 730 }, 731 { 732 LeftSlideOut = { 733 Split0 = { 734 Split0 = { 735 NavCount = 1; 736 NavGeometry0 = { 737 Frame = "{{0, 0}, {945, 150}}"; 738 NavBarVisible = YES; 739 }; 740 NavSplitVertical = NO; 741 }; 742 SplitCount = 1; 743 Tab1 = { 744 Debugger = { 745 Split0 = { 746 SplitCount = 2; 747 }; 748 SplitCount = 1; 749 TabCount = 2; 750 }; 751 LauncherConfigVersion = 7; 752 }; 753 Tab2 = { 754 LauncherConfigVersion = 3; 755 Runner = { 756 }; 757 }; 758 TabCount = 5; 768 759 }; 769 760 SplitCount = 1; … … 780 771 NavCount = 1; 781 772 NavGeometry0 = { 782 Frame = "{{0, 0}, { 973, 150}}";773 Frame = "{{0, 0}, {769, 153}}"; 783 774 NavBarVisible = YES; 784 775 }; 776 NavSplitVertical = NO; 785 777 }; 786 778 SplitCount = 1; 787 Tab 0= {779 Tab1 = { 788 780 Debugger = { 789 781 Split0 = { … … 795 787 LauncherConfigVersion = 7; 796 788 }; 797 Tab 1= {789 Tab2 = { 798 790 LauncherConfigVersion = 3; 799 791 Runner = { 800 792 }; 801 793 }; 802 TabCount = 4;794 TabCount = 5; 803 795 }; 804 796 SplitCount = 1; … … 814 806 Split0 = { 815 807 NavContent0 = { 816 bookmark = F562F80B037E5D2101AEEDB1;808 bookmark = E1096EC303C3F504009B92C1; 817 809 history = ( 818 F5B163A5037E543A01AEEDB1, 810 E17AEDCC03C0F5D300B89ACF, 811 E117A4B803C3E9C600E10BA2, 812 E1096EBB03C3EDB0009B92C1, 813 ); 814 prevStack = ( 815 E17AEDCE03C0F5D300B89ACF, 816 E17AEDCF03C0F5D300B89ACF, 817 E117A4BA03C3E9C600E10BA2, 819 818 ); 820 819 }; 821 820 NavCount = 1; 822 821 NavGeometry0 = { 823 Frame = "{{0, 0}, { 668, 621}}";822 Frame = "{{0, 0}, {749, 201}}"; 824 823 NavBarVisible = YES; 825 824 }; 825 NavSplitVertical = NO; 826 826 }; 827 827 SplitCount = 1; 828 Tab 0= {828 Tab1 = { 829 829 Debugger = { 830 830 Split0 = { … … 836 836 LauncherConfigVersion = 7; 837 837 }; 838 Tab 1= {838 Tab2 = { 839 839 LauncherConfigVersion = 3; 840 840 Runner = { 841 841 }; 842 842 }; 843 TabCount = 4;843 TabCount = 5; 844 844 }; 845 845 SplitCount = 1; … … 854 854 Split0 = { 855 855 Split0 = { 856 NavContent0 = { 857 bookmark = E1096EC403C3F504009B92C1; 858 history = ( 859 E1096EBC03C3EDB0009B92C1, 860 ); 861 }; 856 862 NavCount = 1; 857 863 NavGeometry0 = { 858 Frame = "{{0, 0}, {6 18, 150}}";864 Frame = "{{0, 0}, {668, 621}}"; 859 865 NavBarVisible = YES; 860 866 }; 867 NavSplitVertical = NO; 861 868 }; 862 869 SplitCount = 1; 863