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

Contents of /gnustep/usr-apps/gworkspace/GWorkspace/FileOperations/FileOperation.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations) (download)
Mon Aug 25 17:19:14 2003 UTC (20 years, 9 months ago) by esersale
Branch: MAIN
Changes since 1.3: +24 -0 lines
*** empty log message ***

1 /* FileOperation.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 #include <Foundation/Foundation.h>
26 #include <AppKit/AppKit.h>
27 #ifdef GNUSTEP
28 #include "GWFunctions.h"
29 #include "GWLib.h"
30 #include "GWNotifications.h"
31 #else
32 #include <GWorkspace/GWFunctions.h>
33 #include <GWorkspace/GWLib.h>
34 #include <GWorkspace/GWNotifications.h>
35 #endif
36 #include "FileOperation.h"
37 #include "GWorkspace.h"
38 #include "GNUstep.h"
39
40 #ifndef LONG_DELAY
41 #define LONG_DELAY 86400.0
42 #endif
43
44 static NSString *nibName = @"FileOperationWin";
45
46 @implementation GWorkspace (FileOperations)
47
48 - (int)fileOperationRef
49 {
50 oprefnum++;
51 if (oprefnum == 1000) {
52 oprefnum = 0;
53 }
54 return oprefnum;
55 }
56
57 - (FileOperation *)fileOpWithRef:(int)ref
58 {
59 int i;
60
61 for (i = 0; i < [operations count]; i++) {
62 FileOperation *op = [operations objectAtIndex: i];
63
64 if ([op fileOperationRef] == ref) {
65 return op;
66 }
67 }
68
69 return nil;
70 }
71
72 - (void)endOfFileOperation:(FileOperation *)op
73 {
74 [operations removeObject: op];
75 }
76
77 @end
78
79
80 @implementation FileOperation
81
82 - (void)dealloc
83 {
84 [[NSNotificationCenter defaultCenter] removeObserver: self];
85
86 if (timer && [timer isValid]) {
87 [timer invalidate];
88 }
89
90 RELEASE (operationDict);
91 RELEASE (operation);
92 TEST_RELEASE (source);
93 TEST_RELEASE (destination);
94 TEST_RELEASE (files);
95 TEST_RELEASE (notifNames);
96 TEST_RELEASE (win);
97
98 DESTROY (executor);
99
100 [super dealloc];
101 }
102
103 - (id)initWithOperation:(NSString *)opr
104 source:(NSString *)src
105 destination:(NSString *)dest
106 files:(NSArray *)fls
107 useConfirmation:(BOOL)conf
108 showWindow:(BOOL)showw
109 windowRect:(NSRect)wrect
110 {
111 self = [super init];
112
113 if (self) {
114 if ([NSBundle loadNibNamed: nibName owner: self] == NO) {
115 NSLog(@"failed to load %@!", nibName);
116 } else {
117 int i;
118
119 /* Internationalization */
120 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
121 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
122 [pauseButt setTitle: NSLocalizedString(@"Pause", @"")];
123 [stopButt setTitle: NSLocalizedString(@"Stop", @"")];
124
125 if (NSEqualRects(wrect, NSZeroRect) == NO) {
126 [win setFrame: wrect display: NO];
127 } else if ([win setFrameUsingName: @"fileopprogress"] == NO) {
128 [win setFrame: NSMakeRect(300, 300, 282, 102) display: NO];
129 }
130 [win setDelegate: self];
131
132 gw = [GWorkspace gworkspace];
133 fm = [NSFileManager defaultManager];
134 dnc = [NSDistributedNotificationCenter defaultCenter];
135
136 fileOperationRef = [gw fileOperationRef];
137
138 operation = RETAIN (opr);
139 operationDict = [[NSMutableDictionary alloc] initWithCapacity: 1];
140 [operationDict setObject: operation forKey: @"operation"];
141
142 if (src != nil) {
143 source = [[NSString alloc] initWithString: src];
144 [operationDict setObject: source forKey: @"source"];
145 }
146 if (dest != nil) {
147 destination = [[NSString alloc] initWithString: dest];
148 [operationDict setObject: destination forKey: @"destination"];
149 }
150 if (fls != nil) {
151 files = [[NSMutableArray alloc] initWithCapacity: 1];
152 for(i = 0; i < [fls count]; i++) {
153 [files addObject: [fls objectAtIndex: i]];
154 }
155 [operationDict setObject: files forKey: @"files"];
156 }
157
158 confirm = conf;
159 showwin = showw;
160 executor = nil;
161 opdone = NO;
162
163 if([self showFileOperationAlert] == NO) {
164 [self endOperation];
165 return self;
166 } else {
167 NSMessagePort *port[2];
168 NSArray *ports;
169
170 port[0] = (NSMessagePort *)[NSMessagePort port];
171 port[1] = (NSMessagePort *)[NSMessagePort port];
172 ports = [NSArray arrayWithObjects: port[1], port[0], nil];
173
174 execconn = [[NSConnection alloc] initWithReceivePort: port[0]
175 sendPort: port[1]];
176 [execconn setRootObject: self];
177 [execconn setDelegate: self];
178 [execconn setRequestTimeout: LONG_DELAY];
179 [execconn setReplyTimeout: LONG_DELAY];
180
181 [[NSNotificationCenter defaultCenter] addObserver: self
182 selector: @selector(connectionDidDie:)
183 name: NSConnectionDidDieNotification
184 object: execconn];
185
186 NS_DURING
187 {
188 [NSThread detachNewThreadSelector: @selector(setPorts:)
189 toTarget: [FileOpExecutor class]
190 withObject: ports];
191 }
192 NS_HANDLER
193 {
194 NSLog(@"Error! A fatal error occured while detaching the thread.");
195 }
196 NS_ENDHANDLER
197
198 timer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
199 selector: @selector(checkExecutor:)
200 userInfo: nil repeats: NO];
201 }
202 }
203 }
204
205 return self;
206 }
207
208 - (void)checkExecutor:(id)sender
209 {
210 if ((executor == nil) && (opdone == NO)) {
211 NSString *msg = NSLocalizedString(@"A fatal error occured while detaching the thread!", @"");
212 NSString *buttstr = NSLocalizedString(@"Continue", @"");
213
214 NSRunAlertPanel(nil, msg, buttstr, nil, nil);
215 [self sendDidChangeNotification];
216 [self endOperation];
217 }
218 }
219
220 - (BOOL)showFileOperationAlert
221 {
222 NSString *title;
223 NSString *msg, *msg1, *msg2;
224 int result;
225
226 if(confirm == NO) {
227 return YES;
228 }
229
230 if ([operation isEqual: @"NSWorkspaceMoveOperation"]) {
231 title = NSLocalizedString(@"Move", @"");
232 msg1 = NSLocalizedString(@"Move from: ", @"");
233 msg2 = NSLocalizedString(@"\nto: ", @"");
234 msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
235 } else if ([operation isEqual: @"NSWorkspaceCopyOperation"]) {
236 title = NSLocalizedString(@"Copy", @"");
237 msg1 = NSLocalizedString(@"Copy from: ", @"");
238 msg2 = NSLocalizedString(@"\nto: ", @"");
239 msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
240 } else if ([operation isEqual: @"NSWorkspaceLinkOperation"]) {
241 title = NSLocalizedString(@"Link", @"");
242 msg1 = NSLocalizedString(@"Link ", @"");
243 msg2 = NSLocalizedString(@"\nto: ", @"");
244 msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
245 } else if ([operation isEqual: @"NSWorkspaceRecycleOperation"]) {
246 title = NSLocalizedString(@"Recycler", @"");
247 msg1 = NSLocalizedString(@"Move from: ", @"");
248 msg2 = NSLocalizedString(@"\nto the Recycler", @"");
249 msg = [NSString stringWithFormat: @"%@%@%@?", msg1, source, msg2];
250 } else if ([operation isEqual: @"GWorkspaceRecycleOutOperation"]) {
251 title = NSLocalizedString(@"Recycler", @"");
252 msg1 = NSLocalizedString(@"Move from the Recycler ", @"");
253 msg2 = NSLocalizedString(@"\nto: ", @"");
254 msg = [NSString stringWithFormat: @"%@%@%@?", msg1, msg2, destination];
255 } else if ([operation isEqual: @"GWorkspaceEmptyRecyclerOperation"]) {
256 title = NSLocalizedString(@"Recycler", @"");
257 msg = NSLocalizedString(@"Empty the Recycler?", @"");
258 } else if ([operation isEqual: @"NSWorkspaceDestroyOperation"]) {
259 title = NSLocalizedString(@"Delete", @"");
260 msg = NSLocalizedString(@"Delete the selected objects?", @"");
261 } else if ([operation isEqual: @"NSWorkspaceDuplicateOperation"]) {
262 title = NSLocalizedString(@"Duplicate", @"");
263 msg = NSLocalizedString(@"Duplicate the selected objects?", @"");
264 }
265
266 result = NSRunAlertPanel(title, msg, NSLocalizedString(@"OK", @""),
267 NSLocalizedString(@"Cancel", @""), NULL);
268 if (result != NSAlertDefaultReturn) {
269 return NO;
270 }
271
272 return YES;
273 }
274
275 - (void)registerExecutor:(id)anObject
276 {
277 BOOL result;
278
279 [anObject setProtocolForProxy: @protocol(FileOpExecutorProtocol)];
280 executor = (id <FileOpExecutorProtocol>)[anObject retain];
281
282 result = [executor setOperation: operationDict];
283 result = [executor checkSameName];
284
285 if (result == YES) {
286 NSString *msg, *title;
287
288 if ([operation isEqual: @"NSWorkspaceMoveOperation"]) {
289 msg = @"Some items have the same name;\ndo you want to replace them?";
290 title = @"Move";
291
292 } else if ([operation isEqual: @"NSWorkspaceCopyOperation"]) {
293 msg = @"Some items have the same name;\ndo you want to replace them?";
294 title = @"Copy";
295
296 } else if([operation isEqual: @"NSWorkspaceLinkOperation"]) {
297 msg = @"Some items have the same name;\ndo you want to replace them?";
298 title = @"Link";
299
300 } else if([operation isEqual: @"NSWorkspaceRecycleOperation"]) {
301 msg = @"Some items have the same name;\ndo you want to replace them?";
302 title = @"Recycle";
303
304 } else if([operation isEqual: @"GWorkspaceRecycleOutOperation"]) {
305 msg = @"Some items have the same name;\ndo you want to replace them?";
306 title = @"Recycle";
307 }
308
309 result = NSRunAlertPanel(NSLocalizedString(title, @""),
310 NSLocalizedString(msg, @""),
311 NSLocalizedString(@"OK", @""),
312 NSLocalizedString(@"Cancel", @""), NULL);
313
314 if (result != NSAlertDefaultReturn) {
315 [gw endOfFileOperation: self];
316 return;
317 }
318 }
319
320 filescount = [executor calculateNumFiles];
321 if (showwin) {
322 [self showProgressWin];
323 }
324 [self sendWillChangeNotification];
325 [executor performOperation];
326 }
327
328 - (int)requestUserConfirmationWithMessage:(NSString *)message
329 title:(NSString *)title
330 {
331 return NSRunAlertPanel(NSLocalizedString(title, @""),
332 NSLocalizedString(message, @""),
333 NSLocalizedString(@"OK", @""),
334 NSLocalizedString(@"Cancel", @""), NULL);
335 }
336
337 - (void)showProgressWin
338 {
339 if ([win isVisible] == NO) {
340 if ([operation isEqual: @"NSWorkspaceMoveOperation"]) {
341 [win setTitle: NSLocalizedString(@"Move", @"")];
342 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
343 [fromField setStringValue: relativePathFittingInContainer(fromField, source)];
344 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
345 [toField setStringValue: relativePathFittingInContainer(fromField, destination)];
346
347 } else if ([operation isEqual: @"NSWorkspaceCopyOperation"]) {
348 [win setTitle: NSLocalizedString(@"Copy", @"")];
349 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
350 [fromField setStringValue: relativePathFittingInContainer(fromField, source)];
351 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
352 [toField setStringValue: relativePathFittingInContainer(fromField, destination)];
353
354 } else if ([operation isEqual: @"NSWorkspaceLinkOperation"]) {
355 [win setTitle: NSLocalizedString(@"Link", @"")];
356 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
357 [fromField setStringValue: relativePathFittingInContainer(fromField, source)];
358 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
359 [toField setStringValue: relativePathFittingInContainer(fromField, destination)];
360
361 } else if ([operation isEqual: @"NSWorkspaceDuplicateOperation"]) {
362 [win setTitle: NSLocalizedString(@"Duplicate", @"")];
363 [fromLabel setStringValue: NSLocalizedString(@"In:", @"")];
364 [fromField setStringValue: relativePathFittingInContainer(fromField, destination)];
365 [toLabel setStringValue: @""];
366 [toField setStringValue: @""];
367
368 } else if ([operation isEqual: @"NSWorkspaceDestroyOperation"]) {
369 [win setTitle: NSLocalizedString(@"Destroy", @"")];
370 [fromLabel setStringValue: NSLocalizedString(@"In:", @"")];
371 [fromField setStringValue: relativePathFittingInContainer(fromField, destination)];
372 [toLabel setStringValue: @""];
373 [toField setStringValue: @""];
374
375 } else if ([operation isEqual: @"NSWorkspaceRecycleOperation"]) {
376 [win setTitle: NSLocalizedString(@"Move", @"")];
377 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
378 [fromField setStringValue: relativePathFittingInContainer(fromField, source)];
379 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
380 [toField setStringValue: NSLocalizedString(@"the Recycler", @"")];
381
382 } else if ([operation isEqual: @"GWorkspaceRecycleOutOperation"]) {
383 [win setTitle: NSLocalizedString(@"Move", @"")];
384 [fromLabel setStringValue: NSLocalizedString(@"From:", @"")];
385 [fromField setStringValue: NSLocalizedString(@"the Recycler", @"")];
386 [toLabel setStringValue: NSLocalizedString(@"To:", @"")];
387 [toField setStringValue: relativePathFittingInContainer(fromField, destination)];
388
389 } else if ([operation isEqual: @"GWorkspaceEmptyRecyclerOperation"]) {
390 [win setTitle: NSLocalizedString(@"Destroy", @"")];
391 [fromLabel setStringValue: NSLocalizedString(@"In:", @"")];
392 [fromField setStringValue: NSLocalizedString(@"the Recycler", @"")];
393 [toLabel setStringValue: @""];
394 [toField setStringValue: @""];
395 }
396
397 [progInd setMinValue: 0];
398 [progInd setMaxValue: filescount];
399 }
400
401 [win makeKeyAndOrderFront: nil];
402 showwin = YES;
403 }
404
405 - (int)showErrorAlertWithMessage:(NSString *)message
406 {
407 return NSRunAlertPanel(nil, NSLocalizedString(message, @""),
408 NSLocalizedString(@"Continue", @""), nil, nil);
409 }
410
411 - (void)updateProgressIndicator
412 {
413 [progInd incrementBy: 1.0];
414 }
415
416 - (void)endOperation
417 {
418 DESTROY (executor);
419 if (showwin) {
420 [win saveFrameUsingName: @"fileopprogress"];
421 [win close];
422 }
423 [gw endOfFileOperation: self];
424 }
425
426 - (void)sendWillChangeNotification
427 {
428 NSString *fulldestpath;
429 NSMutableDictionary *dict;
430 int i;
431
432 notifNames = [[NSMutableArray alloc] initWithCapacity: 1];
433
434 if ([operation isEqual: @"NSWorkspaceDuplicateOperation"]) {
435 for(i = 0; i < [files count]; i++) {
436 NSString *name = [NSString stringWithString: [files objectAtIndex: i]];
437 while(1) {
438 name = [name stringByAppendingString: @"_copy"];
439 fulldestpath = [destination stringByAppendingPathComponent: name];
440 if (![fm fileExistsAtPath: fulldestpath]) {
441 [notifNames addObject: name];
442 break;
443 }
444 }
445 }
446 } else {
447 [notifNames addObjectsFromArray: files];
448 }
449
450 dict = [NSMutableDictionary dictionaryWithCapacity: 1];
451 [dict setObject: operation forKey: @"operation"];
452 [dict setObject: source forKey: @"source"];
453 [dict setObject: destination forKey: @"destination"];
454 [dict setObject: notifNames forKey: @"files"];
455
456 [dnc postNotificationName: GWFileSystemWillChangeNotification
457 object: nil
458 userInfo: dict];
459 }
460
461 - (int)sendDidChangeNotification
462 {
463 NSMutableDictionary *notifObj = [NSMutableDictionary dictionary];
464
465 [notifObj setObject: operation forKey: @"operation"];
466 [notifObj setObject: source forKey: @"source"];
467 [notifObj setObject: destination forKey: @"destination"];
468 [notifObj setObject: notifNames forKey: @"files"];
469
470 opdone = YES;
471
472 [dnc postNotificationName: GWFileSystemDidChangeNotification
473 object: nil
474 userInfo: notifObj];
475
476 return 0;
477 }
478
479 - (IBAction)pause:(id)sender
480 {
481 if (executor) {
482 if ([executor isPaused] == NO) {
483 [pauseButt setTitle: NSLocalizedString(@"Continue", @"")];
484 [stopButt setEnabled: NO];
485 [executor Pause];
486 } else {
487 [pauseButt setTitle: NSLocalizedString(@"Pause", @"")];
488 [stopButt setEnabled: YES];
489 [executor performOperation];
490 }
491 }
492 }
493
494 - (IBAction)stop:(id)sender
495 {
496 if (executor) {
497 [executor Stop];
498 }
499 }
500
501 - (int)fileOperationRef
502 {
503 return fileOperationRef;
504 }
505
506 - (NSRect)winRect
507 {
508 if (win && [win isVisible]) {
509 return [win frame];
510 }
511 return NSZeroRect;
512 }
513
514 - (BOOL)showsWindow
515 {
516 return showwin;
517 }
518
519 - (BOOL)connection:(NSConnection*)ancestor
520 shouldMakeNewConnection:(NSConnection*)newConn
521 {
522 if (ancestor == execconn) {
523 [[NSNotificationCenter defaultCenter] addObserver: self
524 selector: @selector(connectionDidDie:)
525 name: NSConnectionDidDieNotification object: newConn];
526 [newConn setDelegate: self];
527 return YES;
528 }
529
530 return NO;
531 }
532
533 - (void)connectionDidDie:(NSNotification *)notification
534 {
535 id conn = [notification object];
536
537 [[NSNotificationCenter defaultCenter] removeObserver: self
538 name: NSConnectionDidDieNotification object: conn];
539
540 if (opdone == NO) {
541 NSString *msg = NSLocalizedString(@"thread connection died!", @"");
542 NSString *buttstr = NSLocalizedString(@"Continue", @"");
543
544 NSRunAlertPanel(nil, msg, buttstr, nil, nil);
545 [self sendDidChangeNotification];
546 [self endOperation];
547 }
548 }
549
550 - (BOOL)windowShouldClose:(id)sender
551 {
552 [win saveFrameUsingName: @"fileopprogress"];
553 return YES;
554 }
555
556 @end
557
558
559 @implementation FileOpExecutor
560
561 + (void)setPorts:(NSArray *)thePorts
562 {
563 NSAutoreleasePool *pool;
564 NSMessagePort *port[2];
565 NSConnection *conn;
566 FileOpExecutor *executor;
567
568 pool = [[NSAutoreleasePool alloc] init];
569
570 port[0] = [thePorts objectAtIndex: 0];
571 port[1] = [thePorts objectAtIndex: 1];
572
573 conn = [NSConnection connectionWithReceivePort: (NSMessagePort *)port[0]
574 sendPort: (NSMessagePort *)port[1]];
575
576 executor = [[self alloc] init];
577 [executor setFileop: thePorts];
578 [(id)[conn rootProxy] registerExecutor: executor];
579 RELEASE (executor);
580
581 [[NSRunLoop currentRunLoop] run];
582 RELEASE (pool);
583 }
584
585 - (void)dealloc
586 {
587 TEST_RELEASE (operation);
588 TEST_RELEASE (source);
589 TEST_RELEASE (destination);
590 TEST_RELEASE (files);
591 [super dealloc];
592 }
593
594 - (id)init
595 {
596 self = [super init];
597
598 if (self) {
599 fm = [NSFileManager defaultManager];
600 stopped = NO;
601 paused = NO;
602 samename = NO;
603 }
604
605 return self;
606 }
607
608 - (void)setFileop:(NSArray *)thePorts
609 {
610 NSMessagePort *port[2];
611 NSConnection *conn;
612 id anObject;
613
614 port[0] = [thePorts objectAtIndex: 0];
615 port[1] = [thePorts objectAtIndex: 1];
616
617 conn = [NSConnection connectionWithReceivePort: (NSMessagePort *)port[0]
618 sendPort: (NSMessagePort *)port[1]];
619
620 anObject = (id)[conn rootProxy];
621 [anObject setProtocolForProxy: @protocol(FileOpProtocol)];
622 fileOp = (id <FileOpProtocol>)anObject;
623 }
624
625 - (BOOL)setOperation:(NSDictionary *)opDict
626 {
627 id dictEntry;
628 int i;
629
630 dictEntry = [opDict objectForKey: @"operation"];
631 if (dictEntry != nil) {
632 ASSIGN (operation, dictEntry);
633 }
634
635 dictEntry = [opDict objectForKey: @"source"];
636 if (dictEntry != nil) {
637 ASSIGN (source, dictEntry);
638 }
639
640 dictEntry = [opDict objectForKey: @"destination"];
641 if (dictEntry != nil) {
642 ASSIGN (destination, dictEntry);
643 }
644
645 files = [[NSMutableArray alloc] initWithCapacity: 1];
646 dictEntry = [opDict objectForKey: @"files"];
647 if (dictEntry != nil) {
648 for (i = 0; i < [dictEntry count]; i++) {
649 [files addObject: [dictEntry objectAtIndex: i]];
650 }
651 }
652
653 return YES;
654 }
655
656 - (BOOL)checkSameName
657 {
658 NSArray *dirContents;
659 int i;
660
661 samename = NO;
662
663 if (destination && [files count]) {
664 dirContents = [fm directoryContentsAtPath: destination];
665 for (i = 0; i < [files count]; i++) {
666 if ([dirContents containsObject: [files objectAtIndex: i]]) {
667 samename = YES;
668 break;
669 }
670 }
671 }
672
673 if (samename) {
674 if (([operation isEqual: NSWorkspaceMoveOperation])
675 || ([operation isEqual: NSWorkspaceCopyOperation])
676 || ([operation isEqual: NSWorkspaceLinkOperation])
677 || ([operation isEqual: NSWorkspaceRecycleOperation])
678 || ([operation isEqual: GWorkspaceRecycleOutOperation])) {
679
680 return YES;
681
682 } else if (([operation isEqual: NSWorkspaceDestroyOperation])
683 || ([operation isEqual: NSWorkspaceDuplicateOperation])
684 || ([operation isEqual: GWorkspaceEmptyRecyclerOperation])) {
685
686 return NO;
687 }
688 }
689
690 return NO;
691 }
692
693 - (int)calculateNumFiles
694 {
695 BOOL isDir;
696 NSDirectoryEnumerator *enumerator;
697 NSString *dirEntry;
698 int i;
699
700 for(i = 0; i < [files count]; i++) {
701 NSString *path = [source stringByAppendingPathComponent: [files objectAtIndex: i]];
702
703 isDir = NO;
704 [fm fileExistsAtPath: path isDirectory: &isDir];
705 if (isDir) {
706 enumerator = [fm enumeratorAtPath: path];
707 while ((dirEntry = [enumerator nextObject])) {
708 fcount++;
709 }
710 } else {
711 fcount++;
712 }
713 }
714
715 return fcount;
716 }
717
718 - (oneway void)performOperation
719 {
720 canupdate = YES;
721 stopped = NO;
722 paused = NO;
723 fcount = [files count];
724
725 if ([operation isEqual: NSWorkspaceMoveOperation]
726 || [operation isEqual: NSWorkspaceRecycleOperation]
727 || [operation isEqual: GWorkspaceRecycleOutOperation]) {
728 [self doMove];
729 } else if ([operation isEqual: NSWorkspaceCopyOperation]) {
730 [self doCopy];
731 } else if([operation isEqual: NSWorkspaceLinkOperation]) {
732 [self doLink];
733 } else if([operation isEqual: NSWorkspaceDestroyOperation]
734 || [operation isEqual: GWorkspaceEmptyRecyclerOperation]) {
735 [self doRemove];
736 } else if([operation isEqual: NSWorkspaceDuplicateOperation]) {
737 [self doDuplicate];
738 }
739 }
740
741 #define CHECK_DONE \
742 if (![files count] || stopped) [self done]; \
743 if (paused) break
744
745 #define GET_FILENAME filename = [files objectAtIndex: 0]
746
747 #define CHECK_SAME_NAME \
748 if (samename) [self removeExisting: filename]
749
750 #define WAIT \
751 [[NSRunLoop currentRunLoop] \
752 runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]
753
754 - (void)doMove
755 {
756 while (1) {
757 CHECK_DONE;
758 GET_FILENAME;
759 CHECK_SAME_NAME;
760
761 [fm movePath: [source stringByAppendingPathComponent: filename]
762 toPath: [destination stringByAppendingPathComponent: filename]
763 handler: self];
764
765 [files removeObject: filename];
766 WAIT;
767 }
768 }
769
770 - (void)doCopy
771 {
772 while (1) {
773 CHECK_DONE;
774 GET_FILENAME;
775 CHECK_SAME_NAME;
776
777 [fm copyPath: [source stringByAppendingPathComponent: filename]
778 toPath: [destination stringByAppendingPathComponent: filename]
779 handler: self];
780
781 [files removeObject: filename];
782 WAIT;
783 }
784 }
785
786 - (void)doLink
787 {
788 while (1) {
789 CHECK_DONE;
790 GET_FILENAME;
791 CHECK_SAME_NAME;
792
793 [fm linkPath: [source stringByAppendingPathComponent: filename]
794 toPath: [destination stringByAppendingPathComponent: filename]
795 handler: self];
796
797 [files removeObject: filename];
798 WAIT;
799 }
800 }
801
802 - (void)doRemove
803 {
804 while (1) {
805 CHECK_DONE;
806 GET_FILENAME;
807
808 [fm removeFileAtPath: [destination stringByAppendingPathComponent: filename]
809 handler: self];
810
811 [files removeObject: filename];
812 WAIT;
813 }
814 }
815
816 - (void)doDuplicate
817 {
818 NSString *fulldestpath;
819 NSString *newname;
820
821 while (1) {
822 CHECK_DONE;
823 GET_FILENAME;
824
825 newname = [NSString stringWithString: filename];
826
827 while (1) {
828 newname = [newname stringByAppendingString: @"_copy"];
829 fulldestpath = [destination stringByAppendingPathComponent: newname];
830
831 if (![fm fileExistsAtPath: fulldestpath]) {
832 break;
833 }
834 }
835
836 [fm copyPath: [destination stringByAppendingPathComponent: filename]
837 toPath: fulldestpath
838 handler: self];
839
840 [files removeObject: filename];
841 WAIT;
842 }
843 }
844
845 - (void)removeExisting:(NSString *)fname
846 {
847 NSString *fulldestpath;
848
849 canupdate = NO;
850 fulldestpath = [destination stringByAppendingPathComponent: fname];
851
852 if ([fm fileExistsAtPath: fulldestpath]) {
853 [fm removeFileAtPath: fulldestpath handler: self];
854 }
855 canupdate = YES;
856 }
857
858 - (void)Pause
859 {
860 paused = YES;
861 }
862
863 - (void)Stop
864 {
865 stopped = YES;
866 }
867
868 - (BOOL)isPaused
869 {
870 return paused;
871 }
872
873 - (void)done
874 {
875 [fileOp sendDidChangeNotification];
876 [fileOp endOperation];
877 }
878
879 - (BOOL)fileManager:(NSFileManager *)manager
880 shouldProceedAfterError:(NSDictionary *)errorDict
881 {
882 NSString *path, *msg;
883 BOOL iserror = NO;
884 int result;
885
886 path = [errorDict objectForKey: @"Path"];
887
888 msg = [NSString stringWithFormat: @"%@ %@\n%@ %@\n",
889 NSLocalizedString(@"File operation error:", @""),
890 [errorDict objectForKey: @"Error"],
891 NSLocalizedString(@"with file:", @""),
892 path];
893
894 result = [fileOp requestUserConfirmationWithMessage: msg title: @"Error"];
895
896 if(result != NSAlertDefaultReturn) {
897 [fileOp sendDidChangeNotification];
898 [fileOp endOperation];
899
900 } else {
901 NSString *fname = [path lastPathComponent];
902 BOOL found = NO;
903
904 while (1) {
905 if ([path isEqualToString: source] == YES) {
906 break;
907 }
908
909 if ([files containsObject: fname] == YES) {
910 [files removeObject: fname];
911 found = YES;
912 break;
913 }
914
915 path = [path stringByDeletingLastPathComponent];
916 fname = [path lastPathComponent];
917 }
918
919 if (found == YES) {
920 [self performOperation];
921 } else {
922 result = [fileOp showErrorAlertWithMessage: @"File Operation Error!"];
923 [fileOp sendDidChangeNotification];
924 [fileOp endOperation];
925 return NO;
926 }
927 }
928
929 return !iserror;
930 }
931
932 - (void)fileManager:(NSFileManager *)manager willProcessPath:(NSString *)path
933 {
934 if (canupdate) {
935 [fileOp updateProgressIndicator];
936 }
937 }
938
939 @end

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