source: trunk/Cocoa/Pester/Source/NJRHotKeyField.m @ 130

Last change on this file since 130 was 130, checked in by Nicholas Riley, 19 years ago

PSPreferencesController.[hm]: Filter hot keys. Read and write to
preferences.

NJRHotKeyField.[hm]: Added property list serialization of hot key data
(not quite like PSAlarm/Alert because we're a GUI element). Added
delegate method for hot key filtering and action triggering when hot
key set or cleared. Only use filtered modifiers to avoid bizarre
behavior. More bug fixes.

English.lproj/Preferences.nib: Connected Clear button. Connected
NJRHotKeyField delegate and target to PSPreferencesController.

NSString-NJRExtensions.[hm]: Replaced "...modifierMask" with
"...modifierFlags" because it's more appropriate.

File size: 6.0 KB
Line 
1//
2//  NJRHotKeyField.m
3//  Pester
4//
5//  Created by Nicholas Riley on Sat Mar 29 2003.
6//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "NJRHotKeyField.h"
10#import "NJRHotKeyFieldCell.h"
11#import "NSString-NJRExtensions.h"
12
13// property list keys
14static NSString * const PLCharacters = @"characters"; // NSString
15static NSString * const PLModifierFlags = @"modifierFlags"; // NSNumber
16static NSString * const PLKeyCode = @"keyCode"; // NSNumber
17
18static const NSRange zeroRange = {0, 0};
19static const unsigned int capturedModifierMask = (NSShiftKeyMask |
20                                                  NSControlKeyMask |
21                                                  NSAlternateKeyMask |
22                                                  NSCommandKeyMask);
23
24static NSParagraphStyle *leftAlignStyle = nil, *centerAlignStyle = nil;
25static NSDictionary *statusAttributes = nil;
26
27@implementation NJRHotKeyField
28
29+ (void)initialize;
30{
31    NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
32    [paraStyle setAlignment: NSLeftTextAlignment];
33    leftAlignStyle = [paraStyle copy];
34    [paraStyle setAlignment: NSCenterTextAlignment];
35    centerAlignStyle = [paraStyle copy];
36    [paraStyle release];
37
38    statusAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
39        [NSFont systemFontOfSize: [NSFont labelFontSize]], NSFontAttributeName,
40        centerAlignStyle, NSParagraphStyleAttributeName, nil];
41}
42
43- (void)_setUp;
44{
45    [self setAllowsEditingTextAttributes: YES];
46    [self setImportsGraphics: NO];
47    [self cell]->isa = [NJRHotKeyFieldCell class];
48}
49
50- (id)initWithCoder:(NSCoder *)coder;
51{
52    if ( (self = [super initWithCoder: coder]) != nil) {
53        [self _setUp];
54    }
55    return self;
56}
57
58- (id)initWithFrame:(NSRect)frameRect;
59{
60    if ( (self = [super initWithFrame: frameRect]) != nil) {
61        [self _setUp];
62    }
63    return self;
64}
65
66// XXX still problems with command-A the first time
67
68- (void)previewKeyEquivalentAttributedString:(NSAttributedString *)equivString;
69{
70    NSMutableAttributedString *previewString = [equivString mutableCopy];
71    [previewString addAttribute: NSParagraphStyleAttributeName value: leftAlignStyle range: NSMakeRange(0, [previewString length])];
72    [self setAttributedStringValue: previewString];
73    [[self currentEditor] setSelectedRange: zeroRange];
74    [previewString release];
75}
76
77- (void)showStatus:(NSString *)error;
78{
79    [self setAttributedStringValue:
80        [[NSAttributedString alloc] initWithString: [NSString stringWithFormat: @"(%@)", error]
81                                        attributes: statusAttributes]];
82    [[self currentEditor] setSelectedRange: zeroRange];
83}
84
85- (void)showKeyEquivalentAttributedStringFinalized:(BOOL)finalized;
86{
87    if (hotKeyCharacters == nil) {
88        [self showStatus: @"none assigned"];
89        return;
90    }
91    NSMutableAttributedString *equivString = [[hotKeyCharacters keyEquivalentAttributedStringWithModifierFlags: hotKeyModifierFlags] mutableCopy];
92    [equivString addAttribute: NSParagraphStyleAttributeName
93                        value: (finalized ? centerAlignStyle : leftAlignStyle)
94                        range: NSMakeRange(0, [equivString length])];
95    [self setAttributedStringValue: equivString];
96    [[self currentEditor] setSelectedRange: zeroRange];
97    [equivString release];
98}
99
100- (void)clearHotKey;
101{
102    [hotKeyCharacters release];
103    hotKeyCharacters = nil;
104    hotKeyModifierFlags = 0;
105    hotKeyCode = 0;
106    [NSApp sendAction: [self action] to: [self target] from: self];
107}
108
109- (void)keyUp:(NSEvent *)theEvent;
110{
111    NSString *characters = [theEvent charactersIgnoringModifiers];
112    int length = [characters length];
113    if (length > 1) {
114        [self showStatus: @"please press only one non-modifier key"];
115        return;
116    }
117    if (length == 1) {
118        unsigned modifierFlags = ([theEvent modifierFlags] & capturedModifierMask);
119        id delegate = [self delegate];
120        NSString *message = nil;
121        if (delegate != nil && ![delegate hotKeyField: self shouldAcceptCharacter: [characters characterAtIndex: 0] modifierFlags: modifierFlags rejectionMessage: &message]) {
122            [self showStatus: message != nil ? message : @"key is unavailable for use"];
123        } else {
124            [hotKeyCharacters release];
125            hotKeyCharacters = [characters retain];
126            hotKeyModifierFlags = modifierFlags;
127            hotKeyCode = [theEvent keyCode];
128            [NSApp sendAction: [self action] to: [self target] from: self];
129            [self showKeyEquivalentAttributedStringFinalized: ([theEvent modifierFlags] & capturedModifierMask) == 0];
130        }
131    }
132}
133
134- (BOOL)performKeyEquivalent:(NSEvent *)theEvent;
135{
136    [self keyUp: theEvent];
137    return [super performKeyEquivalent: theEvent];
138}
139
140- (void)flagsChanged:(NSEvent *)theEvent;
141{
142    unsigned modifierFlags = [theEvent modifierFlags];
143
144    if ((modifierFlags & capturedModifierMask) == 0) {
145        [self showKeyEquivalentAttributedStringFinalized: YES];
146    } else {
147        [self previewKeyEquivalentAttributedString:
148            [@"" keyEquivalentAttributedStringWithModifierFlags: modifierFlags]];
149    }
150}
151
152- (IBAction)clear:(id)sender;
153{
154    [self clearHotKey];
155    [self showKeyEquivalentAttributedStringFinalized: YES];
156}
157
158#pragma mark property list serialization (Pester 1.1)
159
160- (NSDictionary *)propertyListRepresentation;
161{
162    return [NSDictionary dictionaryWithObjectsAndKeys:
163        hotKeyCharacters, PLCharacters,
164        [NSNumber numberWithUnsignedInt: hotKeyModifierFlags], PLModifierFlags,
165        [NSNumber numberWithUnsignedShort: hotKeyCode], PLKeyCode,
166        nil];
167}
168
169- (void)setFromPropertyList:(NSDictionary *)dict;
170{
171    NS_DURING
172        hotKeyCharacters = [[dict objectForKey: PLCharacters] retain];
173        hotKeyModifierFlags = [[dict objectForKey: PLModifierFlags] unsignedIntValue];
174        hotKeyCode = [[dict objectForKey: PLKeyCode] unsignedShortValue];
175        [self showKeyEquivalentAttributedStringFinalized: ([[NSApp currentEvent] modifierFlags] & capturedModifierMask) == 0];
176    NS_HANDLER
177        [self clear: nil];
178    NS_ENDHANDLER
179}
180
181@end
Note: See TracBrowser for help on using the repository browser.