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

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

Pester 1.0

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