source: trunk/Cocoa/Pester/Source/PSAlarmsController.m @ 516

Last change on this file since 516 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: 5.8 KB
Line 
1//
2//  PSAlarmsController.m
3//  Pester
4//
5//  Created by Nicholas Riley on Fri Oct 11 2002.
6//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "PSAlarmsController.h"
10#import "PSAlarm.h"
11#import "PSAlerts.h"
12#import "NSString-NJRExtensions.h"
13#import "NSTableView-NJRExtensions.h"
14#import "NJRTableView.h"
15#import "NJRTableDelegate.h"
16
17@interface PSAlarmsController (PrivateUndoSupport)
18
19- (void)_restoreAlarms:(NSSet *)selectedAlarms;
20- (void)_removeAlarms:(NSSet *)selectedAlarms;
21
22@end
23
24@implementation PSAlarmsController
25
26- (void)alarmsChanged;
27{
28    reorderedAlarms = [[alarmList delegate] reorderedDataForData: [alarms alarms]];
29}
30
31- (id)init;
32{
33    if ( (self = [super initWithWindowNibName: @"Alarms"]) != nil) {
34        alarms = [PSAlarms allAlarms];
35        // XXX workaround for bug in 10.2.1, 10.1.5: autosave name set in IB doesn't show up
36        [self setWindowFrameAutosaveName: @"Pester alarm list"];
37        // Apple documents the NSUserDefaults key, so we can rely on it hopefully.
38        if (nil == [[NSUserDefaults standardUserDefaults] objectForKey:
39            [@"NSWindow Frame " stringByAppendingString: [[self window] frameAutosaveName]]])
40           {
41            [[self window] center];
42           }
43        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(alarmsChanged) name: PSAlarmsDidChangeNotification object: alarms];
44        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(tableViewSelectionDidChange:) name: NSTableViewSelectionDidChangeNotification object: alarmList];
45        messageAttributes = [[NSDictionary alloc] initWithObjectsAndKeys: [[[alarmList tableColumnWithIdentifier: @"message"] dataCell] font], NSFontAttributeName, nil];
46        [alarmList setAutosaveName: @"Alarm list"];
47        [alarmList setAutosaveTableColumns: YES];
48        [self alarmsChanged];
49        [[self window] makeFirstResponder: alarmList];
50        [[self window] setResizeIncrements: NSMakeSize(1, [alarmList cellHeight])];
51    }
52    return self;
53}
54
55- (void)dealloc;
56{
57    [reorderedAlarms release];
58    [messageAttributes release];
59    [super dealloc];
60}
61
62- (NSUndoManager *)undoManager;
63{
64    return [[self window] undoManager];
65}
66
67- (void)_restoreAlarms:(NSSet *)selectedAlarms;
68{
69    [alarms restoreAlarms: selectedAlarms];
70    [[alarmList delegate] selectItems: selectedAlarms];
71    [[self undoManager] setActionName: NSLocalizedString(@"Alarm Removal", "Undo action")];
72    [[[self undoManager] prepareWithInvocationTarget: self] _removeAlarms: selectedAlarms];
73}
74
75- (void)_removeAlarms:(NSSet *)selectedAlarms;
76{
77    [alarms removeAlarms: selectedAlarms];
78    [[self undoManager] setActionName: NSLocalizedString(@"Alarm Removal", "Undo action")];
79    [[[self undoManager] prepareWithInvocationTarget: self] _restoreAlarms: selectedAlarms];
80}
81
82- (IBAction)remove:(id)sender;
83{
84    [self _removeAlarms: [[alarmList delegate] selectedItems]];
85}
86
87@end
88
89@implementation PSAlarmsController (NSTableDataSource)
90
91- (int)numberOfRowsInTableView:(NSTableView *)tableView;
92{
93    return [alarms alarmCount];
94}
95
96- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
97{
98    PSAlarm *alarm = [reorderedAlarms objectAtIndex: row];
99
100    if ([[tableColumn identifier] isEqualToString: @"message"]) {
101        NSMutableString *message = [[alarm message] mutableCopy];
102        [message truncateToWidth: [tableView frameOfCellAtColumn: 0 row: row].size.width by: NSLineBreakByTruncatingTail withAttributes: messageAttributes];
103        return [message autorelease];
104    } else {
105        NSCalendarDate *date = [alarm date];
106        if ([[tableColumn identifier] isEqualToString: @"date"]) return [alarm shortDateString];
107        if ([[tableColumn identifier] isEqualToString: @"time"]) {
108            if (date == nil) return @"«expired»";
109            return [alarm timeString];
110        }
111    }
112    return nil;
113}
114@end
115
116@implementation PSAlarmsController (NJRTableViewDataSource)
117
118- (void)removeSelectedRowsFromTableView:(NSTableView *)aTableView;
119{
120    [self remove: aTableView];
121}
122
123- (NSString *)toolTipForRow:(int)rowIndex;
124{
125    PSAlarm *alarm = [reorderedAlarms objectAtIndex: rowIndex];
126   
127    return [[alarm prettyDescription] string];
128}
129
130@end
131
132@implementation PSAlarmsController (NSTableViewNotifications)
133
134- (void)tableViewSelectionDidChange:(NSNotification *)aNotification;
135{
136    [removeButton setEnabled: ([alarmList numberOfSelectedRows] != 0)];
137}
138
139@end
140
141@implementation PSAlarmsController (NSWindowDelegate)
142
143// XXX workaround for bug in 10.1.5, 10.2.1 (and earlier?): no autosave on window move
144- (void)windowDidMove:(NSNotification *)aNotification
145{
146    NSString *autosaveName = [[self window] frameAutosaveName];
147    // on initial display, we get a notification inside -[NSWindow setFrameAutosaveName]!
148    if (autosaveName != nil) {
149        [[self window] saveFrameUsingName: autosaveName];
150    }
151}
152
153- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame;
154{
155    NSWindow *window = [alarmList window];
156    NSRect frame = [window frame];
157    NSScrollView *scrollView = [alarmList enclosingScrollView];
158    float displayedHeight = [[scrollView contentView] bounds].size.height;
159    float heightChange = [[scrollView documentView] bounds].size.height - displayedHeight;
160    float heightExcess;
161
162    if (heightChange >= 0 && heightChange <= 1) {
163        // either the window is already optimal size, or it's too big
164        float rowHeight = [alarmList cellHeight];
165        heightChange = (rowHeight * [alarmList numberOfRows]) - displayedHeight;
166    }
167
168    frame.size.height += heightChange;
169
170    if ( (heightExcess = [window minSize].height - frame.size.height) > 1 ||
171         (heightExcess = [window maxSize].height - frame.size.height) < 1) {
172        heightChange += heightExcess;
173        frame.size.height += heightExcess;
174    }
175
176    frame.origin.y -= heightChange;
177
178    return frame;
179}
180
181@end
Note: See TracBrowser for help on using the repository browser.