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

Last change on this file since 536 was 355, checked in by Nicholas Riley, 17 years ago

English.lproj/MainMenu.nib: Modernize menu and alarm set dialog
layout. Use keyed archiving (10.2+) nib format.

Info-Pester.plist: Moved from old PBX project.

NJRFSObjectSelector.m: Bug fixes from code sent to Joey: remove
incorrect usage of tryToPerform:with:; fix logic error in menu
construction. Work around Cocoa's deciding that the menu font size
needs adjustment when it doesn't - so the menu font size now matches
the button font size, though the position is still off. Don't pop up
a menu if we're disabled. Use IconRefs for menu icons, though not
(yet) for the button icon.

NJRHistoryTrackingComboBox.m: Remove item height adjustment
workaround; it now makes the items too tall.

NJRHotKey.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyField.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyManager.m: Add a missing [super dealloc] caught by current
GCC.

NJRIntervalField.m: Fix some type errors.

NJRQTMediaPopUpButton.m: Replace SoundFileManager SPI usage, which
doesn't work in Leopard anyway, with manual enumeration of system
sounds. Start migration to QTKit. Use IconRefs for menu icons.

NJRReadMeController.m: Change source encoding to UTF-8.

NJRSoundManager.m: Fix a type error.

NJRVoicePopUpButton.m: Change source encoding to UTF-8.

NSMenuItem-NJRExtensions.[hm]: Code from ICeCoffEE to use IconRefs for
menu item icons.

PSAlarm.m: Change source encoding to UTF-8.

PSAlarms.m: Fix a signedness mismatch.

PSAlarmsController.m: Change source encoding to UTF-8.

PSAlarmSetController.m: Set keyboard focus after unchecking "Do
script:" and "Play" checkboxes.

PSAlerts.m: Add a missing [super dealloc] caught by current GCC. Fix
a memory leak in property list serialization.

PSPowerManager.[hm]: There's now API for scheduling wakeups; use it
(the old code asserted on startup). To fix: removing scheduled
wakeup. Fix a small type-checking error.

PSPreferencesController.m: Add a missing [super dealloc] caught by
current GCC.

PSScriptAlert.m: Change source encoding to UTF-8.

PSTimeDateEditor.m: Fix a tiny, and one-time, memory leak.

PSTimer.m: Update for new PSPowerManager API.

Pester.pbproj: Deleted; now supporting OS X 10.4+ (up from 10.1,
aiee.)

Pester.xcodeproj: Xcode 2.4+ project, upgraded targets, etc.

SoundFileManager.h: Deleted; this SPI no longer exists in Leopard and
possibly earlier.

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