source: trunk/Cocoa/Pester/Source/NJRFSObjectSelector.m@ 43

Last change on this file since 43 was 43, checked in by Nicholas Riley, 21 years ago

Pester 1.1a1.

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

English.lproj/MainMenu.nib: Placeholder for day names in popup menu, fixed up by code (this means you can still edit it from IB though). Added command-shift-T to both in/at cells (required, code removes one or the other as appropriate). Fixed up sizes of fields. Default to today (this will need fixing when we localized the word "today", but it's fine for now...).

English.lproj/Notifier.nib: Remove date formatter because we set a string directly now instead (could set formatter from code, but we don't).

NJRDateFormatter: many workarounds for Cocoa bugs: missing AM/PM, incorrect results with space before AM/PM, etc. Added class methods to do format manipulation and return localized formats which work for output (though not always for input; this class has an internal workaround for the AM/PM problem).

NJRFSObjectSelector: properly handle enabled attribute, store internally and report externally as appropriate. Previously, the button would become enabled if you dropped something on it even if it was supposed to be disabled.

NJRQTMediaPopUpButton: stop sound preview when button disabled.

NJRVoicePopUpButton: stop voice preview when button disabled.

PSAlarm: new method -dateString returns long date string. Maintain local copy of long date, short date and time formats, and locale, using NJRDateFormatter.

PSAlarmNotifierController: update to use -[PSAlarm dateString], -[PSAlarm timeString] for localization instead of using broken formatter.

PSAlarmSetController: update documentation for some more Cocoa bugs I need to file. Set time of day and date formatters with localized date formats from NJRDateFormatter (retain/release issue here?) Localize weekday popup for predefined dates. Localize static date display with NJRDateFormatter. Note a solution (thanks to Douglas Davidson) for figuring out which control is editing. Added command-shift-T key equivalent to toggle in/at. Properly work around bugs witih soundRepetitionCount flashing, except where it's impossible to do anything else.

Read Me.rtfd: Updated for 1.1a1.

VERSION: Updated for 1.1a1.

File size: 9.0 KB
Line 
1#import "NJRFSObjectSelector.h"
2#import "NSImage-NJRExtensions.h"
3#include <Carbon/Carbon.h>
4
5@implementation NJRFSObjectSelector
6
7- (void)_initSelector;
8{
9 canChooseFiles = YES; canChooseDirectories = NO;
10 [self setAlias: nil];
11 [[self cell] setHighlightsBy: NSChangeBackgroundCell];
12 [[self cell] setGradientType: NSGradientNone];
13 [self registerForDraggedTypes:
14 [NSArray arrayWithObjects: NSFilenamesPboardType, NSURLPboardType, nil]];
15}
16
17- (void)dealloc;
18{
19 [selectedAlias release];
20 [fileTypes release];
21 [super dealloc];
22}
23
24- (id)initWithCoder:(NSCoder *)coder;
25{
26 if ( (self = [super initWithCoder: coder]) != nil) {
27 [self _initSelector];
28 }
29 return self;
30}
31
32- (id)initWithFrame:(NSRect)frame;
33{
34 if ( (self = [super initWithFrame: frame]) != nil) {
35 [self _initSelector];
36 }
37 return self;
38}
39
40- (void)drawRect:(NSRect)rect;
41{
42 NSRect boundsRect = [self bounds];
43 [super drawRect: rect];
44 if (dragAccepted) {
45 [[NSColor selectedControlColor] set];
46 [NSBezierPath setDefaultLineWidth: 2];
47 [NSBezierPath strokeRect: NSInsetRect(boundsRect, 2, 2)];
48 } else if (selectedAlias != nil && [self isEnabled]) {
49 static NSImage *popupTriangle = nil;
50 static NSSize imageSize;
51 if (popupTriangle == nil) {
52 popupTriangle = [[NSImage imageNamed: @"Popup triangle"] retain];
53 imageSize = [popupTriangle size];
54 }
55 // equivalent to popup triangle location for large bezel in Carbon
56 [popupTriangle compositeToPoint: NSMakePoint(NSMaxX(boundsRect) - imageSize.width - 5, NSMaxY(boundsRect) - 5) operation: NSCompositeSourceOver];
57 }
58}
59
60- (BOOL)acceptsPath:(NSString *)path;
61{
62 NSFileManager *fm = [NSFileManager defaultManager];
63 BOOL isDir;
64
65 if (![fm fileExistsAtPath: path isDirectory: &isDir]) return NO;
66
67 if (isDir) return canChooseDirectories;
68 if (canChooseFiles) {
69 NSEnumerator *e = [fileTypes objectEnumerator];
70 NSString *extension = [path pathExtension];
71 NSString *hfsType = NSHFSTypeOfFile(path);
72 NSString *fileType;
73
74 while ( (fileType = [e nextObject]) != nil) {
75 if ([fileType isEqualToString: extension] || [fileType isEqualToString: hfsType])
76 return YES;
77 }
78 }
79 return NO;
80}
81
82- (void)setImage:(NSImage *)image;
83{
84 [super setImage: [image bestFitImageForSize: [[self cell] cellSize]]];
85}
86
87- (IBAction)select:(id)sender;
88{
89 NSOpenPanel *openPanel = [NSOpenPanel openPanel];
90 NSString *path = [selectedAlias fullPath];
91 [openPanel setAllowsMultipleSelection: NO];
92 [openPanel setCanChooseDirectories: canChooseDirectories];
93 [openPanel setCanChooseFiles: canChooseFiles];
94 [openPanel beginSheetForDirectory: [path stringByDeletingLastPathComponent]
95 file: [path lastPathComponent]
96 types: fileTypes
97 modalForWindow: [self window]
98 modalDelegate: self
99 didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:)
100 contextInfo: nil];
101}
102
103- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
104{
105 [sheet close];
106
107 if (returnCode == NSOKButton) {
108 NSArray *files = [sheet filenames];
109 NSAssert1([files count] == 1, @"%d items returned, only one expected", [files count]);
110 [self setPath: [files objectAtIndex: 0]];
111 [[self target] tryToPerform: [self action] with: self];
112 }
113}
114
115- (void)revealInFinder:(id<NSMenuItem>)sender;
116{
117 NSString *path = [sender representedObject];
118 if (path == nil) return;
119 [[NSWorkspace sharedWorkspace] selectFile: path inFileViewerRootedAtPath: @""];
120}
121
122- (void)setAlias:(BDAlias *)alias;
123{
124 if (selectedAlias != alias) {
125 [selectedAlias release];
126 selectedAlias = [alias retain];
127 }
128
129 if (alias != nil) { // alias is set
130 NSString *path = [alias fullPath];
131 NSString *revealPath = nil;
132 NSString *targetName = [path lastPathComponent];
133 NSMenu *menu = [[NSMenu alloc] initWithTitle: @""];
134 NSFileManager *fmgr = [NSFileManager defaultManager];
135 NSMenuItem *item;
136 if (path != nil) { // can resolve alias
137 [self setImage: [[NSWorkspace sharedWorkspace] iconForFile: path]];
138 [self setTitle: targetName];
139 do {
140 item = [menu addItemWithTitle: [fmgr displayNameAtPath: path]
141 action: @selector(revealInFinder:)
142 keyEquivalent: @""];
143 [item setTarget: self];
144 [item setRepresentedObject: revealPath];
145 [item setImage:
146 [[[NSWorkspace sharedWorkspace] iconForFile: path] bestFitImageForSize: NSMakeSize(16, 16)]];
147 revealPath = path;
148 path = [path stringByDeletingLastPathComponent];
149 NSAssert1(![path isEqualToString: revealPath], @"Stuck on path |%@|", [alias fullPath]);
150 } while (![revealPath isEqualToString: @"/"] && ![path isEqualToString: @"/Volumes"]);
151 [[self cell] setMenu: menu];
152 } else {
153 [self setImage: nil];
154 [self setTitle: @"(not available)"];
155 [[self cell] setMenu: nil];
156 }
157 } else {
158 [self setImage: nil];
159 [self setTitle: @"(none selected)"];
160 [[self cell] setMenu: nil];
161 }
162 [self setEnabled: isEnabled];
163}
164
165- (BOOL)isEnabled;
166{
167 return isEnabled;
168}
169
170- (void)setEnabled:(BOOL)enabled;
171{
172 isEnabled = enabled;
173 [super setEnabled: enabled ? selectedAlias != nil : NO];
174}
175
176- (void)rightMouseDown:(NSEvent *)theEvent;
177{
178 [self mouseDown: theEvent];
179}
180
181- (void)otherMouseDown:(NSEvent *)theEvent;
182{
183 [self mouseDown: theEvent];
184}
185
186extern MenuRef _NSGetCarbonMenu(NSMenu *menu);
187
188- (void)mouseDown:(NSEvent *)theEvent;
189{
190 NSMenu *menu = [[self cell] menu];
191 MenuRef mRef = _NSGetCarbonMenu(menu);
192
193 if (mRef == NULL) {
194 NSMenu *appMenu = [[[NSApp mainMenu] itemWithTitle: @""] submenu];
195 if (appMenu != nil) {
196 NSMenuItem *item = [appMenu addItemWithTitle: @"" action: NULL keyEquivalent: @""];
197 [appMenu setSubmenu: menu forItem: item];
198 [appMenu removeItem: item];
199 }
200 mRef = _NSGetCarbonMenu(menu);
201 }
202
203 ChangeMenuAttributes(mRef, kMenuAttrExcludesMarkColumn, 0);
204 theEvent = [NSEvent mouseEventWithType: [theEvent type]
205 location: [self convertPoint: NSMakePoint(-1, 1) toView: nil]
206 modifierFlags: [theEvent modifierFlags]
207 timestamp: [theEvent timestamp]
208 windowNumber: [theEvent windowNumber]
209 context: [theEvent context]
210 eventNumber: [theEvent eventNumber]
211 clickCount: [theEvent clickCount]
212 pressure: [theEvent pressure]];
213
214 // this undocumented API does not work any better; contextual menu items are still added:
215 // [menu _popUpMenuWithEvent: theEvent forView: self];
216 [NSMenu popUpContextMenu: menu withEvent: theEvent forView: self];
217}
218
219- (BDAlias *)alias;
220{
221 return selectedAlias;
222}
223
224- (void)setPath:(NSString *)path;
225{
226 [self setAlias: [BDAlias aliasWithPath: path]];
227}
228
229- (BOOL)canChooseDirectories;
230{
231 return canChooseDirectories;
232}
233
234- (BOOL)canChooseFiles;
235{
236 return canChooseFiles;
237}
238
239- (void)setCanChooseDirectories:(BOOL)flag;
240{
241 canChooseDirectories = flag;
242}
243
244- (void)setCanChooseFiles:(BOOL)flag;
245{
246 canChooseFiles = flag;
247}
248
249- (NSArray *)fileTypes;
250{
251 return fileTypes;
252}
253
254- (void)setFileTypes:(NSArray *)types;
255{
256 if (fileTypes == types) return;
257
258 [fileTypes release];
259 fileTypes = [types retain];
260}
261
262@end
263
264
265@implementation NJRFSObjectSelector (NSDraggingDestination)
266
267- (BOOL)acceptsDragFrom:(id <NSDraggingInfo>)sender;
268{
269 NSURL *url = [NSURL URLFromPasteboard: [sender draggingPasteboard]];
270
271 if (url == nil || ![url isFileURL]) return NO;
272 return [self acceptsPath: [url path]];
273}
274
275- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
276{
277 if ([self acceptsDragFrom: sender] && [sender draggingSourceOperationMask] &
278 (NSDragOperationCopy | NSDragOperationLink)) {
279 dragAccepted = YES;
280 [self setNeedsDisplay: YES];
281 return NSDragOperationLink;
282 }
283 return NSDragOperationNone;
284}
285
286- (void)draggingExited:(id <NSDraggingInfo>)sender;
287{
288 dragAccepted = NO;
289 [self setNeedsDisplay: YES];
290}
291
292- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
293{
294 dragAccepted = NO;
295 [self setNeedsDisplay: YES];
296 return [self acceptsDragFrom: sender];
297}
298
299- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
300{
301 if ([sender draggingSource] != self) {
302 NSURL *url = [NSURL URLFromPasteboard: [sender draggingPasteboard]];
303 if (url == nil) return NO;
304 [self setPath: [url path]];
305 [[self target] tryToPerform: [self action] with: self];
306 }
307 return YES;
308}
309
310@end
Note: See TracBrowser for help on using the repository browser.