1 |
/* IconsViewerIcon.m |
2 |
* |
3 |
* Copyright (C) 2003 Free Software Foundation, Inc. |
4 |
* |
5 |
* Author: Enrico Sersale <enrico@imago.ro> |
6 |
* Date: August 2001 |
7 |
* |
8 |
* This file is part of the GNUstep GWorkspace application |
9 |
* |
10 |
* This program is free software; you can redistribute it and/or modify |
11 |
* it under the terms of the GNU General Public License as published by |
12 |
* the Free Software Foundation; either version 2 of the License, or |
13 |
* (at your option) any later version. |
14 |
* |
15 |
* This program is distributed in the hope that it will be useful, |
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
* GNU General Public License for more details. |
19 |
* |
20 |
* You should have received a copy of the GNU General Public License |
21 |
* along with this program; if not, write to the Free Software |
22 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 |
*/ |
24 |
|
25 |
|
26 |
#include <Foundation/Foundation.h> |
27 |
#include <AppKit/AppKit.h> |
28 |
#ifdef GNUSTEP |
29 |
#include "GWLib.h" |
30 |
#include "GWProtocol.h" |
31 |
#include "GWFunctions.h" |
32 |
#include "GWNotifications.h" |
33 |
#else |
34 |
#include <GWorkspace/GWLib.h> |
35 |
#include <GWorkspace/GWProtocol.h> |
36 |
#include <GWorkspace/GWFunctions.h> |
37 |
#include <GWorkspace/GWNotifications.h> |
38 |
#endif |
39 |
#include "IconsViewerIcon.h" |
40 |
#include "GNUstep.h" |
41 |
|
42 |
#define CHECK_LOCK if (locked) return |
43 |
#define CHECK_LOCK_RET(x) if (locked) return x |
44 |
|
45 |
@implementation IconsViewerIcon |
46 |
|
47 |
- (void)dealloc |
48 |
{ |
49 |
RELEASE (path); |
50 |
RELEASE (name); |
51 |
RELEASE (type); |
52 |
RELEASE (namelabel); |
53 |
RELEASE (icon); |
54 |
RELEASE (highlight); |
55 |
[super dealloc]; |
56 |
} |
57 |
|
58 |
- (id)initForPath:(NSString *)apath delegate:(id)adelegate |
59 |
{ |
60 |
self = [super init]; |
61 |
if (self) { |
62 |
NSString *defApp = nil, *t = nil; |
63 |
NSFont *font; |
64 |
|
65 |
fm = [NSFileManager defaultManager]; |
66 |
|
67 |
ASSIGN (path, apath); |
68 |
[self setDelegate: adelegate]; |
69 |
|
70 |
labelWidth = [delegate getCellsWidth] - 4; |
71 |
font = [NSFont systemFontOfSize: 12]; |
72 |
[self setFrame: NSMakeRect(0, 0, 64, 52)]; |
73 |
isSelect = NO; |
74 |
locked = NO; |
75 |
|
76 |
ASSIGN (name, [path lastPathComponent]); |
77 |
|
78 |
[[NSWorkspace sharedWorkspace] getInfoForFile: path |
79 |
application: &defApp |
80 |
type: &t]; |
81 |
ASSIGN (type, t); |
82 |
isPakage = [GWLib isPakageAtPath: path]; |
83 |
ASSIGN (icon, [GWLib iconForFile: path ofType: type]); |
84 |
ASSIGN (highlight, [NSImage imageNamed: @"CellHighlight.tiff"]); |
85 |
|
86 |
namelabel = [NSTextField new]; |
87 |
[namelabel setFont: font]; |
88 |
[namelabel setBezeled: NO]; |
89 |
[namelabel setEditable: NO]; |
90 |
[namelabel setSelectable: NO]; |
91 |
[namelabel setAlignment: NSCenterTextAlignment]; |
92 |
[namelabel setBackgroundColor: [NSColor windowBackgroundColor]]; |
93 |
[namelabel setTextColor: [NSColor blackColor]]; |
94 |
[self setLabelWidth]; |
95 |
|
96 |
[self registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; |
97 |
|
98 |
dragdelay = 0; |
99 |
isDragTarget = NO; |
100 |
onSelf = NO; |
101 |
} |
102 |
|
103 |
return self; |
104 |
} |
105 |
|
106 |
- (void)setPath:(NSString *)apath |
107 |
{ |
108 |
NSString *defApp = nil, *t = nil; |
109 |
|
110 |
ASSIGN (path, apath); |
111 |
ASSIGN (name, [path lastPathComponent]); |
112 |
ASSIGN (icon, [GWLib iconForFile: path ofType: type]); |
113 |
|
114 |
[[NSWorkspace sharedWorkspace] getInfoForFile: path |
115 |
application: &defApp |
116 |
type: &t]; |
117 |
ASSIGN (type, t); |
118 |
isPakage = [delegate isPakageAtPath: path]; |
119 |
|
120 |
[self setLabelWidth]; |
121 |
} |
122 |
|
123 |
- (void)select |
124 |
{ |
125 |
if (isSelect) { |
126 |
return; |
127 |
} |
128 |
if ([fm fileExistsAtPath: path] == NO) { |
129 |
return; |
130 |
} |
131 |
isSelect = YES; |
132 |
[namelabel setBackgroundColor: [NSColor whiteColor]]; |
133 |
[delegate unselectIconsDifferentFrom: self]; |
134 |
[self setNeedsDisplay: YES]; |
135 |
[delegate setTheCurrentSelection: [NSArray arrayWithObject: path]]; |
136 |
[(NSView *)delegate setNeedsDisplayInRect: [namelabel frame]]; |
137 |
} |
138 |
|
139 |
- (void)unselect |
140 |
{ |
141 |
if (isSelect == NO) { |
142 |
return; |
143 |
} |
144 |
isSelect = NO; |
145 |
[namelabel setBackgroundColor: [NSColor windowBackgroundColor]]; |
146 |
[self setNeedsDisplay: YES]; |
147 |
[delegate setTheCurrentSelection: [NSArray array]]; |
148 |
[(NSView *)delegate setNeedsDisplayInRect: [namelabel frame]]; |
149 |
} |
150 |
|
151 |
- (void)renewIcon |
152 |
{ |
153 |
ASSIGN (icon, [GWLib iconForFile: path ofType: type]); |
154 |
[self setNeedsDisplay: YES]; |
155 |
} |
156 |
|
157 |
- (void)setLabelWidth |
158 |
{ |
159 |
int width = (int)[[namelabel font] widthOfString: name] + 8; |
160 |
|
161 |
labelWidth = [delegate getCellsWidth] - 4; |
162 |
|
163 |
if (width > labelWidth) { |
164 |
width = labelWidth; |
165 |
} |
166 |
[namelabel setFrame: NSMakeRect(0, 0, width, 14)]; |
167 |
[namelabel setStringValue: cutFileLabelText(name, namelabel, width - 8)]; |
168 |
} |
169 |
|
170 |
- (NSTextField *)myLabel |
171 |
{ |
172 |
return namelabel; |
173 |
} |
174 |
|
175 |
- (NSString *)type |
176 |
{ |
177 |
return type; |
178 |
} |
179 |
|
180 |
- (NSString *)path |
181 |
{ |
182 |
return path; |
183 |
} |
184 |
|
185 |
- (NSString *)myName |
186 |
{ |
187 |
return name; |
188 |
} |
189 |
|
190 |
- (NSSize)iconShift |
191 |
{ |
192 |
NSRect r = [self frame]; |
193 |
NSSize s = [icon size]; |
194 |
|
195 |
return NSMakeSize((r.size.width - s.width) / 2, (r.size.height - s.height) / 2); |
196 |
} |
197 |
|
198 |
- (BOOL)isSelect |
199 |
{ |
200 |
return isSelect; |
201 |
} |
202 |
|
203 |
- (void)setLocked:(BOOL)value |
204 |
{ |
205 |
if (locked == value) { |
206 |
return; |
207 |
} |
208 |
locked = value; |
209 |
[namelabel setTextColor: (locked ? [NSColor disabledControlTextColor] |
210 |
: [NSColor controlTextColor])]; |
211 |
[self setNeedsDisplay: YES]; |
212 |
[namelabel setNeedsDisplay: YES]; |
213 |
} |
214 |
|
215 |
- (BOOL)isLocked |
216 |
{ |
217 |
return locked; |
218 |
} |
219 |
|
220 |
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent |
221 |
{ |
222 |
return YES; |
223 |
} |
224 |
|
225 |
- (void)mouseUp:(NSEvent *)theEvent |
226 |
{ |
227 |
int count = [theEvent clickCount]; |
228 |
|
229 |
CHECK_LOCK; |
230 |
|
231 |
if(count > 1) { |
232 |
unsigned int modifier = [theEvent modifierFlags]; |
233 |
|
234 |
if ([fm fileExistsAtPath: path] == NO) { |
235 |
return; |
236 |
} |
237 |
|
238 |
[delegate openTheCurrentSelection: [NSArray arrayWithObject: path] |
239 |
newViewer: (modifier == NSControlKeyMask)]; |
240 |
} |
241 |
} |
242 |
|
243 |
- (void)mouseDown:(NSEvent *)theEvent |
244 |
{ |
245 |
int count = [theEvent clickCount]; |
246 |
|
247 |
CHECK_LOCK; |
248 |
|
249 |
if(count == 1) { |
250 |
if([theEvent modifierFlags] == 2) { |
251 |
[delegate setShiftClickValue: YES]; |
252 |
if (isSelect == YES) { |
253 |
[self unselect]; |
254 |
return; |
255 |
} else { |
256 |
[self select]; |
257 |
} |
258 |
} else { |
259 |
[delegate setShiftClickValue: NO]; |
260 |
if (isSelect == NO) { |
261 |
[self select]; |
262 |
} |
263 |
} |
264 |
} |
265 |
} |
266 |
|
267 |
- (void)mouseDragged:(NSEvent *)theEvent |
268 |
{ |
269 |
if ([fm fileExistsAtPath: path] == NO) { |
270 |
return; |
271 |
} |
272 |
|
273 |
if(dragdelay < 5) { |
274 |
dragdelay++; |
275 |
return; |
276 |
} |
277 |
|
278 |
[self startExternalDragOnEvent: theEvent]; |
279 |
} |
280 |
|
281 |
- (NSMenu *)menuForEvent:(NSEvent *)theEvent |
282 |
{ |
283 |
if (([theEvent type] == NSRightMouseDown) && isSelect) { |
284 |
return [delegate menuForRightMouseEvent: theEvent]; |
285 |
} |
286 |
|
287 |
return [super menuForEvent: theEvent]; |
288 |
} |
289 |
|
290 |
- (id)delegate |
291 |
{ |
292 |
return delegate; |
293 |
} |
294 |
|
295 |
- (void)setDelegate:(id)aDelegate |
296 |
{ |
297 |
delegate = aDelegate; |
298 |
} |
299 |
|
300 |
- (void)drawRect:(NSRect)rect |
301 |
{ |
302 |
NSRect r = [self bounds]; |
303 |
NSSize s = [icon size]; |
304 |
NSPoint p = NSMakePoint((r.size.width - s.width) / 2, (r.size.height - s.height) / 2); |
305 |
|
306 |
if(isSelect) { |
307 |
[highlight compositeToPoint: NSZeroPoint operation: NSCompositeSourceOver]; |
308 |
} |
309 |
|
310 |
if (icon != nil) { |
311 |
if (locked == NO) { |
312 |
[icon compositeToPoint: p operation: NSCompositeSourceOver]; |
313 |
} else { |
314 |
[icon dissolveToPoint: p fraction: 0.3]; |
315 |
} |
316 |
} |
317 |
} |
318 |
|
319 |
@end |
320 |
|
321 |
@implementation IconsViewerIcon (DraggingSource) |
322 |
|
323 |
- (void)startExternalDragOnEvent:(NSEvent *)event |
324 |
{ |
325 |
NSEvent *nextEvent; |
326 |
NSPoint dragPoint; |
327 |
NSPasteboard *pb; |
328 |
NSImage *dragIcon; |
329 |
NSArray *selection; |
330 |
|
331 |
nextEvent = [[self window] nextEventMatchingMask: |
332 |
NSLeftMouseUpMask | NSLeftMouseDraggedMask]; |
333 |
|
334 |
if([nextEvent type] != NSLeftMouseDragged) { |
335 |
return; |
336 |
} |
337 |
|
338 |
dragPoint = [nextEvent locationInWindow]; |
339 |
dragPoint = [self convertPoint: dragPoint fromView: nil]; |
340 |
|
341 |
pb = [NSPasteboard pasteboardWithName: NSDragPboard]; |
342 |
[self declareAndSetShapeOnPasteboard: pb]; |
343 |
|
344 |
selection = [delegate getTheCurrentSelection]; |
345 |
|
346 |
if ([selection count] > 1) { |
347 |
dragIcon = [NSImage imageNamed: @"MultipleSelection.tiff"]; |
348 |
} else { |
349 |
dragIcon = [GWLib iconForFile: path ofType: type]; |
350 |
} |
351 |
|
352 |
[self dragImage: dragIcon |
353 |
at: dragPoint |
354 |
offset: NSZeroSize |
355 |
event: event |
356 |
pasteboard: pb |
357 |
source: self |
358 |
slideBack: [[GWLib workspaceApp] animateSlideBack]]; |
359 |
} |
360 |
|
361 |
- (void)draggedImage:(NSImage *)anImage |
362 |
endedAt:(NSPoint)aPoint |
363 |
deposited:(BOOL)flag |
364 |
{ |
365 |
dragdelay = 0; |
366 |
onSelf = NO; |
367 |
} |
368 |
|
369 |
- (void)declareAndSetShapeOnPasteboard:(NSPasteboard *)pb |
370 |
{ |
371 |
NSArray *dndtypes; |
372 |
NSArray *selection; |
373 |
|
374 |
dndtypes = [NSArray arrayWithObject: NSFilenamesPboardType]; |
375 |
[pb declareTypes: dndtypes owner: nil]; |
376 |
selection = [delegate getTheCurrentSelection]; |
377 |
|
378 |
if ([pb setPropertyList: selection forType: NSFilenamesPboardType] == NO) { |
379 |
return; |
380 |
} |
381 |
} |
382 |
|
383 |
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)flag |
384 |
{ |
385 |
return NSDragOperationAll; |
386 |
} |
387 |
|
388 |
@end |
389 |
|
390 |
@implementation IconsViewerIcon (DraggingDestination) |
391 |
|
392 |
- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender |
393 |
{ |
394 |
NSPasteboard *pb; |
395 |
NSDragOperation sourceDragMask; |
396 |
NSArray *sourcePaths; |
397 |
NSString *fromPath; |
398 |
NSString *buff; |
399 |
NSString *iconPath; |
400 |
int i, count; |
401 |
|
402 |
CHECK_LOCK_RET (NSDragOperationNone); |
403 |
|
404 |
pb = [sender draggingPasteboard]; |
405 |
if([[pb types] indexOfObject: NSFilenamesPboardType] != NSNotFound) { |
406 |
sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; |
407 |
count = [sourcePaths count]; |
408 |
|
409 |
if ((count == 1) && ([path isEqualToString: [sourcePaths objectAtIndex: 0]])) { |
410 |
onSelf = YES; |
411 |
isDragTarget = YES; |
412 |
return NSDragOperationAll; |
413 |
} |
414 |
|
415 |
if ((([type isEqualToString: NSDirectoryFileType] == NO) |
416 |
&& ([type isEqualToString: NSFilesystemFileType] == NO)) || isPakage) { |
417 |
return NSDragOperationNone; |
418 |
} |
419 |
|
420 |
fromPath = [[sourcePaths objectAtIndex: 0] stringByDeletingLastPathComponent]; |
421 |
|
422 |
if (count == 0) { |
423 |
return NSDragOperationNone; |
424 |
} |
425 |
|
426 |
if ([fm isWritableFileAtPath: path] == NO) { |
427 |
return NSDragOperationNone; |
428 |
} |
429 |
|
430 |
if ([path isEqualToString: fromPath]) { |
431 |
return NSDragOperationNone; |
432 |
} |
433 |
|
434 |
for (i = 0; i < count; i++) { |
435 |
if ([path isEqualToString: [sourcePaths objectAtIndex: i]]) { |
436 |
return NSDragOperationNone; |
437 |
} |
438 |
} |
439 |
|
440 |
buff = [NSString stringWithString: path]; |
441 |
while (1) { |
442 |
for (i = 0; i < count; i++) { |
443 |
if ([buff isEqualToString: [sourcePaths objectAtIndex: i]]) { |
444 |
return NSDragOperationNone; |
445 |
} |
446 |
} |
447 |
if ([buff isEqualToString: fixPath(@"/", 0)] == YES) { |
448 |
break; |
449 |
} |
450 |
buff = [buff stringByDeletingLastPathComponent]; |
451 |
} |
452 |
|
453 |
isDragTarget = YES; |
454 |
|
455 |
iconPath = [path stringByAppendingPathComponent: @".opendir.tiff"]; |
456 |
|
457 |
if ([fm isReadableFileAtPath: iconPath]) { |
458 |
NSImage *img = [[NSImage alloc] initWithContentsOfFile: iconPath]; |
459 |
|
460 |
if (img) { |
461 |
ASSIGN (icon, img); |
462 |
RELEASE (img); |
463 |
} else { |
464 |
ASSIGN (icon, [NSImage imageNamed: @"FileIcon_Directory_Open.tiff"]); |
465 |
} |
466 |
} else { |
467 |
ASSIGN (icon, [NSImage imageNamed: @"FileIcon_Directory_Open.tiff"]); |
468 |
} |
469 |
|
470 |
[self setNeedsDisplay: YES]; |
471 |
|
472 |
sourceDragMask = [sender draggingSourceOperationMask]; |
473 |
|
474 |
if (sourceDragMask == NSDragOperationCopy) { |
475 |
return NSDragOperationCopy; |
476 |
} else if (sourceDragMask == NSDragOperationLink) { |
477 |
return NSDragOperationLink; |
478 |
} else { |
479 |
return NSDragOperationAll; |
480 |
} |
481 |
} |
482 |
|
483 |
return NSDragOperationNone; |
484 |
} |
485 |
|
486 |
- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender |
487 |
{ |
488 |
NSDragOperation sourceDragMask; |
489 |
|
490 |
CHECK_LOCK_RET (NSDragOperationNone); |
491 |
|
492 |
if (isPakage) { |
493 |
return NSDragOperationNone; |
494 |
} |
495 |
if (isDragTarget == NO) { |
496 |
return NSDragOperationNone; |
497 |
} |
498 |
|
499 |
sourceDragMask = [sender draggingSourceOperationMask]; |
500 |
|
501 |
if (sourceDragMask == NSDragOperationCopy) { |
502 |
return NSDragOperationCopy; |
503 |
} else if (sourceDragMask == NSDragOperationLink) { |
504 |
return NSDragOperationLink; |
505 |
} else { |
506 |
return NSDragOperationAll; |
507 |
} |
508 |
|
509 |
return NSDragOperationNone; |
510 |
} |
511 |
|
512 |
- (void)draggingExited:(id <NSDraggingInfo>)sender |
513 |
{ |
514 |
if(isDragTarget == YES) { |
515 |
isDragTarget = NO; |
516 |
if (onSelf == NO) { |
517 |
ASSIGN (icon, [GWLib iconForFile: path ofType: type]); |
518 |
[self setNeedsDisplay: YES]; |
519 |
} |
520 |
onSelf = NO; |
521 |
} |
522 |
} |
523 |
|
524 |
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender |
525 |
{ |
526 |
CHECK_LOCK_RET (NO); |
527 |
return isDragTarget; |
528 |
} |
529 |
|
530 |
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender |
531 |
{ |
532 |
CHECK_LOCK_RET (NO); |
533 |
return YES; |
534 |
} |
535 |
|
536 |
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender |
537 |
{ |
538 |
NSPasteboard *pb; |
539 |
NSDragOperation sourceDragMask; |
540 |
NSArray *sourcePaths; |
541 |
NSString *operation, *source; |
542 |
NSMutableArray *files; |
543 |
NSMutableDictionary *opDict; |
544 |
NSString *trashPath; |
545 |
int i; |
546 |
|
547 |
CHECK_LOCK; |
548 |
|
549 |
isDragTarget = NO; |
550 |
|
551 |
if (onSelf == YES) { |
552 |
onSelf = NO; |
553 |
return; |
554 |
} |
555 |
|
556 |
ASSIGN (icon, [GWLib iconForFile: path ofType: type]); |
557 |
[self setNeedsDisplay: YES]; |
558 |
|
559 |
sourceDragMask = [sender draggingSourceOperationMask]; |
560 |
pb = [sender draggingPasteboard]; |
561 |
sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; |
562 |
source = [[sourcePaths objectAtIndex: 0] stringByDeletingLastPathComponent]; |
563 |
|
564 |
trashPath = [[GWLib workspaceApp] trashPath]; |
565 |
|
566 |
if ([source isEqualToString: trashPath]) { |
567 |
operation = GWorkspaceRecycleOutOperation; |
568 |
} else { |
569 |
if (sourceDragMask == NSDragOperationCopy) { |
570 |
operation = NSWorkspaceCopyOperation; |
571 |
} else if (sourceDragMask == NSDragOperationLink) { |
572 |
operation = NSWorkspaceLinkOperation; |
573 |
} else { |
574 |
operation = NSWorkspaceMoveOperation; |
575 |
} |
576 |
} |
577 |
|
578 |
files = [NSMutableArray arrayWithCapacity: 1]; |
579 |
for(i = 0; i < [sourcePaths count]; i++) { |
580 |
[files addObject: [[sourcePaths objectAtIndex: i] lastPathComponent]]; |
581 |
} |
582 |
|
583 |
opDict = [NSMutableDictionary dictionaryWithCapacity: 4]; |
584 |
[opDict setObject: operation forKey: @"operation"]; |
585 |
[opDict setObject: source forKey: @"source"]; |
586 |
[opDict setObject: path forKey: @"destination"]; |
587 |
[opDict setObject: files forKey: @"files"]; |
588 |
|
589 |
[[GWLib workspaceApp] performFileOperationWithDictionary: opDict]; |
590 |
} |
591 |
|
592 |
@end |