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

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

Float vs. double fixes to pacify GCC.

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