source: trunk/Cocoa/Pester/Source/PSAlarms.m@ 51

Last change on this file since 51 was 51, checked in by Nicholas Riley, 21 years ago

Alarms.nib: Removed horizontal scroll bar. Turned on grid. Set delegate to NJRTableDelegate instead of PSAlarmSetController.

NJRTableDelegate: In general, made functional (was previously unused). Fixed MyCompanyName. Changed ORDER_BY_CONTEXT to use key-value coding instead of assuming data consists of a dictionary of dictionaries. Added sorting support (reorderedData, replaces oData) with autosave support for sort context. Added _positionTypeSelectDisplay, which adjusts position and justification of type select display control based on the current sort column. Added support for reverse sorting in type select string. Use table data source instead of sorted data so text matches as displayed (this will break with non-text cells...).

NJRTableView: Adapted from iTableView (Jaguar table alternate table background color), TableTester (most everything else) and NJROutlineView (keyDown, moveToBeginning/EndOfDocument). Support for type selection, delete shortcut for row deletion, and iTunes-alike background colors and frame.

NSCharacterSet-NJRExtensions: Moved _typeSelectSet from NJROutlineView as it's now shared with NJRTableView. Still need to factor NJROutlineView as embedded in HostLauncher some day.

PSAlarm: Reorganized, renamed and categorized methods. Added time accessor for the benefit of sorting. Renamed compare: to compareDate: for clarity. Added compareMessage:, though it's currently unused. Renamed cancel to cancelTimer for clarity.

PSAlarmSetController: More fun with initial first responder on window show/hide; still need to work around bug properly (subclass NSComboBox?) and fix it for real. As is, works for OS X 10.1.

PSAlarms: Added alarms accessor, returning alarm array. Fixed memory leak on successful alarm removal (oops). Added removeAlarms:, needed with sorted alarm list.

PSAlarmsController: Set window resize increment. Changes to table delegate methods to use reordered alarm list. Register for NSTableViewSelectionDidChangeNotification now we're no longer the table view delegate. Fixed autoselection in alarmsChanged by using data reordering support in NJRTableView. Implement NJRTableViewDataSource to permit deletion from table view.

Pester.pbproj: Added new files.

Read Me.rtfd: Added TableTester/iTableView acknowledgements. Updated release notes.

File size: 5.3 KB
Line 
1//
2// PSAlarms.m
3// Pester
4//
5// Created by Nicholas Riley on Fri Oct 11 2002.
6// Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "PSAlarms.h"
10#import "PSAlarm.h"
11
12NSString * const PSAlarmsDidChangeNotification = @"PSAlarmsDidChangeNotification";
13NSString * const PSAlarmsNextAlarmDidChangeNotification = @"PSAlarmsNextAlarmDidChangeNotification";
14
15static NSString * const PSPendingAlarms = @"Pester pending alarms"; // NSUserDefaults key
16
17static PSAlarms *PSAlarmsAllAlarms = nil;
18
19@interface PSAlarms (Private)
20
21- (void)_updateNextAlarm;
22
23@end
24
25@implementation PSAlarms
26
27+ (void)setUp;
28{
29 if (PSAlarmsAllAlarms == nil) {
30 PSAlarmsAllAlarms = [[self alloc] init];
31 [PSAlarmsAllAlarms _updateNextAlarm]; // only generate notifications after singleton established
32 }
33}
34
35+ (PSAlarms *)allAlarms;
36{
37 NSAssert(PSAlarmsAllAlarms != nil, @"Attempt to use +[PSAlarms allAlarms] before setup complete");
38 return PSAlarmsAllAlarms;
39}
40
41- (void)_updateNextAlarm;
42{
43 NSEnumerator *e;
44 PSAlarm *alarm, *oldNextAlarm = nextAlarm;
45 [nextAlarm release];
46 nextAlarm = nil;
47 // sort alarms so earliest is first
48 [alarms sortUsingSelector: @selector(compareDate:)];
49 // find first un-expired alarm
50 e = [alarms objectEnumerator];
51 while ( (alarm = [e nextObject]) != nil) {
52 if ([alarm isValid]) {
53 nextAlarm = [alarm retain];
54 break;
55 }
56 }
57 if (oldNextAlarm != nextAlarm)
58 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsNextAlarmDidChangeNotification object: nextAlarm];
59}
60
61- (id)init;
62{
63 if ( (self = [super init]) != nil) {
64 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];
81 }
82 return self;
83}
84
85- (void)dealloc;
86{
87 [alarms release];
88 [[NSNotificationCenter defaultCenter] removeObserver: self];
89 [super dealloc];
90}
91
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];
121}
122
123- (PSAlarm *)nextAlarm;
124{
125 return nextAlarm;
126}
127
128- (NSArray *)alarms;
129{
130 return alarms;
131}
132
133- (int)alarmCount;
134{
135 return [alarms count];
136}
137
138- (PSAlarm *)alarmAtIndex:(int)index;
139{
140 return [alarms objectAtIndex: index];
141}
142
143- (void)removeAlarmAtIndex:(int)index;
144{
145 [(PSAlarm *)[alarms objectAtIndex: index] cancelTimer];
146 [alarms removeObjectAtIndex: index];
147}
148
149- (void)removeAlarmsAtIndices:(NSArray *)indices;
150{
151 NSEnumerator *e = [indices objectEnumerator];
152 NSNumber *n;
153 int indexCount = [indices count], i = 0, alarmIndex;
154 int *indexArray = (int *)malloc(indexCount * sizeof(int));
155 NS_DURING
156 while ( (n = [e nextObject]) != nil) {
157 alarmIndex = [n intValue];
158 [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancelTimer];
159 indexArray[i] = alarmIndex;
160 i++;
161 }
162 [alarms removeObjectsFromIndices: indexArray numIndices: indexCount];
163 free(indexArray); indexArray = NULL;
164 [self _changed];
165 NS_HANDLER
166 free(indexArray);
167 [self _changed];
168 [localException raise];
169 NS_ENDHANDLER
170}
171
172- (void)removeAlarms:(NSSet *)alarmsToRemove;
173{
174 NSEnumerator *e = [alarms objectEnumerator];
175 PSAlarm *alarm;
176 NSMutableArray *indices = [NSMutableArray arrayWithCapacity: [alarmsToRemove count]];
177 int alarmIndex = 0;
178
179 while ( (alarm = [e nextObject]) != nil) {
180 if ([alarmsToRemove containsObject: alarm])
181 [indices addObject: [NSNumber numberWithInt: alarmIndex]];
182 alarmIndex++;
183 }
184 [self removeAlarmsAtIndices: indices];
185}
186
187@end
Note: See TracBrowser for help on using the repository browser.