OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * @constructor | 8 * @constructor |
9 */ | 9 */ |
10 function FileCopyManager() { | 10 function FileCopyManager() { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 }; | 100 }; |
101 | 101 |
102 /** | 102 /** |
103 * A record of a queued copy operation. | 103 * A record of a queued copy operation. |
104 * | 104 * |
105 * Multiple copy operations may be queued at any given time. Additional | 105 * Multiple copy operations may be queued at any given time. Additional |
106 * Tasks may be added while the queue is being serviced. Though a | 106 * Tasks may be added while the queue is being serviced. Though a |
107 * cancel operation cancels everything in the queue. | 107 * cancel operation cancels everything in the queue. |
108 * | 108 * |
109 * @param {DirectoryEntry} targetDirEntry Target directory. | 109 * @param {DirectoryEntry} targetDirEntry Target directory. |
110 * @param {boolean} sourceOnDrive True if the source entries are on Drive. | |
111 * @param {boolean} targetOnDrive True if the target entry is on Drive. | |
112 * @param {DirectoryEntry=} opt_zipBaseDirEntry Base directory dealt as a root | 110 * @param {DirectoryEntry=} opt_zipBaseDirEntry Base directory dealt as a root |
113 * in ZIP archive. | 111 * in ZIP archive. |
114 * @constructor | 112 * @constructor |
115 */ | 113 */ |
116 FileCopyManager.Task = function(targetDirEntry, | 114 FileCopyManager.Task = function(targetDirEntry, opt_zipBaseDirEntry) { |
117 sourceOnDrive, | |
118 targetOnDrive, | |
119 opt_zipBaseDirEntry) { | |
120 this.targetDirEntry = targetDirEntry; | 115 this.targetDirEntry = targetDirEntry; |
121 this.zipBaseDirEntry = opt_zipBaseDirEntry; | 116 this.zipBaseDirEntry = opt_zipBaseDirEntry; |
122 this.originalEntries = null; | 117 this.originalEntries = null; |
123 | 118 |
124 this.pendingDirectories = []; | 119 this.pendingDirectories = []; |
125 this.pendingFiles = []; | 120 this.pendingFiles = []; |
126 this.pendingBytes = 0; | 121 this.pendingBytes = 0; |
127 | 122 |
128 this.completedDirectories = []; | 123 this.completedDirectories = []; |
129 this.completedFiles = []; | 124 this.completedFiles = []; |
130 this.completedBytes = 0; | 125 this.completedBytes = 0; |
131 | 126 |
132 this.deleteAfterCopy = false; | 127 this.deleteAfterCopy = false; |
133 this.move = false; | 128 this.move = false; |
134 this.zip = false; | 129 this.zip = false; |
135 this.sourceOnDrive = sourceOnDrive; | |
136 this.targetOnDrive = targetOnDrive; | |
137 | 130 |
138 // If directory already exists, we try to make a copy named 'dir (X)', | 131 // If directory already exists, we try to make a copy named 'dir (X)', |
139 // where X is a number. When we do this, all subsequent copies from | 132 // where X is a number. When we do this, all subsequent copies from |
140 // inside the subtree should be mapped to the new directory name. | 133 // inside the subtree should be mapped to the new directory name. |
141 // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should | 134 // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should |
142 // become 'dir (1)\file.txt'. | 135 // become 'dir (1)\file.txt'. |
143 this.renamedDirectories_ = []; | 136 this.renamedDirectories_ = []; |
144 }; | 137 }; |
145 | 138 |
146 /** | 139 /** |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 return true; | 522 return true; |
530 }; | 523 }; |
531 | 524 |
532 /** | 525 /** |
533 * Kick off pasting. | 526 * Kick off pasting. |
534 * | 527 * |
535 * @param {Array.<string>} files Pathes of source files. | 528 * @param {Array.<string>} files Pathes of source files. |
536 * @param {Array.<string>} directories Pathes of source directories. | 529 * @param {Array.<string>} directories Pathes of source directories. |
537 * @param {boolean} isCut If the source items are removed from original | 530 * @param {boolean} isCut If the source items are removed from original |
538 * location. | 531 * location. |
539 * @param {boolean} isOnDrive If the source items are on Google Drive. | |
540 * @param {string} targetPath Target path. | 532 * @param {string} targetPath Target path. |
541 * @param {boolean} targetOnDrive If target is on Drive. | |
542 */ | 533 */ |
543 FileCopyManager.prototype.paste = function(files, directories, isCut, isOnDrive, | 534 FileCopyManager.prototype.paste = function( |
544 targetPath, targetOnDrive) { | 535 files, directories, isCut, targetPath) { |
545 var self = this; | 536 var self = this; |
546 var entries = []; | 537 var entries = []; |
547 var added = 0; | 538 var added = 0; |
548 var total; | 539 var total; |
549 | 540 |
550 var steps = { | 541 var steps = { |
551 start: function() { | 542 start: function() { |
552 // Filter entries. | 543 // Filter entries. |
553 var entryFilterFunc = function(entry) { | 544 var entryFilterFunc = function(entry) { |
554 if (entry == '') | 545 if (entry == '') |
(...skipping 28 matching lines...) Expand all Loading... |
583 if (added == total) | 574 if (added == total) |
584 steps.onSourceEntriesFound(); | 575 steps.onSourceEntriesFound(); |
585 }, | 576 }, |
586 | 577 |
587 onSourceEntriesFound: function() { | 578 onSourceEntriesFound: function() { |
588 self.root_.getDirectory(targetPath, {}, | 579 self.root_.getDirectory(targetPath, {}, |
589 steps.onTargetEntryFound, steps.onPathError); | 580 steps.onTargetEntryFound, steps.onPathError); |
590 }, | 581 }, |
591 | 582 |
592 onTargetEntryFound: function(targetEntry) { | 583 onTargetEntryFound: function(targetEntry) { |
593 self.queueCopy_(targetEntry, | 584 self.queueCopy_(targetEntry, entries, isCut); |
594 entries, | |
595 isCut, | |
596 isOnDrive, | |
597 targetOnDrive); | |
598 }, | 585 }, |
599 | 586 |
600 onPathError: function(err) { | 587 onPathError: function(err) { |
601 self.eventRouter_.sendProgressEvent( | 588 self.eventRouter_.sendProgressEvent( |
602 'ERROR', | 589 'ERROR', |
603 self.getStatus(), | 590 self.getStatus(), |
604 new FileCopyManager.Error( | 591 new FileCopyManager.Error( |
605 util.FileOperationErrorType.FILESYSTEM_ERROR, err)); | 592 util.FileOperationErrorType.FILESYSTEM_ERROR, err)); |
606 } | 593 } |
607 }; | 594 }; |
(...skipping 15 matching lines...) Expand all Loading... |
623 (PathUtil.getRootPath(sourceEntry.fullPath) == | 610 (PathUtil.getRootPath(sourceEntry.fullPath) == |
624 PathUtil.getRootPath(targetDirEntry.fullPath)); | 611 PathUtil.getRootPath(targetDirEntry.fullPath)); |
625 }; | 612 }; |
626 | 613 |
627 /** | 614 /** |
628 * Initiate a file copy. | 615 * Initiate a file copy. |
629 * | 616 * |
630 * @param {DirectoryEntry} targetDirEntry Target directory. | 617 * @param {DirectoryEntry} targetDirEntry Target directory. |
631 * @param {Array.<Entry>} entries Entries to copy. | 618 * @param {Array.<Entry>} entries Entries to copy. |
632 * @param {boolean} deleteAfterCopy In case of move. | 619 * @param {boolean} deleteAfterCopy In case of move. |
633 * @param {boolean} sourceOnDrive Source directory on Drive. | |
634 * @param {boolean} targetOnDrive Target directory on Drive. | |
635 * @return {FileCopyManager.Task} Copy task. | 620 * @return {FileCopyManager.Task} Copy task. |
636 * @private | 621 * @private |
637 */ | 622 */ |
638 FileCopyManager.prototype.queueCopy_ = function(targetDirEntry, | 623 FileCopyManager.prototype.queueCopy_ = function( |
639 entries, | 624 targetDirEntry, entries, deleteAfterCopy) { |
640 deleteAfterCopy, | |
641 sourceOnDrive, | |
642 targetOnDrive) { | |
643 var self = this; | 625 var self = this; |
644 // When copying files, null can be specified as source directory. | 626 // When copying files, null can be specified as source directory. |
645 var copyTask = new FileCopyManager.Task( | 627 var copyTask = new FileCopyManager.Task(targetDirEntry); |
646 targetDirEntry, sourceOnDrive, targetOnDrive); | |
647 if (deleteAfterCopy) { | 628 if (deleteAfterCopy) { |
648 if (this.isMovable(entries[0], targetDirEntry)) { | 629 if (this.isMovable(entries[0], targetDirEntry)) { |
649 copyTask.move = true; | 630 copyTask.move = true; |
650 } else { | 631 } else { |
651 copyTask.deleteAfterCopy = true; | 632 copyTask.deleteAfterCopy = true; |
652 } | 633 } |
653 } | 634 } |
654 copyTask.setEntries(entries, function() { | 635 copyTask.setEntries(entries, function() { |
655 self.copyTasks_.push(copyTask); | 636 self.copyTasks_.push(copyTask); |
656 self.maybeScheduleCloseBackgroundPage_(); | 637 self.maybeScheduleCloseBackgroundPage_(); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
856 util.EntryChangedType.CREATED, targetEntry); | 837 util.EntryChangedType.CREATED, targetEntry); |
857 onCopyCompleteBase(targetEntry, 0); | 838 onCopyCompleteBase(targetEntry, 0); |
858 }; | 839 }; |
859 | 840 |
860 var onFilesystemError = function(err) { | 841 var onFilesystemError = function(err) { |
861 errorCallback(new FileCopyManager.Error( | 842 errorCallback(new FileCopyManager.Error( |
862 util.FileOperationErrorType.FILESYSTEM_ERROR, err)); | 843 util.FileOperationErrorType.FILESYSTEM_ERROR, err)); |
863 }; | 844 }; |
864 | 845 |
865 var onDeduplicated = function(targetRelativePath) { | 846 var onDeduplicated = function(targetRelativePath) { |
| 847 var isSourceOnDrive = PathUtil.isDriveBasedPath(sourceEntry.fullPath); |
| 848 var isTargetOnDrive = PathUtil.isDriveBasedPath(targetDirEntry.fullPath); |
| 849 |
866 // TODO(benchan): drive::FileSystem has not implemented directory copy, | 850 // TODO(benchan): drive::FileSystem has not implemented directory copy, |
867 // and thus we only call FileEntry.copyTo() for files. Revisit this | 851 // and thus we only call FileEntry.copyTo() for files. Revisit this |
868 // code when drive::FileSystem supports directory copy. | 852 // code when drive::FileSystem supports directory copy. |
869 if (sourceEntry.isFile && (task.sourceOnDrive || task.targetOnDrive)) { | 853 if (sourceEntry.isFile && (isSourceOnDrive || isTargetOnDrive)) { |
870 var sourceFileUrl = sourceEntry.toURL(); | 854 var sourceFileUrl = sourceEntry.toURL(); |
871 var targetFileUrl = targetDirEntry.toURL() + '/' + | 855 var targetFileUrl = targetDirEntry.toURL() + '/' + |
872 encodeURIComponent(targetRelativePath); | 856 encodeURIComponent(targetRelativePath); |
873 var sourceFilePath = util.extractFilePath(sourceFileUrl); | 857 var sourceFilePath = util.extractFilePath(sourceFileUrl); |
874 var targetFilePath = util.extractFilePath(targetFileUrl); | 858 var targetFilePath = util.extractFilePath(targetFileUrl); |
875 var transferedBytes = 0; | 859 var transferedBytes = 0; |
876 | 860 |
877 var onStartTransfer = function() { | 861 var onStartTransfer = function() { |
878 chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener( | 862 chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener( |
879 onFileTransfersUpdated); | 863 onFileTransfersUpdated); |
(...skipping 24 matching lines...) Expand all Loading... |
904 var s = statusList[i]; | 888 var s = statusList[i]; |
905 // Comparing urls is unreliable, since they may use different | 889 // Comparing urls is unreliable, since they may use different |
906 // url encoding schemes (eg. rfc2396 vs. rfc3986). | 890 // url encoding schemes (eg. rfc2396 vs. rfc3986). |
907 var filePath = util.extractFilePath(s.fileUrl); | 891 var filePath = util.extractFilePath(s.fileUrl); |
908 if (filePath == sourceFilePath || filePath == targetFilePath) { | 892 if (filePath == sourceFilePath || filePath == targetFilePath) { |
909 var processed = s.processed; | 893 var processed = s.processed; |
910 | 894 |
911 // It becomes tricky when both the sides are on Drive. | 895 // It becomes tricky when both the sides are on Drive. |
912 // Currently, it is implemented by download followed by upload. | 896 // Currently, it is implemented by download followed by upload. |
913 // Note, however, download will not happen if the file is cached. | 897 // Note, however, download will not happen if the file is cached. |
914 if (task.sourceOnDrive && task.targetOnDrive) { | 898 if (isSourceOnDrive && isTargetOnDrive) { |
915 if (filePath == sourceFilePath) { | 899 if (filePath == sourceFilePath) { |
916 // Download transfer is detected. Let's halve the progress. | 900 // Download transfer is detected. Let's halve the progress. |
917 downTransfer = processed = (s.processed >> 1); | 901 downTransfer = processed = (s.processed >> 1); |
918 } else { | 902 } else { |
919 // If download transfer has been detected, the upload transfer | 903 // If download transfer has been detected, the upload transfer |
920 // is stacked on top of it after halving. Otherwise, just use | 904 // is stacked on top of it after halving. Otherwise, just use |
921 // the upload transfer as-is. | 905 // the upload transfer as-is. |
922 processed = downTransfer > 0 ? | 906 processed = downTransfer > 0 ? |
923 downTransfer + (s.processed >> 1) : s.processed; | 907 downTransfer + (s.processed >> 1) : s.processed; |
924 } | 908 } |
925 } | 909 } |
926 | 910 |
927 if (processed > transferedBytes) { | 911 if (processed > transferedBytes) { |
928 onCopyProgress(sourceEntry, processed - transferedBytes); | 912 onCopyProgress(sourceEntry, processed - transferedBytes); |
929 transferedBytes = processed; | 913 transferedBytes = processed; |
930 } | 914 } |
931 } | 915 } |
932 } | 916 } |
933 }; | 917 }; |
934 | 918 |
935 if (task.sourceOnDrive && task.targetOnDrive) { | 919 if (isSourceOnDrive && isTargetOnDrive) { |
936 targetDirEntry.getDirectory( | 920 targetDirEntry.getDirectory( |
937 PathUtil.dirname(targetRelativePath), {create: false}, | 921 PathUtil.dirname(targetRelativePath), {create: false}, |
938 function(dirEntry) { | 922 function(dirEntry) { |
939 onStartTransfer(); | 923 onStartTransfer(); |
940 sourceEntry.copyTo( | 924 sourceEntry.copyTo( |
941 dirEntry, PathUtil.basename(targetRelativePath), | 925 dirEntry, PathUtil.basename(targetRelativePath), |
942 onSuccessTransfer, onFailTransfer); | 926 onSuccessTransfer, onFailTransfer); |
943 }, | 927 }, |
944 onFilesystemError); | 928 onFilesystemError); |
945 return; | 929 return; |
946 } | 930 } |
947 | 931 |
948 var onFileTransferCompleted = function() { | 932 var onFileTransferCompleted = function() { |
949 self.cancelCallback_ = null; | 933 self.cancelCallback_ = null; |
950 if (chrome.runtime.lastError) { | 934 if (chrome.runtime.lastError) { |
951 onFailTransfer({ | 935 onFailTransfer({ |
952 code: chrome.runtime.lastError.message, | 936 code: chrome.runtime.lastError.message, |
953 toDrive: task.targetOnDrive, | 937 toDrive: isTargetOnDrive, |
954 sourceFileUrl: sourceFileUrl | 938 sourceFileUrl: sourceFileUrl |
955 }); | 939 }); |
956 } else { | 940 } else { |
957 targetDirEntry.getFile(targetRelativePath, {}, onSuccessTransfer, | 941 targetDirEntry.getFile(targetRelativePath, {}, onSuccessTransfer, |
958 onFailTransfer); | 942 onFailTransfer); |
959 } | 943 } |
960 }; | 944 }; |
961 | 945 |
962 self.cancelCallback_ = function() { | 946 self.cancelCallback_ = function() { |
963 self.cancelCallback_ = null; | 947 self.cancelCallback_ = null; |
964 chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener( | 948 chrome.fileBrowserPrivate.onFileTransfersUpdated.removeListener( |
965 onFileTransfersUpdated); | 949 onFileTransfersUpdated); |
966 if (task.sourceOnDrive) { | 950 if (isSourceOnDrive) { |
967 chrome.fileBrowserPrivate.cancelFileTransfers([sourceFileUrl], | 951 chrome.fileBrowserPrivate.cancelFileTransfers([sourceFileUrl], |
968 function() {}); | 952 function() {}); |
969 } else { | 953 } else { |
970 chrome.fileBrowserPrivate.cancelFileTransfers([targetFileUrl], | 954 chrome.fileBrowserPrivate.cancelFileTransfers([targetFileUrl], |
971 function() {}); | 955 function() {}); |
972 } | 956 } |
973 }; | 957 }; |
974 | 958 |
975 // TODO(benchan): Until drive::FileSystem supports FileWriter, we use the | 959 // TODO(benchan): Until drive::FileSystem supports FileWriter, we use the |
976 // transferFile API to copy files into or out from a drive file system. | 960 // transferFile API to copy files into or out from a drive file system. |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1342 filesystemError = error; | 1326 filesystemError = error; |
1343 onComplete(); | 1327 onComplete(); |
1344 }); | 1328 }); |
1345 } | 1329 } |
1346 }; | 1330 }; |
1347 | 1331 |
1348 /** | 1332 /** |
1349 * Creates a zip file for the selection of files. | 1333 * Creates a zip file for the selection of files. |
1350 * | 1334 * |
1351 * @param {Entry} dirEntry the directory containing the selection. | 1335 * @param {Entry} dirEntry the directory containing the selection. |
1352 * @param {boolean} isOnDrive If directory is on Drive. | |
1353 * @param {Array.<Entry>} selectionEntries the selected entries. | 1336 * @param {Array.<Entry>} selectionEntries the selected entries. |
1354 */ | 1337 */ |
1355 FileCopyManager.prototype.zipSelection = function(dirEntry, isOnDrive, | 1338 FileCopyManager.prototype.zipSelection = function(dirEntry, selectionEntries) { |
1356 selectionEntries) { | |
1357 var self = this; | 1339 var self = this; |
1358 var zipTask = new FileCopyManager.Task( | 1340 var zipTask = new FileCopyManager.Task(dirEntry, dirEntry); |
1359 dirEntry, isOnDrive, isOnDrive, dirEntry); | |
1360 zipTask.zip = true; | 1341 zipTask.zip = true; |
1361 zipTask.setEntries(selectionEntries, function() { | 1342 zipTask.setEntries(selectionEntries, function() { |
1362 // TODO: per-entry zip progress update with accurate byte count. | 1343 // TODO: per-entry zip progress update with accurate byte count. |
1363 // For now just set pendingBytes to zero so that the progress bar is full. | 1344 // For now just set pendingBytes to zero so that the progress bar is full. |
1364 zipTask.pendingBytes = 0; | 1345 zipTask.pendingBytes = 0; |
1365 self.copyTasks_.push(zipTask); | 1346 self.copyTasks_.push(zipTask); |
1366 if (self.copyTasks_.length == 1) { | 1347 if (self.copyTasks_.length == 1) { |
1367 // Assume self.cancelRequested_ == false. | 1348 // Assume self.cancelRequested_ == false. |
1368 // This moved us from 0 to 1 active tasks, let the servicing begin! | 1349 // This moved us from 0 to 1 active tasks, let the servicing begin! |
1369 self.serviceAllTasks_(); | 1350 self.serviceAllTasks_(); |
1370 } else { | 1351 } else { |
1371 // Force to update the progress of butter bar when there are new tasks | 1352 // Force to update the progress of butter bar when there are new tasks |
1372 // coming while servicing current task. | 1353 // coming while servicing current task. |
1373 self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus()); | 1354 self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus()); |
1374 } | 1355 } |
1375 }); | 1356 }); |
1376 }; | 1357 }; |
OLD | NEW |