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

Last change on this file since 355 was 355, checked in by Nicholas Riley, 12 years ago

English.lproj/MainMenu.nib: Modernize menu and alarm set dialog
layout. Use keyed archiving (10.2+) nib format.

Info-Pester.plist: Moved from old PBX project.

NJRFSObjectSelector.m: Bug fixes from code sent to Joey: remove
incorrect usage of tryToPerform:with:; fix logic error in menu
construction. Work around Cocoa's deciding that the menu font size
needs adjustment when it doesn't - so the menu font size now matches
the button font size, though the position is still off. Don't pop up
a menu if we're disabled. Use IconRefs? for menu icons, though not
(yet) for the button icon.

NJRHistoryTrackingComboBox.m: Remove item height adjustment
workaround; it now makes the items too tall.

NJRHotKey.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyField.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyManager.m: Add a missing [super dealloc] caught by current
GCC.

NJRIntervalField.m: Fix some type errors.

NJRQTMediaPopUpButton.m: Replace SoundFileManager? SPI usage, which
doesn't work in Leopard anyway, with manual enumeration of system
sounds. Start migration to QTKit. Use IconRefs? for menu icons.

NJRReadMeController.m: Change source encoding to UTF-8.

NJRSoundManager.m: Fix a type error.

NJRVoicePopUpButton.m: Change source encoding to UTF-8.

NSMenuItem-NJRExtensions.[hm]: Code from ICeCoffEE to use IconRefs? for
menu item icons.

PSAlarm.m: Change source encoding to UTF-8.

PSAlarms.m: Fix a signedness mismatch.

PSAlarmsController.m: Change source encoding to UTF-8.

PSAlarmSetController.m: Set keyboard focus after unchecking "Do
script:" and "Play" checkboxes.

PSAlerts.m: Add a missing [super dealloc] caught by current GCC. Fix
a memory leak in property list serialization.

PSPowerManager.[hm]: There's now API for scheduling wakeups; use it
(the old code asserted on startup). To fix: removing scheduled
wakeup. Fix a small type-checking error.

PSPreferencesController.m: Add a missing [super dealloc] caught by
current GCC.

PSScriptAlert.m: Change source encoding to UTF-8.

PSTimeDateEditor.m: Fix a tiny, and one-time, memory leak.

PSTimer.m: Update for new PSPowerManager API.

Pester.pbproj: Deleted; now supporting OS X 10.4+ (up from 10.1,
aiee.)

Pester.xcodeproj: Xcode 2.4+ project, upgraded targets, etc.

SoundFileManager?.h: Deleted; this SPI no longer exists in Leopard and
possibly earlier.

File size: 19.2 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#import "PSAlerts.h"
12#import "PSTimer.h"
13#import "NJRDateFormatter.h"
14#import "NSCalendarDate-NJRExtensions.h"
15#import "NSDictionary-NJRExtensions.h"
16#import "NSString-NJRExtensions.h"
17
18NSString * const PSAlarmTimerSetNotification = @"PSAlarmTimerSetNotification";
19NSString * const PSAlarmTimerExpiredNotification = @"PSAlarmTimerExpiredNotification";
20NSString * const PSAlarmDiedNotification = @"PSAlarmDiedNotification";
21
22// property list keys
23static NSString * const PLAlarmType = @"type"; // NSString
24static NSString * const PLAlarmDate = @"date"; // NSNumber
25static NSString * const PLAlarmInterval = @"interval"; // NSNumber
26static NSString * const PLAlarmSnoozeInterval = @"snooze interval"; // NSNumber
27static NSString * const PLAlarmMessage = @"message"; // NSString
28static NSString * const PLAlarmAlerts = @"alerts"; // NSDictionary
29static NSString * const PLAlarmRepeating = @"repeating"; // NSNumber
30
31static NSString *dateFormat, *shortDateFormat, *timeFormat;
32static NSDictionary *locale;
33
34@implementation PSAlarm
35
36#pragma mark initialize-release
37
38+ (void)initialize; // XXX change on locale modification, subscribe to NSNotifications
39{
40    dateFormat = [[NJRDateFormatter localizedDateFormatIncludingWeekday: YES] retain];
41    shortDateFormat = [[NJRDateFormatter localizedShortDateFormatIncludingWeekday: NO] retain];
42    timeFormat = [[NJRDateFormatter localizedTimeFormatIncludingSeconds: YES] retain];
43    locale = [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] retain];
44}
45
46- (void)dealloc;
47{
48    // NSLog(@"DEALLOC %@", self);
49    alarmType = PSAlarmInvalid;
50    [alarmDate release]; alarmDate = nil;
51    [alarmMessage release]; alarmMessage = nil;
52    [invalidMessage release]; invalidMessage = nil;
53    [timer invalidate]; [timer release]; timer = nil;
54    [alerts release]; alerts = nil;
55    [super dealloc];
56}
57
58#pragma mark private
59
60- (void)_setAlarmDate:(NSCalendarDate *)aDate;
61{
62    if (alarmDate != aDate) {
63        [alarmDate release];
64        alarmDate = nil;
65        alarmDate = [aDate retain];
66    }
67}
68
69- (void)_beInvalid:(NSString *)aMessage;
70{
71    alarmType = PSAlarmInvalid;
72    if (aMessage != invalidMessage) {
73        [invalidMessage release];
74        invalidMessage = nil;
75        [self _setAlarmDate: nil];
76        alarmInterval = 0;
77        invalidMessage = [aMessage retain];
78    }
79}
80
81- (void)_beValidWithType:(PSAlarmType)type;
82{
83    if (alarmType == PSAlarmSet) return; // already valid
84    [invalidMessage release];
85    invalidMessage = nil;
86    alarmType = type;
87    if (type != PSAlarmInterval) [self setRepeating: NO];
88}
89
90- (void)_setDateFromInterval;
91{
92    [self _setAlarmDate: [NSCalendarDate dateWithTimeIntervalSinceNow: alarmInterval]];
93    [self _beValidWithType: PSAlarmInterval];
94}
95
96- (void)_setIntervalFromDate;
97{
98    alarmInterval = [alarmDate timeIntervalSinceNow];
99    if (alarmInterval <= 0) {
100        [self _beInvalid: @"Please specify an alarm time in the future."];
101        return;
102    }
103    [self _beValidWithType: PSAlarmDate];
104}
105
106- (PSAlarmType)_alarmTypeForString:(NSString *)string;
107{
108    if ([string isEqualToString: @"PSAlarmDate"]) return PSAlarmDate;
109    if ([string isEqualToString: @"PSAlarmInterval"]) return PSAlarmInterval;
110    if ([string isEqualToString: @"PSAlarmSet"]) return PSAlarmSet;
111    if ([string isEqualToString: @"PSAlarmInvalid"]) return PSAlarmInvalid;
112    if ([string isEqualToString: @"PSAlarmSnooze"]) return PSAlarmSnooze;
113    if ([string isEqualToString: @"PSAlarmExpired"]) return PSAlarmExpired;
114    NSLog(@"unknown alarm type string: %@", string);
115    return nil;
116}
117
118- (NSString *)_alarmTypeString;
119{
120    switch (alarmType) {
121        case PSAlarmDate: return @"PSAlarmDate";
122        case PSAlarmInterval: return @"PSAlarmInterval";
123        case PSAlarmSet: return @"PSAlarmSet";
124        case PSAlarmInvalid: return @"PSAlarmInvalid";
125        case PSAlarmSnooze: return @"PSAlarmSnooze";
126        case PSAlarmExpired: return @"PSAlarmExpired";
127        default: return [NSString stringWithFormat: @"<unknown: %u>", alarmType];
128    }
129}
130
131- (NSString *)_stringForInterval:(unsigned long long)interval;
132{
133    const unsigned long long minute = 60, hour = minute * 60, day = hour * 24, year = day * 365.26;
134    // +[NSString stringWithFormat:] in 10.1 does not support long longs: work around it by converting to unsigned ints or longs for display
135    if (interval == 0) return nil;
136    if (interval < minute) return [NSString stringWithFormat: @"%us", (unsigned)interval];
137    if (interval < hour) return [NSString stringWithFormat: @"%um", (unsigned)(interval / minute)];
138    if (interval < day) return [NSString stringWithFormat: @"%uh %um", (unsigned)(interval / hour), (unsigned)((interval % hour) / minute)];
139    if (interval < 2 * day) return @"One day";
140    if (interval < year) return [NSString stringWithFormat: @"%u days", (unsigned)(interval / day)];
141    if (interval < 2 * year) return @"One year";
142    return [NSString stringWithFormat: @"%lu years", (unsigned long)(interval / year)];
143}
144
145- (void)_timerExpired:(PSTimer *)aTimer;
146{
147    NSLog(@"expired: %@; now %@", [[aTimer fireDate] description], [[NSDate date] description]);
148    alarmType = PSAlarmExpired;
149    [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerExpiredNotification object: self];
150    [timer release]; timer = nil;
151}
152
153#pragma mark alarm setting
154
155- (void)setInterval:(NSTimeInterval)anInterval;
156{
157    alarmInterval = anInterval;
158    if (alarmInterval <= 0) {
159        [self _beInvalid: @"Please specify an alarm interval."]; return;
160    }
161    [self _setDateFromInterval];
162}
163
164- (void)setForDateAtTime:(NSCalendarDate *)dateTime;
165{
166    [self _setAlarmDate: dateTime];
167    [self _setIntervalFromDate];
168}
169
170- (void)setForDate:(NSDate *)date atTime:(NSDate *)time;
171{
172    NSCalendarDate *dateTime;
173    if (time == nil && date == nil) {
174        [self _beInvalid: @"Please specify an alarm date and time."]; return;
175    }
176    if (time == nil) {
177        [self _beInvalid: @"Please specify an alarm time."]; return;
178    }
179    if (date == nil) {
180        [self _beInvalid: @"Please specify an alarm date."]; return;
181    }
182    // XXX if calTime's date is different from the default date, complain
183    dateTime = [NSCalendarDate dateWithDate: date atTime: time];
184    if (dateTime == nil) {
185        [self _beInvalid: @"Please specify a reasonable date and time."]; return;
186    }
187    [self setForDateAtTime: dateTime];
188}
189
190- (void)setRepeating:(BOOL)isRepeating;
191{
192    repeating = isRepeating;
193}
194
195- (void)setSnoozeInterval:(NSTimeInterval)anInterval;
196{
197    snoozeInterval = anInterval;
198    NSAssert(alarmType == PSAlarmExpired, NSLocalizedString(@"Can't snooze an alarm that hasn't expired", "Assertion for PSAlarm snooze setting"));
199    alarmType = PSAlarmSnooze;
200}
201
202- (void)setWakeUp:(BOOL)doWake;
203{
204    [timer setWakeUp: doWake];
205}
206
207#pragma mark accessing
208
209- (NSString *)message;
210{
211    if (alarmMessage == nil || [alarmMessage isEqualToString: @""])
212        return @"Alarm!";
213    return alarmMessage;
214}
215
216- (void)setMessage:(NSString *)aMessage;
217{
218    if (aMessage != alarmMessage) {
219        [alarmMessage release];
220        alarmMessage = nil;
221        alarmMessage = [aMessage retain];
222    }
223}
224
225- (BOOL)isValid;
226{
227    if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
228    if (alarmType == PSAlarmInvalid ||
229        (alarmType == PSAlarmExpired && ![self isRepeating])) return NO;
230    return YES;
231}
232
233- (NSString *)invalidMessage;
234{
235    if (invalidMessage == nil) return @"";
236    return invalidMessage;
237}
238
239- (NSCalendarDate *)date;
240{
241    if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
242    return alarmDate;
243}
244
245- (NSCalendarDate *)time;
246{
247    if (alarmType == PSAlarmInterval) [self _setDateFromInterval];
248    return [[NSCalendarDate alloc] initWithYear: 0
249                                          month: 1
250                                            day: 1
251                                           hour: [alarmDate hourOfDay]
252                                         minute: [alarmDate minuteOfHour]
253                                         second: [alarmDate secondOfMinute]
254                                       timeZone: nil];
255}
256
257- (NSTimeInterval)interval;
258{
259    if (alarmType == PSAlarmDate) [self _setIntervalFromDate];
260    return alarmInterval;
261}
262
263- (NSTimeInterval)snoozeInterval;
264{
265    return snoozeInterval;
266}
267
268- (NSTimeInterval)timeRemaining;
269{
270    NSAssert1(alarmType == PSAlarmSet, NSLocalizedString(@"Can't get time remaining on alarm with no timer set: %@", "Assertion for PSAlarm time remaining, internal error; %@ replaced by alarm description"), self);
271    return -[[NSDate date] timeIntervalSinceDate: alarmDate];
272}
273
274- (void)setAlerts:(PSAlerts *)theAlerts;
275{
276    [alerts release]; alerts = nil;
277    alerts = [theAlerts retain];
278}
279
280- (PSAlerts *)alerts;
281{
282    if (alerts == nil) alerts = [[PSAlerts alloc] init];
283    return alerts;
284}
285
286- (BOOL)isRepeating;
287{
288    return repeating;
289}
290
291- (NSString *)dateString;
292{
293    return [[self date] descriptionWithCalendarFormat: dateFormat locale: locale];
294}
295
296- (NSString *)shortDateString;
297{
298    return [[self date] descriptionWithCalendarFormat: shortDateFormat locale: locale];
299}
300
301- (NSString *)timeString;
302{
303    return [[self date] descriptionWithCalendarFormat: timeFormat locale: locale];
304}
305
306- (NSString *)dateTimeString;
307{
308    return [NSString stringWithFormat: @"%@ at %@", [self dateString], [self timeString]];
309}
310
311- (NSString *)nextDateTimeString;
312{
313    if (![self isRepeating]) {
314        return nil;
315    } else {
316        NSCalendarDate *date = [[NSCalendarDate alloc] initWithTimeIntervalSinceNow: [self interval]];
317        NSString *nextDateTimeString = [NSString stringWithFormat: @"%@ at %@",
318            [date descriptionWithCalendarFormat: dateFormat locale: locale],
319            [date descriptionWithCalendarFormat: timeFormat locale: locale]];
320        [date release];
321        return nextDateTimeString;
322    }
323}
324
325- (NSString *)intervalString;
326{
327    const unsigned long long mval = 99, minute = 60, hour = minute * 60;
328    unsigned long long interval = [self interval];
329    if (interval == 0) return nil;
330    if (interval == 1) return @"One second";
331    if (interval == minute) return @"One minute";
332    if (interval % minute == 0) return [NSString stringWithFormat: @"%u minutes", (unsigned)(interval / minute)];
333    if (interval <= mval) return [NSString stringWithFormat: @"%u seconds", (unsigned)interval];
334    if (interval == hour) return @"One hour";
335    if (interval % hour == 0) return [NSString stringWithFormat: @"%u hours", (unsigned)(interval / hour)];
336    if (interval <= mval * minute) return [NSString stringWithFormat: @"%u minutes", (unsigned)(interval / minute)];
337    if (interval <= mval * hour) return [NSString stringWithFormat: @"%u hours", (unsigned)(interval / hour)];
338    return [self _stringForInterval: interval];
339}
340
341- (NSString *)timeRemainingString;
342{
343    NSString *timeRemainingString = [self _stringForInterval: llround([self timeRemaining])];
344   
345    if (timeRemainingString == nil) return @"«expired»";
346    return timeRemainingString;
347}
348
349- (NSAttributedString *)prettyDescription;
350{
351    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
352    NSAttributedString *alertList = [alerts prettyList];
353
354    [string appendAttributedString:
355        [[NSString stringWithFormat: NSLocalizedString(@"At alarm time for %@:\n", "Alert list title in pretty description, %@ replaced with message"), [self message]] small]];
356    if (alertList != nil) {
357        [string appendAttributedString: alertList];
358    } else {
359        [string appendAttributedString: [@"Do nothing." small]];
360    }
361    if ([self isRepeating]) {
362        [string appendAttributedString:
363            [[NSString stringWithFormat: @"\nAlarm repeats every %@.", [[self intervalString] lowercaseString]] small]];
364    }
365    return [string autorelease];
366}
367
368#pragma mark actions
369
370- (BOOL)setTimer;
371{
372    if (alarmType == PSAlarmExpired) {
373        if ([self isRepeating]) {
374            [self _setDateFromInterval];
375        } else {
376            [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmDiedNotification object: self];
377            return NO;
378        }
379    } else if (alarmType == PSAlarmDate) {
380        if (![self isValid]) return NO;
381    } else if (alarmType == PSAlarmSnooze) {
382        [self _setAlarmDate: [NSCalendarDate dateWithTimeIntervalSinceNow: snoozeInterval]];
383    } else if (alarmType != PSAlarmInterval) {
384        return NO;
385    }
386    timer = [PSTimer scheduledTimerWithTimeInterval: (alarmType == PSAlarmSnooze ? snoozeInterval : alarmInterval) target: self selector: @selector(_timerExpired:) userInfo: nil repeats: NO];
387    if (timer == nil) return NO;
388    [timer retain];
389    alarmType = PSAlarmSet;
390    [alerts prepareForAlarm: self];
391
392    [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmTimerSetNotification object: self];
393    // NSLog(@"set: %@; now %@; remaining %@", [[timer fireDate] description], [[NSDate date] description], [self timeRemainingString]);
394    return YES;
395}
396
397- (void)cancelTimer;
398{
399    [timer invalidate]; [timer release]; timer = nil;
400}
401
402- (void)resetTimer;
403{
404    if (timer != nil || alarmType != PSAlarmSet)
405        return;
406
407    alarmType = PSAlarmDate;
408    if (![self isRepeating]) {
409        [self setTimer];
410    } else {
411        // don't want to put this logic in setTimer or isValid because it can cause invalid alarms to be set (consider when someone clicks the "repeat" checkbox, then switches to a [nonrepeating, by design] date alarm, and enters a date that has passed: we do -not- want the alarm to magically morph into a repeating interval alarm)
412        NSTimeInterval savedInterval = alarmInterval;
413        if (![self setTimer]) {
414            alarmType = PSAlarmInterval;
415            [self setInterval: savedInterval];
416            [self setTimer];
417        }
418    }
419}
420
421#pragma mark comparing
422
423- (NSComparisonResult)compareDate:(PSAlarm *)otherAlarm;
424{
425    return [[self date] compare: [otherAlarm date]];
426}
427
428- (NSComparisonResult)compareMessage:(PSAlarm *)otherAlarm;
429{
430    return [[self message] caseInsensitiveCompare: [otherAlarm message]];
431}
432
433#pragma mark printing
434
435- (NSString *)description;
436{
437    return [NSString stringWithFormat: @"%@: type %@ date %@ interval %.1f%@%@",
438        [super description], [self _alarmTypeString], alarmDate, alarmInterval,
439        (repeating ? @" repeating" : @""),
440        (alarmType == PSAlarmInvalid ?
441         [NSString stringWithFormat: @"\ninvalid message: %@", invalidMessage]
442        : (alarmType == PSAlarmSet ?
443           [NSString stringWithFormat: @"\ntimer: %@", timer] : @""))];
444}
445
446#pragma mark property list serialization (Pester 1.1)
447
448- (NSDictionary *)propertyListRepresentation;
449{
450    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 5];
451    if (![self isValid]) return nil;
452    [dict setObject: [self _alarmTypeString] forKey: PLAlarmType];
453    switch (alarmType) {
454        case PSAlarmDate:
455        case PSAlarmSet:
456            [dict setObject: [NSNumber numberWithDouble: [alarmDate timeIntervalSinceReferenceDate]] forKey: PLAlarmDate];
457        case PSAlarmSnooze:
458        case PSAlarmInterval:
459        case PSAlarmExpired:
460            break;
461        default:
462            NSAssert1(NO, NSLocalizedString(@"Can't save alarm type %@", "Assertion for invalid PSAlarm type on string; %@ replaced with alarm type string"), [self _alarmTypeString]);
463            break;
464    }
465    if ((alarmType != PSAlarmSet || repeating) && alarmType != PSAlarmDate) {
466        [dict setObject: [NSNumber numberWithBool: repeating] forKey: PLAlarmRepeating];
467        [dict setObject: [NSNumber numberWithDouble: alarmInterval] forKey: PLAlarmInterval];
468    }
469    if (snoozeInterval != 0)
470        [dict setObject: [NSNumber numberWithDouble: snoozeInterval] forKey: PLAlarmSnoozeInterval];
471    [dict setObject: alarmMessage forKey: PLAlarmMessage];
472    if (alerts != nil) {
473        [dict setObject: [alerts propertyListRepresentation] forKey: PLAlarmAlerts];
474    }
475    return dict;
476}
477
478- (id)initWithPropertyList:(NSDictionary *)dict;
479{
480    if ( (self = [self init]) != nil) {
481        PSAlerts *alarmAlerts;
482        alarmType = [self _alarmTypeForString: [dict objectForRequiredKey: PLAlarmType]];
483        switch (alarmType) {
484            case PSAlarmDate:
485            case PSAlarmSet:
486               { NSCalendarDate *date = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate: [[dict objectForRequiredKey: PLAlarmDate] doubleValue]];
487                [self _setAlarmDate: date];
488                [date release];
489               }
490                break;
491            case PSAlarmSnooze: // snooze interval set but not confirmed; ignore
492                alarmType = PSAlarmExpired;
493            case PSAlarmInterval:
494            case PSAlarmExpired:
495                break;
496            default:
497                NSAssert1(NO, NSLocalizedString(@"Can't load alarm type %@", "Assertion for invalid PSAlarm type on load; %@ replaced with alarm type string"), [self _alarmTypeString]);
498                break;
499        }
500        repeating = [[dict objectForKey: PLAlarmRepeating] boolValue];
501        if ((alarmType != PSAlarmSet || repeating) && alarmType != PSAlarmDate)
502            alarmInterval = [[dict objectForRequiredKey: PLAlarmInterval] doubleValue];
503        snoozeInterval = [[dict objectForKey: PLAlarmSnoozeInterval] doubleValue];
504        [self setMessage: [dict objectForRequiredKey: PLAlarmMessage]];
505        alarmAlerts = [[PSAlerts alloc] initWithPropertyList: [dict objectForRequiredKey: PLAlarmAlerts]];
506        [self setAlerts: alarmAlerts];
507        [alarmAlerts release];
508        [self resetTimer];
509        if (alarmType == PSAlarmExpired) {
510            [self setTimer];
511            if (alarmType == PSAlarmExpired) { // failed to restart
512                [self release];
513                self = nil;
514            }
515        }
516    }
517    return self;
518}
519
520#pragma mark archiving (Pester 1.0)
521
522- (void)encodeWithCoder:(NSCoder *)coder;
523{
524    if (![self isValid]) return;
525    [coder encodeValueOfObjCType: @encode(PSAlarmType) at: &alarmType];
526    switch (alarmType) {
527        case PSAlarmDate:
528        case PSAlarmSet:
529            [coder encodeObject: alarmDate];
530            break;
531        case PSAlarmInterval:
532            [coder encodeValueOfObjCType: @encode(NSTimeInterval) at: &alarmInterval];
533            break;
534        default:
535            break;
536    }
537    [coder encodeObject: alarmMessage];
538    // NSLog(@"encoded: %@", self); // XXX happening twice, gdb refuses to show proper backtrace, grr
539    return;
540}
541
542- (id)initWithCoder:(NSCoder *)coder;
543{
544    if ( (self = [self init]) != nil) {
545        PSAlerts *legacyAlerts = [[PSAlerts alloc] initWithPesterVersion1Alerts];
546        [self setAlerts: legacyAlerts];
547        [legacyAlerts release];
548        [coder decodeValueOfObjCType: @encode(PSAlarmType) at: &alarmType];
549        switch (alarmType) {
550            case PSAlarmDate:
551            case PSAlarmSet:
552                [self _setAlarmDate: [coder decodeObject]];
553                break;
554            case PSAlarmInterval:
555                [coder decodeValueOfObjCType: @encode(NSTimeInterval) at: &alarmInterval];
556                break;
557            default:
558                break;
559        }
560        [self setMessage: [coder decodeObject]];
561        if (alarmType == PSAlarmSet) {
562            alarmType = PSAlarmDate;
563            [self setTimer];
564        }
565    }
566    return self;
567}
568
569@end
Note: See TracBrowser for help on using the repository browser.