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

Last change on this file since 111 was 28, checked in by Nicholas Riley, 19 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.