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

Last change on this file since 60 was 60, checked in by Nicholas Riley, 17 years ago

PSScriptAlert.m: Removed reference to NDAppleScriptObject.

PSMovieAlertController.[hm]: Added minimum sizing.

NJRCenteringMovieView.[hm]: Support for centering movie inside its
frame if the frame is too large for the movie; sizes movie
proportionally if necessary (not used in Pester).

NSImage-NJRExtensions.[hm]: Fixed copyright.

Read Me.rtfd: Updated with bug fixes.

PSMovieAlert.m: Note bug in NSMovieView, currently doesn't affect us.

NJRQTMediaPopUpButton.m: Work around background processor use bug when
NSMovieView has movie set but not playing.

NJRVoicePopUpButton.m: Removed obsolete comment.

PSApplication.m: Only show alarm set window on rapp if alerts aren't
expiring.

PSAlarms.[hm]: Added -alarmsExpiring for support of conditional
rapp window open feature in PSApplication.

PSAlarmSetController.m: Stop window update timer and movie playback on
hide, restart timer on activate - fixes background processor usage.

File size: 9.0 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#import "NSDictionary-NJRExtensions.h"
12
13NSString * const PSAlarmImportException = @"PSAlarmImportException";
14
15NSString * const PSAlarmsDidChangeNotification = @"PSAlarmsDidChangeNotification";
16NSString * const PSAlarmsNextAlarmDidChangeNotification = @"PSAlarmsNextAlarmDidChangeNotification";
17
18// NSUserDefaults key
19static NSString * const PSPendingAlarms = @"Pester pending alarms"; // 1.0 Ð 1.1a3
20static NSString * const PSAllAlarms = @"Pester alarms"; // 1.1a4 Ð
21
22// property list keys
23static NSString * const PLAlarmsPending = @"pending";
24static NSString * const PLAlarmsExpired = @"expired";
25
26static PSAlarms *PSAlarmsAllAlarms = nil;
27
28@interface PSAlarms (Private)
29
30- (void)_updateNextAlarm;
31
32@end
33
34@implementation PSAlarms
35
36+ (void)setUp;
37{
38    if (PSAlarmsAllAlarms == nil) {
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        }
45        [PSAlarmsAllAlarms _updateNextAlarm]; // only generate notifications after singleton established
46    }
47}
48
49+ (PSAlarms *)allAlarms;
50{
51    NSAssert(PSAlarmsAllAlarms != nil, @"Attempt to use +[PSAlarms allAlarms] before setup complete");
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];
95}
96
97- (void)_updateNextAlarm;
98{
99    NSEnumerator *e;
100    PSAlarm *alarm, *oldNextAlarm = nextAlarm;
101    [nextAlarm release];
102    nextAlarm = nil;
103    // sort alarms so earliest is first
104    [alarms sortUsingSelector: @selector(compareDate:)];
105    // find first un-expired alarm
106    e = [alarms objectEnumerator];
107    while ( (alarm = [e nextObject]) != nil) {
108        if ([alarm isValid]) {
109            nextAlarm = [alarm retain];
110            break;
111        }
112    }
113    if (oldNextAlarm != nextAlarm)
114        [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsNextAlarmDidChangeNotification object: nextAlarm];
115}
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
126- (id)init;
127{
128    if ( (self = [super init]) != nil) {
129        alarms = [[NSMutableArray alloc] init];
130        expiredAlarms = [[NSMutableSet alloc] init];
131        [self _setUpNotifications];
132    }
133    return self;
134}
135
136- (void)dealloc;
137{
138    [alarms release];
139    [expiredAlarms release];
140    [[NSNotificationCenter defaultCenter] removeObserver: self];
141    [super dealloc];
142}
143
144#pragma mark accessing
145
146- (NSArray *)alarms;
147{
148    return alarms;
149}
150
151- (PSAlarm *)nextAlarm;
152{
153    return nextAlarm;
154}
155
156- (int)alarmCount;
157{
158    return [alarms count];
159}
160
161- (PSAlarm *)alarmAtIndex:(int)index;
162{
163    return [alarms objectAtIndex: index];
164}
165
166- (void)removeAlarmAtIndex:(int)index;
167{
168    [(PSAlarm *)[alarms objectAtIndex: index] cancelTimer];
169    [alarms removeObjectAtIndex: index];
170}
171
172- (void)removeAlarmsAtIndices:(NSArray *)indices;
173{
174    NSEnumerator *e = [indices objectEnumerator];
175    NSNumber *n;
176    int indexCount = [indices count], i = 0, alarmIndex;
177    int *indexArray = (int *)malloc(indexCount * sizeof(int));
178    NS_DURING
179        while ( (n = [e nextObject]) != nil) {
180            alarmIndex = [n intValue];
181            [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancelTimer];
182            indexArray[i] = alarmIndex;
183            i++;
184        }
185        [alarms removeObjectsFromIndices: indexArray numIndices: indexCount];
186        free(indexArray); indexArray = NULL;
187        [self _changed];
188    NS_HANDLER
189        free(indexArray);
190        [self _changed];
191        [localException raise];
192    NS_ENDHANDLER
193}
194
195- (void)removeAlarms:(NSSet *)alarmsToRemove;
196{
197    NSEnumerator *e = [alarms objectEnumerator];
198    PSAlarm *alarm;
199    NSMutableArray *indices = [NSMutableArray arrayWithCapacity: [alarmsToRemove count]];
200    int alarmIndex = 0;
201
202    while ( (alarm = [e nextObject]) != nil) {
203        if ([alarmsToRemove containsObject: alarm])
204            [indices addObject: [NSNumber numberWithInt: alarmIndex]];
205        alarmIndex++;
206    }
207    [self removeAlarmsAtIndices: indices];
208}
209
210- (BOOL)alarmsExpiring;
211{
212    return [expiredAlarms count] != 0;
213}
214
215#pragma mark property list serialization (Pester 1.1)
216
217- (NSDictionary *)propertyListRepresentation;
218{
219    NSMutableArray *plPendingAlarms = [[NSMutableArray alloc] initWithCapacity: [alarms count]];
220    NSMutableArray *plExpiredAlarms = [[NSMutableArray alloc] initWithCapacity: [expiredAlarms count]];
221    NSDictionary *plAllAlarms, *plAlarm;
222    NSEnumerator *e;
223    PSAlarm *alarm;
224
225    e = [alarms objectEnumerator];
226    while ( (alarm = [e nextObject]) != nil) {
227        plAlarm = [alarm propertyListRepresentation];
228        if (plAlarm != nil)
229            [plPendingAlarms addObject: plAlarm];
230    }
231
232    e = [expiredAlarms objectEnumerator];
233    while ( (alarm = [e nextObject]) != nil) {
234        plAlarm = [alarm propertyListRepresentation];
235        if (plAlarm != nil)
236            [plExpiredAlarms addObject: plAlarm];
237    }
238   
239    plAllAlarms = [NSDictionary dictionaryWithObjectsAndKeys:
240        plPendingAlarms, PLAlarmsPending, plExpiredAlarms, PLAlarmsExpired, nil];
241    [plPendingAlarms release];
242    [plExpiredAlarms release];
243   
244    return plAllAlarms;
245}
246
247- (id)initWithPropertyList:(NSDictionary *)dict;
248{
249    if ( (self = [super init]) != nil) {
250        NSArray *plPendingAlarms = [dict objectForRequiredKey: PLAlarmsPending];
251        NSArray *plExpiredAlarms = [dict objectForRequiredKey: PLAlarmsExpired];
252        NSEnumerator *e;
253        NSDictionary *plAlarm;
254        PSAlarm *alarm;
255
256        alarms = [[NSMutableArray alloc] initWithCapacity: [plPendingAlarms count]];
257        e = [plPendingAlarms objectEnumerator];
258        while ( (plAlarm = [e nextObject]) != nil) {
259            [alarms addObject: [[PSAlarm alloc] initWithPropertyList: plAlarm]];
260        }
261
262        e = [plExpiredAlarms objectEnumerator];
263        while ( (plAlarm = [e nextObject]) != nil) {
264            // expired alarms may be just that, or they may have outstanding repeats - if the latter, PSAlarm will reschedule the alarm.
265            if ( (alarm = [[PSAlarm alloc] initWithPropertyList: plAlarm]) != nil)
266                [alarms addObject: alarm];
267        }
268        expiredAlarms = [[NSMutableSet alloc] init];
269       
270        [self _setUpNotifications];
271    }
272    return self;
273}
274
275#pragma mark archiving (Pester 1.0)
276
277- (unsigned)countOfVersion1Alarms;
278{
279    return [[[NSUserDefaults standardUserDefaults] objectForKey: PSPendingAlarms] count];
280}
281
282- (void)discardVersion1Alarms;
283{
284    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
285    [defaults removeObjectForKey: PSPendingAlarms];
286    [defaults synchronize];
287}
288
289- (void)importVersion1Alarms;
290{
291    NSArray *alarmsData = [[NSUserDefaults standardUserDefaults] arrayForKey: PSPendingAlarms];
292    NSEnumerator *e = [alarmsData objectEnumerator];
293    NSData *alarmData;
294    PSAlarm *alarm;
295    while ( (alarmData = [e nextObject]) != nil) {
296        NS_DURING
297            alarm = [NSUnarchiver unarchiveObjectWithData: alarmData];
298        NS_HANDLER
299            alarm = nil;
300            // XXX
301        NS_ENDHANDLER
302        if (alarm != nil)
303            [alarms addObject: alarm];
304    }
305}
306
307@end
Note: See TracBrowser for help on using the repository browser.