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

Last change on this file since 364 was 364, checked in by Nicholas Riley, 13 years ago

English.lproj/Alarms.nib: Specify alternating row coloring in the nib,
now we're 10.4+.

English.lproj/InfoPlist.strings: Updated for 1.1b6.

English.lproj/Localizable.strings: Quote alarm message in pretty
description (used in tooltip). Change voice error now it no longer
incorporates OSStatus.

English.lproj/MainMenu.nib: Add speech prefs again; turn repetitions
field into a NJRValidatingField and hook up its delegate.

Info-Pester.plist: Updated for 1.1b6.

NJRHotKey.m: Switch to new Objective-C exception style.

NJRIntervalField.[hm]: Now a subclass of NJRValidatingField.

NJRTableDelegate.m: Get rid of our own tooltip support as NSTableView
now supports them (though with a minor visual glitch on the first
tooltip).

NJRTableView.[hm]: Remove tooltip support. Remove alternating row
coloring support.

NJRValidatingField.[hm]: Contains validation sheet stuff from
NJRIntervalField.

NJRVoicePopUpButton.[hm]: Switch to NSSpeechSynthesizer.

PSAlarm.m: Quote alarm message in pretty description (used in
tooltip). Fix repeating alarms not restoring as repeating if they
didn't expire while Pester was not running. No longer set timer on
Pester 1.0 alarm import, to help make importing atomic.

PSAlarmSetController.[hm]: Use NJRValidatingField for repetitions
field. Switch to new Objective-C exception style. Fix validation
issues on in/at changing. Temporary changes to restore speech support
and allow the sound popup to be removed entirely from the nib (rather
than being dragged out of the visible area, as it was in 1.1b5).
Changes for NSSpeechSynthesizer, which uses different voice names.

PSAlarms.m: Switch to new Objective-C exception style. Fix
duplication and error handling in Pester 1.0 alarm import, making
atomic.

PSAlarmsController.m: Use new tooltip support (since it's implemented
in the delegate rather than the data source, we have to proxy it).

PSAlerts.m: Wrap initialization in exception block so we don't leak.

PSApplication.m: Switch to new Objective-C exception style.

PSMediaAlert.m: Clamp repetitions at 1..99 so the user can't type an
invalid value, then quit and have it saved.

PSSpeechAlert.[hm]: Switch to NSSpeechSynthesizer. Throw an
intelligible exception if the voice is unavailable.

PSTimer.m: Switch to new Objective-C exception style.

Pester.xcodeproj: Remove VERSION generation; rename targets to be more
understandable.

Read Me.rtfd: Updated for 1.1b6.

SUSpeaker.[hm]: Gone in switch to NSSpeechSynthesizer.

VERSION: Gone - we use agvtool for everything now.

Updates/release-notes.html: Updated for 1.1b6.

Updates/updates.xml: Updated for 1.1b6.

package-Pester.sh: Use agvtool to get version. Atomically update
file on Web server to avoid partial downloads.

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