/[gnustep]/gnustep/usr-apps/gworkspace/GWorkspace/Recycler/Recycler.m
ViewVC logotype

Contents of /gnustep/usr-apps/gworkspace/GWorkspace/Recycler/Recycler.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations) (download)
Tue Sep 30 15:38:05 2003 UTC (20 years, 6 months ago) by esersale
Branch: MAIN
Changes since 1.3: +4 -2 lines
*** empty log message ***

1 /* Recycler.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 "GWFunctions.h"
31 #include "GWNotifications.h"
32 #else
33 #include <GWorkspace/GWLib.h>
34 #include <GWorkspace/GWFunctions.h>
35 #include <GWorkspace/GWNotifications.h>
36 #endif
37 #include "Recycler.h"
38 #include "RecyclerViews.h"
39 #include "RecyclerIcon.h"
40 #include "GWorkspace.h"
41 #include "GNUstep.h"
42
43 @implementation Recycler
44
45 - (void)dealloc
46 {
47 [[NSNotificationCenter defaultCenter] removeObserver: self];
48 RELEASE (tile);
49 RELEASE (emptyImg);
50 RELEASE (fullImg);
51 RELEASE (recyclerView);
52 RELEASE (iconsView);
53 RELEASE (icons);
54 RELEASE (recyclerWin);
55 RELEASE (trashPath);
56 RELEASE (contentsDict);
57 TEST_RELEASE (selectedPath);
58 [super dealloc];
59 }
60
61 - (id)initWithTrashPath:(NSString *)trashpath
62 {
63 self = [super initWithFrame: NSMakeRect(0, 0, 64, 64)];
64 if (self) {
65 NSUserDefaults *defaults;
66 id result;
67 NSScrollView *scroll;
68 unsigned int style;
69
70 defaults = [NSUserDefaults standardUserDefaults];
71
72 result = [defaults objectForKey: @"recyclercontents"];
73 if (result == nil) {
74 contentsDict = [[NSMutableDictionary alloc] initWithCapacity: 1];
75 } else {
76 contentsDict = [result mutableCopy];
77 }
78
79 ASSIGN (trashPath, trashpath);
80 ASSIGN (tile, [NSImage imageNamed: @"common_Tile.tiff"]);
81 ASSIGN (emptyImg, [NSImage imageNamed: @"Recycler.tiff"]);
82 ASSIGN (fullImg, [NSImage imageNamed: @"RecyclerFull.tiff"]);
83 icons = [[NSMutableArray alloc] initWithCapacity: 1];
84 fm = [NSFileManager defaultManager];
85 gw = [GWorkspace gworkspace];
86 isDragTarget = NO;
87 isOpen = NO;
88 selectedPath = nil;
89 [self registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
90
91 style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
92
93 recyclerWin = [[NSWindow alloc] initWithContentRect: NSZeroRect
94 styleMask: style backing: NSBackingStoreBuffered defer: NO];
95 if ([recyclerWin setFrameUsingName: @"recyclerwin"] == NO) {
96 [recyclerWin setFrame: NSMakeRect(100, 100, 400, 128) display: NO];
97 }
98 [recyclerWin setMinSize: NSMakeSize(220, 128)];
99 [recyclerWin setMaxSize: NSMakeSize(2000, 128)];
100 [recyclerWin setTitle: NSLocalizedString(@"Recycler", @"")];
101 [recyclerWin setReleasedWhenClosed: NO];
102 [recyclerWin setDelegate: self];
103
104 recyclerView = [[RecyclerView alloc] init];
105 [recyclerView setFrame: [[recyclerWin contentView] frame]];
106
107 logoView = [[LogoView alloc] init];
108 [recyclerView addSubview: logoView];
109
110 scroll = [NSScrollView new];
111 [scroll setBorderType: NSBezelBorder];
112 [scroll setHasHorizontalScroller: YES];
113 [scroll setHasVerticalScroller: NO];
114 [scroll setAutoresizingMask: NSViewWidthSizable];
115 [scroll setBorderType: NSNoBorder];
116
117 iconsView = [[IconsView alloc] initForRecycler: self];
118 [scroll setDocumentView: iconsView];
119
120 [recyclerView addSubview: scroll];
121 RELEASE (scroll);
122
123 [recyclerWin setContentView: recyclerView];
124
125 [self makeTrashContents];
126
127 [[NSNotificationCenter defaultCenter] addObserver: self
128 selector: @selector(fileSystemWillChange:)
129 name: GWFileSystemWillChangeNotification
130 object: nil];
131
132 [[NSNotificationCenter defaultCenter] addObserver: self
133 selector: @selector(fileSystemDidChange:)
134 name: GWFileSystemDidChangeNotification
135 object: nil];
136
137 [[NSNotificationCenter defaultCenter] addObserver: self
138 selector: @selector(watcherNotification:)
139 name: GWFileWatcherFileDidChangeNotification
140 object: nil];
141
142 [self setWatcher];
143
144 win = [[NSWindow alloc] initWithContentRect: NSZeroRect
145 styleMask: NSBorderlessWindowMask
146 backing: NSBackingStoreRetained defer: NO];
147
148 if ([win setFrameUsingName: @"recycler"] == NO) {
149 NSRect r = [[NSScreen mainScreen] frame];
150 [win setFrame: NSMakeRect(r.size.width - 64, 0, 64, 64) display: NO];
151 }
152 [win setReleasedWhenClosed: NO];
153 [win setContentView: self];
154 }
155
156 return self;
157 }
158
159 - (void)activate
160 {
161 [win orderFront: nil];
162 }
163
164 - (NSWindow *)myWin
165 {
166 return win;
167 }
168
169 - (NSWindow *)recyclerWin
170 {
171 return recyclerWin;
172 }
173
174 - (void)makeTrashContents
175 {
176 NSArray *dirContents = [fm directoryContentsAtPath: trashPath];
177 NSArray *refnames = [contentsDict allKeys];
178 int i, count;
179
180 for (i = 0; i < [refnames count]; i++) {
181 NSString *refname = [refnames objectAtIndex: i];
182 if ([dirContents containsObject: refname] == NO) {
183 [contentsDict removeObjectForKey: refname];
184 }
185 }
186
187 count = [icons count];
188 for (i = 0; i < count; i++) {
189 RecyclerIcon *icon = [icons objectAtIndex: 0];
190 [iconsView removeIcon: icon];
191 [icons removeObject: icon];
192 }
193
194 for (i = 0; i < [dirContents count]; i++) {
195 NSString *fname = [dirContents objectAtIndex: i];
196 NSString *fpath = [trashPath stringByAppendingPathComponent: fname];
197 RecyclerIcon *icon;
198
199 [self verifyDictionaryForFileName: fname];
200 icon = [[RecyclerIcon alloc] initWithPath: fpath inIconsView: iconsView];
201 [icons addObject: icon];
202 [iconsView addIcon: icon];
203 RELEASE (icon);
204 }
205
206 if ([dirContents count] > 0) {
207 isFull = YES;
208 [logoView setIsFull: YES];
209 [self setNeedsDisplay: YES];
210 } else {
211 isFull = NO;
212 [logoView setIsFull: NO];
213 [self setNeedsDisplay: YES];
214 }
215
216 TEST_RELEASE (selectedPath);
217 selectedPath = nil;
218
219 [self saveDictionary];
220 }
221
222 - (BOOL)isFull
223 {
224 return isFull;
225 }
226
227 - (BOOL)isOpen
228 {
229 return isOpen;
230 }
231
232 - (NSString *)selectedPath
233 {
234 return selectedPath;
235 }
236
237 - (BOOL)verifyDictionaryForFileName:(NSString *)fname
238 {
239 NSString *fpath = [trashPath stringByAppendingPathComponent: fname];
240 NSDictionary *attributes = [fm fileAttributesAtPath: fpath traverseLink: NO];
241 NSDictionary *fdict = [contentsDict objectForKey: fname];
242
243 if (fdict != nil) {
244 NSNumber *s1 = [attributes objectForKey: @"NSFileSize"];
245 NSNumber *s2 = [NSNumber numberWithInt: [[fdict objectForKey: @"size"] intValue]];
246 NSNumber *p1 = [attributes objectForKey: @"NSFilePosixPermissions"];
247 NSNumber *p2 = [NSNumber numberWithInt: [[fdict objectForKey: @"permissions"] intValue]];
248 NSDate *d1 = [attributes objectForKey: @"NSFileModificationDate"];
249 NSDate *d2 = [NSDate dateWithString: [fdict objectForKey: @"modifdate"]];
250
251 if (([s1 isEqual: s2] == NO)
252 || ([p1 isEqual: p2] == NO)
253 || ([d1 isEqual: d2] == NO)) {
254 [contentsDict removeObjectForKey: fname];
255 return NO;
256 }
257 } else {
258 return NO;
259 }
260
261 return YES;
262 }
263
264 - (void)setCurrentSelection:(NSString *)path
265 {
266 if (path != nil) {
267 ASSIGN (selectedPath, path);
268 [gw setSelectedPaths: [NSArray arrayWithObject: selectedPath]];
269 } else {
270 TEST_RELEASE (selectedPath);
271 selectedPath = nil;
272 }
273 }
274
275 - (void)updateDefaults
276 {
277 if ([win isVisible]) {
278 [win saveFrameUsingName: @"recycler"];
279 }
280 if ([recyclerWin isVisible]) {
281 [recyclerWin saveFrameUsingName: @"recyclerwin"];
282 }
283 }
284
285 - (void)saveDictionary
286 {
287 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
288 [defaults setObject: contentsDict forKey: @"recyclercontents"];
289 [defaults synchronize];
290 }
291
292 - (void)setWatcher
293 {
294 [GWLib addWatcherForPath: trashPath];
295 watching = YES;
296 }
297
298 - (void)unsetWatcher
299 {
300 [[NSNotificationCenter defaultCenter] removeObserver: self
301 name: GWFileWatcherFileDidChangeNotification object: nil];
302
303 [GWLib removeWatcherForPath: trashPath];
304
305 watching = NO;
306 }
307
308 - (void)watcherNotification:(NSNotification *)notification
309 {
310 NSDictionary *notifdict = (NSDictionary *)[notification object];
311 NSString *path = [notifdict objectForKey: @"path"];
312
313 if ([path isEqualToString: trashPath]) {
314 NSString *event = [notifdict objectForKey: @"event"];
315
316 if ((event == GWFileDeletedInWatchedDirectory)
317 || (event == GWFileCreatedInWatchedDirectory)) {
318 [self makeTrashContents];
319 }
320 }
321 }
322
323 - (void)fileSystemWillChange:(NSNotification *)notification
324 {
325 NSDictionary *dict = (NSDictionary *)[notification object];
326 NSString *operation = [dict objectForKey: @"operation"];
327 NSString *source = [dict objectForKey: @"source"];
328 NSString *destination = [dict objectForKey: @"destination"];
329
330 if (operation == NSWorkspaceRecycleOperation
331 || operation == NSWorkspaceMoveOperation) {
332 if ([destination isEqualToString: trashPath]) {
333 NSArray *files = [dict objectForKey: @"files"];
334 int i;
335
336 for (i = 0; i < [files count]; i++) {
337 NSString *fname = [files objectAtIndex: i];
338 NSString *origpath = [source stringByAppendingPathComponent: fname];
339 NSDictionary *attributes = [fm fileAttributesAtPath: origpath traverseLink: NO];
340 NSString *owner = [attributes objectForKey: @"NSFileOwnerAccountName"];
341 NSString *group = [attributes objectForKey: @"NSFileGroupOwnerAccountName"];
342 NSString *permissions = [[attributes objectForKey: @"NSFilePosixPermissions"] stringValue];
343 NSString *size = [[attributes objectForKey: @"NSFileSize"] stringValue];
344 NSString *modifdate = [[attributes objectForKey: @"NSFileModificationDate"] description];
345 NSMutableDictionary *fdict = [NSMutableDictionary dictionaryWithCapacity: 1];
346
347 [fdict setObject: fname forKey: @"fname"];
348 [fdict setObject: origpath forKey: @"origpath"];
349 [fdict setObject: owner forKey: @"owner"];
350 [fdict setObject: group forKey: @"group"];
351 [fdict setObject: permissions forKey: @"permissions"];
352 [fdict setObject: size forKey: @"size"];
353 [fdict setObject: modifdate forKey: @"modifdate"];
354
355 [contentsDict setObject: fdict forKey: fname];
356 }
357 }
358 }
359
360 if (operation == GWorkspaceRecycleOutOperation) {
361 [self unsetWatcher];
362 }
363 }
364
365 - (void)fileSystemDidChange:(NSNotification *)notification
366 {
367 NSDictionary *dict = (NSDictionary *)[notification object];
368 NSString *operation = [dict objectForKey: @"operation"];
369 NSString *source = [dict objectForKey: @"source"];
370 NSString *destination = [dict objectForKey: @"destination"];
371
372 if (operation == GWorkspaceRecycleOutOperation) {
373 NSArray *files = [dict objectForKey: @"files"];
374 int i;
375
376 for (i = 0; i < [files count]; i++) {
377 NSString *fname = [files objectAtIndex: i];
378 NSDictionary *fdict = [contentsDict objectForKey: fname];
379 NSString *fpath = [destination stringByAppendingPathComponent: fname];
380
381 [fm changeFileAttributes: fdict atPath: fpath];
382 }
383
384 [self makeTrashContents];
385
386 if (watching == NO) {
387 [self setWatcher];
388 }
389
390 return;
391 }
392
393 if (operation == GWorkspaceRenameOperation) {
394 destination = [destination stringByDeletingLastPathComponent];
395 }
396
397 if ([source isEqualToString: trashPath]
398 || [destination isEqualToString: trashPath]) {
399 [self makeTrashContents];
400 }
401 }
402
403 - (void)emptyRecycler
404 {
405 NSArray *files = [fm directoryContentsAtPath: trashPath];
406 int tag;
407
408 [gw performFileOperation: GWorkspaceEmptyRecyclerOperation
409 source: trashPath destination: trashPath files: files tag: &tag];
410 }
411
412 - (void)putAway
413 {
414 RecyclerIcon *icon;
415 NSString *name, *path;
416 NSDictionary *dict;
417 NSString *origpath;
418 BOOL isdir;
419 int i, tag;
420
421 for (i = 0; i < [icons count]; i++) {
422 icon = [icons objectAtIndex: i];
423
424 if ([icon isSelect] == NO) {
425 continue;
426 }
427
428 name = [icon name];
429 path = [icon path];
430
431 if ([self verifyDictionaryForFileName: name] == NO) {
432 return;
433 }
434
435 dict = [contentsDict objectForKey: name];
436
437 origpath = [dict objectForKey: @"origpath"];
438 if (origpath != nil) {
439 origpath = [origpath stringByDeletingLastPathComponent];
440 if (([fm fileExistsAtPath: origpath isDirectory: &isdir] && isdir) == NO) {
441 return;
442 }
443 } else {
444 return;
445 }
446
447 [gw performFileOperation: GWorkspaceRecycleOutOperation
448 source: trashPath destination: origpath
449 files: [NSArray arrayWithObject: name] tag: &tag];
450 }
451 }
452
453 - (void)mouseDown:(NSEvent*)theEvent
454 {
455 NSEvent *nextEvent;
456 NSPoint location, lastLocation, origin;
457 float initx, inity;
458
459 if ([theEvent clickCount] > 1) {
460 [recyclerWin orderFront: nil];
461 return;
462 }
463
464 initx = [win frame].origin.x;
465 inity = [win frame].origin.y;
466
467 lastLocation = [theEvent locationInWindow];
468
469 while (1) {
470 nextEvent = [win nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask];
471
472 if ([nextEvent type] == NSLeftMouseUp) {
473 [self updateDefaults];
474 break;
475 } else if ([nextEvent type] == NSLeftMouseDragged) {
476 location = [win mouseLocationOutsideOfEventStream];
477 origin = [win frame].origin;
478 origin.x += (location.x - lastLocation.x);
479 origin.y += (location.y - lastLocation.y);
480 [win setFrameOrigin: origin];
481 }
482 }
483 }
484
485 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
486 {
487 return YES;
488 }
489
490 - (void)drawRect:(NSRect)rect
491 {
492 [self lockFocus];
493 [tile compositeToPoint: NSZeroPoint operation: NSCompositeSourceOver];
494 if (isFull) {
495 [fullImg compositeToPoint: NSMakePoint(8, 8) operation: NSCompositeSourceOver];
496 } else {
497 [emptyImg compositeToPoint: NSMakePoint(8, 8) operation: NSCompositeSourceOver];
498 }
499 [self unlockFocus];
500 }
501
502 - (BOOL)windowShouldClose:(id)sender
503 {
504 [self updateDefaults];
505 isOpen = NO;
506 return YES;
507 }
508
509 - (void)windowDidBecomeKey:(NSNotification *)aNotification
510 {
511 isOpen = YES;
512 }
513
514 - (void)windowDidResignKey:(NSNotification *)aNotification
515 {
516 isOpen = NO;
517 }
518
519 @end
520
521 @implementation Recycler (DraggingDestination)
522
523 - (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
524 {
525 NSPasteboard *pb = [sender draggingPasteboard];
526
527 if([[pb types] indexOfObject: NSFilenamesPboardType] != NSNotFound) {
528 NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
529
530 if ((sourceDragMask == NSDragOperationCopy)
531 || (sourceDragMask == NSDragOperationLink)) {
532 return NSDragOperationNone;
533 }
534
535 isDragTarget = YES;
536 return NSDragOperationAll;
537 }
538
539 return NSDragOperationNone;
540 }
541
542 - (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
543 {
544 NSDragOperation sourceDragMask;
545
546 if (isDragTarget == NO) {
547 return NSDragOperationNone;
548 }
549
550 sourceDragMask = [sender draggingSourceOperationMask];
551
552 if ((sourceDragMask == NSDragOperationCopy)
553 || (sourceDragMask == NSDragOperationLink)) {
554 return NSDragOperationNone;
555 }
556
557 return NSDragOperationAll;
558 }
559
560 - (void)draggingExited:(id <NSDraggingInfo>)sender
561 {
562 isDragTarget = NO;
563 }
564
565 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
566 {
567 return isDragTarget;
568 }
569
570 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
571 {
572 return YES;
573 }
574
575 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
576 {
577 NSPasteboard *pb;
578 NSString *source;
579 NSArray *sourcePaths;
580 NSMutableArray *files;
581 int i, tag;
582
583 isDragTarget = NO;
584
585 pb = [sender draggingPasteboard];
586 sourcePaths = [pb propertyListForType: NSFilenamesPboardType];
587 source = [[sourcePaths objectAtIndex: 0] stringByDeletingLastPathComponent];
588
589 files = [NSMutableArray arrayWithCapacity: 1];
590 for (i = 0; i < [sourcePaths count]; i++) {
591 [files addObject: [[sourcePaths objectAtIndex: i] lastPathComponent]];
592 }
593
594 [gw performFileOperation: NSWorkspaceRecycleOperation source: source
595 destination: trashPath files: files tag: &tag];
596 }
597
598 @end
599

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26