source: releases/Pester/1.0/Source/PSAlarms.m @ 111

Last change on this file since 111 was 28, checked in by Nicholas Riley, 19 years ago

Pester 1.0

File size: 4.7 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(compare:)];
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- (int)alarmCount;
129{
130    return [alarms count];
131}
132
133- (PSAlarm *)alarmAtIndex:(int)index;
134{
135    return [alarms objectAtIndex: index];
136}
137
138- (void)removeAlarmAtIndex:(int)index;
139{
140    [(PSAlarm *)[alarms objectAtIndex: index] cancel];
141    [alarms removeObjectAtIndex: index];
142}
143
144- (void)removeAlarmsAtIndices:(NSArray *)indices;
145{
146    NSEnumerator *e = [indices objectEnumerator];
147    NSNumber *n;
148    int indexCount = [indices count], i = 0, alarmIndex;
149    int *indexArray = (int *)malloc(indexCount * sizeof(int));
150    NS_DURING
151        while ( (n = [e nextObject]) != nil) {
152            alarmIndex = [n intValue];
153            [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancel];
154            indexArray[i] = alarmIndex;
155            i++;
156        }
157        [alarms removeObjectsFromIndices: indexArray numIndices: indexCount];
158        [self _changed];
159    NS_HANDLER
160        free(indexArray);
161        [self _changed];
162        [localException raise];
163    NS_ENDHANDLER
164}
165
166@end
Note: See TracBrowser for help on using the repository browser.