source: trunk/Cocoa/Pester/Source/PSAlarm.m@ 39

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

Changes for Pester 1.1d1.

File size: 9.0 KB
Line 
1//
2// PSAlarm.m
3// Pester
4//
5// Created by Nicholas Riley on Wed Oct 09 2002.
6// Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "PSAlarm.h"
10#import "PSAlert.h"
11
12NSString * const PSAlarmTimerSetNotification = @"PSAlarmTimerSetNotification";
13NSString * const PSAlarmTimerExpiredNotification = @"PSAlarmTimerExpiredNotification";
14
15// XXX need to reset pending alarms after sleep, they "freeze" and never expire.
16
17@implementation PSAlarm
18
19- (void)dealloc;
20{
21 // NSLog(@"DEALLOC %@", self);
22 alarmType = PSAlarmInvalid;
23 [alarmDate release]; alarmDate = nil;
24 [alarmMessage release]; alarmMessage = nil;
25 [invalidMessage release]; invalidMessage = nil;
26 [timer invalidate]; [timer release]; timer = nil;
27 [alerts release]; alerts = nil;
28 [super dealloc];
29}
30
31- (void)_setAlarmDate:(NSCalendarDate *)aDate;
32{
33 if (alarmDate != aDate) {
34 [alarmDate release];
35 alarmDate = nil;
36 alarmDate = [aDate retain];
37 }
38}
39
40- (void)_invalidate:(NSString *)aMessage;
41{
42 alarmType = PSAlarmInvalid;
43 if (aMessage != invalidMessage) {
44 [invalidMessage release];
45 invalidMessage = nil;
46 [self _setAlarmDate: nil];
47 alarmInterval = 0;
48 invalidMessage = [aMessage retain];
49 }
50}
51
52- (void)_validateForType:(PSAlarmType)type;
53{
54 if (alarmType == PSAlarmSet) return; // already valid
55 [invalidMessage release];
56 invalidMessage = nil;
57 alarmType = type;
58}
59
60- (void)_setDateFromInterval;
61{
62 [alarmDate release]; alarmDate = nil;
63 alarmDate = [NSCalendarDate dateWithTimeIntervalSinceNow: alarmInterval];
64 [alarmDate retain];
65 [self _validateForType: PSAlarmInterval];
66}
67
68- (void)setInterval:(NSTimeInterval)anInterval;
69{
70 alarmInterval = anInterval;
71 if (alarmInterval <= 0) {
72 [self _invalidate: @"Please specify an alarm interval."]; return;
73 }
74 [self _setDateFromInterval];
75}
76
77- (void)_setIntervalFromDate;
78{
79 alarmInterval = [alarmDate timeIntervalSinceNow] + 1;
80 if (alarmInterval <= 0) {
81 [self _invalidate: @"Please specify an alarm time in the future."];
82 return;
83 }
84 [self _validateForType: PSAlarmDate];
85}
86
87- (void)setForDateAtTime:(NSCalendarDate *)dateTime;
88{
89 [self _setAlarmDate: dateTime];
90 [self _setIntervalFromDate];
91}
92
93- (void)setForDate:(NSDate *)date atTime:(NSDate *)time;
94{
95 NSCalendarDate *calTime, *calDate;
96 if (time == nil && date == nil) {
97 [self _invalidate: @"Please specify an alarm date and time."]; return;
98 }
99 if (time == nil) {
100 [self _invalidate: @"Please specify an alarm time."]; return;
101 }
102 if (date == nil) {
103 [self _invalidate: @"Please specify an alarm date."]; return;
104 }
105 // XXX if calTime's date is different from the default date, complain
106 calTime = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: [time timeIntervalSinceReferenceDate]];
107 calDate = [NSCalendarDate dateWithTimeIntervalSinceReferenceDate: [date timeIntervalSinceReferenceDate]];
108 if (calTime == nil || calDate == nil) {
109 [self _invalidate: @"Please specify a reasonable date and time."];
110 }
111 [self setForDateAtTime:
112 [[[NSCalendarDate alloc] initWithYear: [calDate yearOfCommonEra]
113 month: [calDate monthOfYear]
114 day: [calDate dayOfMonth]
115 hour: [calTime hourOfDay]
116 minute: [calTime minuteOfHour]
117 second: [calTime secondOfMinute]
118 timeZone: nil] autorelease]];
119}
120
121- (BOOL)isValid;
122{
123 if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
124 return (alarmType != PSAlarmInvalid);
125}
126
127- (void)setMessage:(NSString *)aMessage;
128{
129 if (aMessage != alarmMessage) {
130 [alarmMessage release];
131 alarmMessage = nil;
132 alarmMessage = [aMessage retain];
133 }
134}
135
136- (NSString *)message;
137{
138 if (alarmMessage == nil || [alarmMessage isEqualToString: @""])
139 return @"Alarm!";
140 return alarmMessage;
141}
142
143- (NSString *)invalidMessage;
144{
145 if (invalidMessage == nil) return @"";
146 return invalidMessage;
147}
148
149- (NSCalendarDate *)date;
150{
151 if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
152 return alarmDate;
153}
154
155- (NSString *)shortDateString;
156{
157 return [[self date] descriptionWithCalendarFormat: [[NSUserDefaults standardUserDefaults] stringForKey: NSShortDateFormatString]];
158}
159
160- (NSString *)timeString;
161{
162 return [[self date] descriptionWithCalendarFormat: @"%1I:%M:%S %p"]; // XXX regular format doesn't work
163}
164
165- (NSString *)timeRemainingString;
166{
167 static const unsigned long long minute = 60, hour = minute * 60, day = hour * 24, year = day * 365.26;
168 unsigned long long interval = [self interval];
169 // +[NSString stringWithFormat:] in 10.1 does not support long longs: work around it by converting to unsigned ints or longs for display
170 if (interval == 0) return @"ÇexpiredÈ";
171 if (interval < minute) return [NSString stringWithFormat: @"%us", (unsigned)interval];
172 if (interval < day) return [NSString stringWithFormat: @"%uh %um", (unsigned)(interval / hour), (unsigned)((interval % hour) / minute)];
173 if (interval < year) return [NSString stringWithFormat: @"%u days", (unsigned)(interval / day)];
174 if (interval < 2 * year) return @"One year";
175 return [NSString stringWithFormat: @"%lu years", (unsigned long)(interval / year)];
176}
177
178- (NSTimeInterval)interval;
179{
180 if (alarmType == PSAlarmSet || alarmType == PSAlarmDate) [self _setIntervalFromDate];
181 return alarmInterval;
182}
183
184- (BOOL)setTimer;
185{
186 switch (alarmType) {
187 case PSAlarmDate: if (![self isValid]) return NO;
188 case PSAlarmInterval:
189 timer = [NSTimer scheduledTimerWithTimeInterval: alarmInterval
190 target: self
191 selector: @selector(_timerExpired:)
192 userInfo: nil
193 repeats: NO];
194 if (timer != nil) {
195 [timer retain];
196 alarmType = PSAlarmSet;
197 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerSetNotification object: self];
198 return YES;
199 }
200 default:
201 return NO;
202 }
203}
204
205- (void)cancel;
206{
207 [timer invalidate]; [timer release]; timer = nil;
208}
209
210- (void)_timerExpired:(NSTimer *)aTimer;
211{
212 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self];
213 [timer release]; timer = nil;
214}
215
216- (NSString *)_alarmTypeString;
217{
218 switch (alarmType) {
219 case PSAlarmDate: return @"PSAlarmDate";
220 case PSAlarmInterval: return @"PSAlarmInterval";
221 case PSAlarmSet: return @"PSAlarmSet";
222 case PSAlarmInvalid: return @"PSAlarmInvalid";
223 default: return [NSString stringWithFormat: @"<unknown: %u>", alarmType];
224 }
225}
226
227- (NSComparisonResult)compare:(PSAlarm *)otherAlarm;
228{
229 return [[self date] compare: [otherAlarm date]];
230}
231
232- (void)addAlert:(PSAlert *)alert;
233{
234 if (alerts == nil) alerts = [[NSMutableArray alloc] initWithCapacity: 4];
235 [alerts addObject: alert];
236}
237
238- (void)removeAlerts;
239{
240 [alerts removeAllObjects];
241}
242
243- (NSArray *)alerts;
244{
245 return [[alerts copy] autorelease];
246}
247
248- (NSString *)description;
249{
250 return [NSString stringWithFormat: @"%@: type %@ date %@ interval %.1f%@",
251 [super description], [self _alarmTypeString], alarmDate, alarmInterval,
252 (alarmType == PSAlarmInvalid ?
253 [NSString stringWithFormat: @"\ninvalid message: %@", invalidMessage]
254 : (alarmType == PSAlarmSet ?
255 [NSString stringWithFormat: @"\ntimer: %@", timer] : @""))];
256}
257
258- (void)encodeWithCoder:(NSCoder *)coder;
259{
260 if (![self isValid]) return;
261 [coder encodeValueOfObjCType: @encode(PSAlarmType) at: &alarmType];
262 switch (alarmType) {
263 case PSAlarmDate:
264 case PSAlarmSet:
265 [coder encodeObject: alarmDate];
266 break;
267 case PSAlarmInterval:
268 [coder encodeValueOfObjCType: @encode(NSTimeInterval) at: &alarmInterval];
269 break;
270 default:
271 break;
272 }
273 [coder encodeObject: alarmMessage];
274 // NSLog(@"encoded: %@", self); // XXX happening twice, gdb refuses to show proper backtrace, grr
275 return;
276}
277
278- (id)initWithCoder:(NSCoder *)coder;
279{
280 if ( (self = [super init]) != nil) {
281 [coder decodeValueOfObjCType: @encode(PSAlarmType) at: &alarmType];
282 switch (alarmType) {
283 case PSAlarmDate:
284 case PSAlarmSet:
285 [self _setAlarmDate: [coder decodeObject]];
286 break;
287 case PSAlarmInterval:
288 [coder decodeValueOfObjCType: @encode(NSTimeInterval) at: &alarmInterval];
289 break;
290 default:
291 break;
292 }
293 [self setMessage: [coder decodeObject]];
294 if (alarmType == PSAlarmSet) {
295 alarmType = PSAlarmDate;
296 [self setTimer];
297 }
298 }
299 return self;
300}
301
302@end
Note: See TracBrowser for help on using the repository browser.