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

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