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

Last change on this file since 600 was 600, checked in by Nicholas Riley, 10 years ago

Prototypes 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.001]];
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.