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

Last change on this file since 553 was 553, checked in by Nicholas Riley, 15 years ago

No longer need special code to scale icons (it had issues, anyway).

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