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

Last change on this file since 355 was 355, checked in by Nicholas Riley, 12 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.