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

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

Changes for Pester 1.1d1.

File size: 9.0 KB
RevLine 
[24]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"
[34]10#import "PSAlert.h"
[24]11
[26]12NSString * const PSAlarmTimerSetNotification = @"PSAlarmTimerSetNotification";
13NSString * const PSAlarmTimerExpiredNotification = @"PSAlarmTimerExpiredNotification";
[24]14
[34]15// XXX need to reset pending alarms after sleep, they "freeze" and never expire.
16
[24]17@implementation PSAlarm
18
[26]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;
[28]26 [timer invalidate]; [timer release]; timer = nil;
[34]27 [alerts release]; alerts = nil;
[26]28 [super dealloc];
29}
30
[24]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{
[28]54 if (alarmType == PSAlarmSet) return; // already valid
[24]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 }
[26]74 [self _setDateFromInterval];
[24]75}
76
77- (void)_setIntervalFromDate;
78{
[28]79 alarmInterval = [alarmDate timeIntervalSinceNow] + 1;
[24]80 if (alarmInterval <= 0) {
81 [self _invalidate: @"Please specify an alarm time in the future."];
82 return;
83 }
84 [self _validateForType: PSAlarmDate];
85}
86
[26]87- (void)setForDateAtTime:(NSCalendarDate *)dateTime;
[24]88{
[26]89 [self _setAlarmDate: dateTime];
[24]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{
[26]123 if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
124 return (alarmType != PSAlarmInvalid);
[24]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{
[26]145 if (invalidMessage == nil) return @"";
[24]146 return invalidMessage;
147}
148
[28]149- (NSCalendarDate *)date;
[24]150{
151 if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
152 return alarmDate;
153}
154
[28]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
[24]178- (NSTimeInterval)interval;
179{
[28]180 if (alarmType == PSAlarmSet || alarmType == PSAlarmDate) [self _setIntervalFromDate];
[24]181 return alarmInterval;
182}
183
[26]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) {
[28]195 [timer retain];
[26]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{
[28]207 [timer invalidate]; [timer release]; timer = nil;
[26]208}
209
210- (void)_timerExpired:(NSTimer *)aTimer;
211{
212 [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self];
[28]213 [timer release]; timer = nil;
[26]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
[34]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
[26]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];
[28]274 // NSLog(@"encoded: %@", self); // XXX happening twice, gdb refuses to show proper backtrace, grr
[26]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
[24]302@end
Note: See TracBrowser for help on using the repository browser.