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

Last change on this file since 608 was 608, checked in by Nicholas Riley, 14 years ago

Display "today" or "tomorrow" when setting an alarm.

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