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

Last change on this file since 41 was 41, checked in by Nicholas Riley, 21 years ago

Popup triangle.tiff: Needed display component of NJRFSObjectSelector.
This one appears to use transparency unlike the one I prepared for
Process Exhibits, so it should be preferred.

NSMovie-NJRExtensions: Added -isStatic to identify whether the movie
contains dynamic components. If the movie is static, it most likely
contains only an image and shouldn't be 'played' as such, otherwise
the duration will be so short that the image won't be useful.

NJRFSObjectSelector: Fixed -drawRect: to draw the drag feedback
rectangle inside the bounds of the control, not inside whatever dirty
rectangle is passed to the method (often they are the same, but not
always). Only draw the popup arrow if the control is enabled.
Properly draw the popup arrow with transparency. Display the 'make
alias' cursor as additional drag feedback.

PSMovieAlertController: Only repeat movie and auto-close after movie
finished if it contains time-based media, otherwise just display the
movie (an image) until the window is closed or alarms are cancelled.

NSImage-NJRExtensions: Include code to actually scale icons from
F-Script Anywhere, otherwise the menu ends up with 32x32 (or
potentially larger) icons if smaller variations are not provided.
There's some more code in FSA that chooses which representation to
select; this code may still not be properly handling representations,
but it works better now. A good test case is the icon for Tex-Edit
Plus documents.

NJRQTMediaPopUpButton: Added notification for movie change (needed to
update interface). Changed -_validatePreview to
-_validateWithPreview: - preview is now optional. This will be needed
when I add archiving support for the selected item; we'll need to
validate it before updating the interface, but we don't want sounds to
play. Added some #pragma mark lines to separate methods by
functionality. Call -validateWithPreview: NO in awakeFromNib (again,
this logic will become more sophisticated later). Commented some
debugging logic since I'm pretty happy with the code. Added
-canRepeat accessor and setters, notification support in the
validation method. Added drag feedback.

PSAlarmSetController: Notification support, -setSoundRepetitionCount:
to avoid flashing with repetition text field control as NSStepper is
adjusted

English.lproj/MainMenu.nib: Switched action method for the NSStepper
stuff discussed above.

AM /Users/nicholas/Documents/Development/Cocoa/Pester/Source/Popup triangle.tiff
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NSMovie-NJRExtensions.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NJRFSObjectSelector.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/PSMovieAlertController.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NSImage-NJRExtensions.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NJRQTMediaPopUpButton.h
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NJRQTMediaPopUpButton.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/.DS_Store
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/English.lproj/MainMenu.nib/objects.nib
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/English.lproj/MainMenu.nib/info.nib
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/English.lproj/MainMenu.nib/classes.nib
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/Pester.pbproj/nicholas.pbxuser
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/Pester.pbproj/project.pbxproj
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/PSAlarmSetController.h
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/PSAlarmSetController.m
M /Users/nicholas/Documents/Development/Cocoa/Pester/Source/NSMovie-NJRExtensions.h

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