source: releases/Pester/1.1b6/Source/PSAlarm.m@ 505

Last change on this file since 505 was 364, checked in by Nicholas Riley, 17 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.