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 /** | 5 /** |
6 * @constructor | 6 * @constructor |
7 * @param {DirectoryEntry} root Root directory entry. | 7 * @param {DirectoryEntry} root Root directory entry. |
8 */ | 8 */ |
9 function FileCopyManager(root) { | 9 function FileCopyManager(root) { |
10 this.copyTasks_ = []; | 10 this.copyTasks_ = []; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 this.pendingDirectories = []; | 54 this.pendingDirectories = []; |
55 this.pendingFiles = []; | 55 this.pendingFiles = []; |
56 this.pendingBytes = 0; | 56 this.pendingBytes = 0; |
57 | 57 |
58 this.completedDirectories = []; | 58 this.completedDirectories = []; |
59 this.completedFiles = []; | 59 this.completedFiles = []; |
60 this.completedBytes = 0; | 60 this.completedBytes = 0; |
61 | 61 |
62 this.deleteAfterCopy = false; | 62 this.deleteAfterCopy = false; |
63 this.move = false; | 63 this.move = false; |
64 this.zip = false; | |
64 this.sourceOnGData = false; | 65 this.sourceOnGData = false; |
65 this.targetOnGData = false; | 66 this.targetOnGData = false; |
66 | 67 |
67 // If directory already exists, we try to make a copy named 'dir (X)', | 68 // If directory already exists, we try to make a copy named 'dir (X)', |
68 // where X is a number. When we do this, all subsequent copies from | 69 // where X is a number. When we do this, all subsequent copies from |
69 // inside the subtree should be mapped to the new directory name. | 70 // inside the subtree should be mapped to the new directory name. |
70 // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should | 71 // For example, if 'dir' was copied as 'dir (1)', then 'dir\file.txt' should |
71 // become 'dir (1)\file.txt'. | 72 // become 'dir (1)\file.txt'. |
72 this.renamedDirectories_ = []; | 73 this.renamedDirectories_ = []; |
73 }; | 74 }; |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 pendingBytes: 0, | 224 pendingBytes: 0, |
224 | 225 |
225 completedItems: 0, // Files + Directories | 226 completedItems: 0, // Files + Directories |
226 completedFiles: 0, | 227 completedFiles: 0, |
227 completedDirectories: 0, | 228 completedDirectories: 0, |
228 completedBytes: 0, | 229 completedBytes: 0, |
229 | 230 |
230 percentage: NaN, | 231 percentage: NaN, |
231 pendingCopies: 0, | 232 pendingCopies: 0, |
232 pendingMoves: 0, | 233 pendingMoves: 0, |
234 pendingZips: 0, | |
233 filename: '' // In case pendingItems == 1 | 235 filename: '' // In case pendingItems == 1 |
234 }; | 236 }; |
235 | 237 |
236 var pendingFile = null; | 238 var pendingFile = null; |
237 | 239 |
238 for (var i = 0; i < this.copyTasks_.length; i++) { | 240 for (var i = 0; i < this.copyTasks_.length; i++) { |
239 var task = this.copyTasks_[i]; | 241 var task = this.copyTasks_[i]; |
240 var pendingFiles = task.pendingFiles.length; | 242 var pendingFiles = task.pendingFiles.length; |
241 var pendingDirectories = task.pendingDirectories.length; | 243 var pendingDirectories = task.pendingDirectories.length; |
242 rv.pendingFiles += pendingFiles; | 244 rv.pendingFiles += pendingFiles; |
243 rv.pendingDirectories += pendingDirectories; | 245 rv.pendingDirectories += pendingDirectories; |
244 rv.pendingBytes += task.pendingBytes; | 246 rv.pendingBytes += task.pendingBytes; |
245 | 247 |
246 rv.completedFiles += task.completedFiles.length; | 248 rv.completedFiles += task.completedFiles.length; |
247 rv.completedDirectories += task.completedDirectories.length; | 249 rv.completedDirectories += task.completedDirectories.length; |
248 rv.completedBytes += task.completedBytes; | 250 rv.completedBytes += task.completedBytes; |
249 | 251 |
250 if (task.move || task.deleteAfterCopy) { | 252 if (task.zip) { |
253 rv.pendingZips += pendingFiles + pendingDirectories; | |
254 } else if (task.move || task.deleteAfterCopy) { | |
251 rv.pendingMoves += pendingFiles + pendingDirectories; | 255 rv.pendingMoves += pendingFiles + pendingDirectories; |
252 } else { | 256 } else { |
253 rv.pendingCopies += pendingFiles + pendingDirectories; | 257 rv.pendingCopies += pendingFiles + pendingDirectories; |
254 } | 258 } |
255 | 259 |
256 if (task.pendingFiles.length === 1) | 260 if (task.pendingFiles.length === 1) |
257 pendingFile = task.pendingFiles[0]; | 261 pendingFile = task.pendingFiles[0]; |
258 | 262 |
259 if (task.pendingDirectories.length === 1) | 263 if (task.pendingDirectories.length === 1) |
260 pendingFile = task.pendingDirectories[0]; | 264 pendingFile = task.pendingDirectories[0]; |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 | 632 |
629 self.sendProgressEvent_('PROGRESS'); | 633 self.sendProgressEvent_('PROGRESS'); |
630 | 634 |
631 // We yield a few ms between copies to give the browser a chance to service | 635 // We yield a few ms between copies to give the browser a chance to service |
632 // events (like perhaps the user clicking to cancel the copy, for example). | 636 // events (like perhaps the user clicking to cancel the copy, for example). |
633 setTimeout(function() { | 637 setTimeout(function() { |
634 self.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); | 638 self.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); |
635 }, 10); | 639 }, 10); |
636 } | 640 } |
637 | 641 |
638 this.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); | 642 if (!task.zip) |
643 this.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); | |
644 else | |
645 this.serviceZipTask_(task, onTaskComplete, errorCallback); | |
639 }; | 646 }; |
640 | 647 |
641 /** | 648 /** |
642 * Service the next entry in a given task. | 649 * Service the next entry in a given task. |
643 * TODO(olege): Refactor this method into a separate class. | 650 * TODO(olege): Refactor this method into a separate class. |
644 * | 651 * |
645 * @private | 652 * @private |
646 * @param {FileManager.Task} task A task. | 653 * @param {FileManager.Task} task A task. |
647 * @param {Function} successCallback On success. | 654 * @param {Function} successCallback On success. |
648 * @param {Function} errorCallback On error. | 655 * @param {Function} errorCallback On error. |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
958 // Check to see if the target exists. This kicks off the rest of the copy | 965 // Check to see if the target exists. This kicks off the rest of the copy |
959 // if the target is not found, or raises an error if it does. | 966 // if the target is not found, or raises an error if it does. |
960 util.resolvePath(targetDirEntry, targetRelativePath, onTargetExists, | 967 util.resolvePath(targetDirEntry, targetRelativePath, onTargetExists, |
961 onTargetNotResolved); | 968 onTargetNotResolved); |
962 } | 969 } |
963 | 970 |
964 tryNextCopy(); | 971 tryNextCopy(); |
965 }; | 972 }; |
966 | 973 |
967 /** | 974 /** |
975 * Service a zip file creation task. | |
976 * | |
977 * @private | |
978 * @param {FileManager.Task} task A task. | |
979 * @param {Function} completeCallback On complete. | |
980 * @param {Function} errorCallback On error. | |
981 */ | |
982 FileCopyManager.prototype.serviceZipTask_ = function(task, completeCallback, | |
983 errorCallback) { | |
984 var self = this; | |
985 var dirURL = task.sourceDirEntry.toURL(); | |
986 var selectionURLs = []; | |
987 for (var i = 0; i < task.pendingDirectories.length; i++) | |
988 selectionURLs.push(task.pendingDirectories[i].toURL()); | |
989 for (var i = 0; i < task.pendingFiles.length; i++) | |
990 selectionURLs.push(task.pendingFiles[i].toURL()); | |
991 | |
992 var destName = 'Archive'; | |
993 if (task.originalEntries.length == 1) { | |
994 var entryPath = task.originalEntries[0].fullPath; | |
995 var i = entryPath.lastIndexOf('/'); | |
996 var basename = (i < 0) ? entryPath : entryPath.substr(i + 1); | |
997 i = basename.lastIndexOf('.'); | |
998 destName = ((i < 0) ? basename : basename.substr(0, i)); | |
999 } | |
1000 | |
1001 var copyNumber = 0; | |
1002 var firstExistingEntry = null; | |
1003 var destPath = destName + '.zip'; | |
1004 | |
1005 function onError(reason, data) { | |
1006 self.log_('serviceZipTask error: ' + reason + ':', data); | |
1007 errorCallback(new FileCopyManager.Error(reason, data)); | |
1008 } | |
1009 | |
1010 function onTargetExists(existingEntry) { | |
1011 if (copyNumber < 10) { | |
1012 if (!firstExistingEntry) | |
1013 firstExistingEntry = existingEntry; | |
1014 copyNumber++; | |
1015 tryZipSelection(); | |
1016 } else { | |
1017 onError('TARGET_EXISTS', firstExistingEntry); | |
1018 } | |
1019 } | |
1020 | |
1021 function onTargetNotResolved() { | |
1022 function onZipSelectionComplete() { | |
tbarzic
2012/11/10 03:40:56
what if zip failed? we should probably show an err
hshi1
2012/11/12 20:12:12
Done.
| |
1023 self.sendProgressEvent_('SUCCESS'); | |
1024 completeCallback(task); | |
1025 } | |
1026 | |
1027 self.sendProgressEvent_('PROGRESS'); | |
1028 chrome.fileBrowserPrivate.zipSelection(dirURL, selectionURLs, destPath, | |
1029 onZipSelectionComplete); | |
1030 } | |
1031 | |
1032 function tryZipSelection() { | |
1033 if (copyNumber > 0) | |
1034 destPath = destName + ' (' + copyNumber + ').zip'; | |
1035 | |
1036 // Check if the target exists. This kicks off the rest of the zip file | |
1037 // creation if the target is not found, or raises an error if it does. | |
1038 util.resolvePath(task.targetDirEntry, destPath, onTargetExists, | |
1039 onTargetNotResolved); | |
1040 } | |
1041 | |
1042 tryZipSelection(); | |
1043 }; | |
1044 | |
1045 /** | |
968 * Copy the contents of sourceEntry into targetEntry. | 1046 * Copy the contents of sourceEntry into targetEntry. |
969 * | 1047 * |
970 * @private | 1048 * @private |
971 * @param {Entry} sourceEntry entry that will be copied. | 1049 * @param {Entry} sourceEntry entry that will be copied. |
972 * @param {Entry} targetEntry entry to which sourceEntry will be copied. | 1050 * @param {Entry} targetEntry entry to which sourceEntry will be copied. |
973 * @param {function(Entry, number)} progressCallback function that will be | 1051 * @param {function(Entry, number)} progressCallback function that will be |
974 * called when a part of the source entry is copied. It takes |targetEntry| | 1052 * called when a part of the source entry is copied. It takes |targetEntry| |
975 * and size of the last copied chunk as parameters. | 1053 * and size of the last copied chunk as parameters. |
976 * @param {function(Entry, number)} successCallback function that will be called | 1054 * @param {function(Entry, number)} successCallback function that will be called |
977 * the copy operation finishes. It takes |targetEntry| and size of the last | 1055 * the copy operation finishes. It takes |targetEntry| and size of the last |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1044 id: id, | 1122 id: id, |
1045 timeout: setTimeout(this.forceDeleteTask.bind(this, id), | 1123 timeout: setTimeout(this.forceDeleteTask.bind(this, id), |
1046 FileCopyManager.DELETE_TIMEOUT) | 1124 FileCopyManager.DELETE_TIMEOUT) |
1047 }; | 1125 }; |
1048 this.deleteTasks_.push(task); | 1126 this.deleteTasks_.push(task); |
1049 callback(id); | 1127 callback(id); |
1050 this.sendDeleteEvent_(task, 'SCHEDULED'); | 1128 this.sendDeleteEvent_(task, 'SCHEDULED'); |
1051 }; | 1129 }; |
1052 | 1130 |
1053 /** | 1131 /** |
1132 * Creates a zip file for the selection of files. | |
1133 * @param {Entry} dirEntry the directory containing the selection. | |
1134 * @param {boolean} isOnGData If directory is on GDrive. | |
1135 * @param {Array.<Entry>} selectionEntries the selected entries. | |
1136 */ | |
1137 FileCopyManager.prototype.zipSelection = function(dirEntry, isOnGData, | |
1138 selectionEntries) { | |
1139 var self = this; | |
1140 var zipTask = new FileCopyManager.Task(dirEntry, dirEntry); | |
1141 zipTask.zip = true; | |
1142 zipTask.sourceOnGData = isOnGData; | |
1143 zipTask.targetOnGData = isOnGData; | |
1144 zipTask.setEntries(selectionEntries, function() { | |
1145 // TODO: per-entry zip progress update with accurate byte count. | |
1146 // For now just set pendingBytes to zero so that the progress bar is full. | |
1147 zipTask.pendingBytes = 0; | |
1148 self.copyTasks_.push(zipTask); | |
1149 if (self.copyTasks_.length == 1) { | |
1150 // Assume self.cancelRequested_ == false. | |
1151 // This moved us from 0 to 1 active tasks, let the servicing begin! | |
1152 self.serviceAllTasks_(); | |
1153 } else { | |
1154 // Force to update the progress of butter bar when there are new tasks | |
1155 // coming while servicing current task. | |
1156 self.sendProgressEvent_('PROGRESS'); | |
1157 } | |
1158 }); | |
1159 }; | |
1160 | |
1161 /** | |
1054 * Force deletion before timeout runs out. | 1162 * Force deletion before timeout runs out. |
1055 * @param {number} id The delete task id (as returned by deleteEntries). | 1163 * @param {number} id The delete task id (as returned by deleteEntries). |
1056 */ | 1164 */ |
1057 FileCopyManager.prototype.forceDeleteTask = function(id) { | 1165 FileCopyManager.prototype.forceDeleteTask = function(id) { |
1058 var task = this.findDeleteTaskAndCancelTimeout_(id); | 1166 var task = this.findDeleteTaskAndCancelTimeout_(id); |
1059 if (task) this.serviceDeleteTask_(task); | 1167 if (task) this.serviceDeleteTask_(task); |
1060 }; | 1168 }; |
1061 | 1169 |
1062 /** | 1170 /** |
1063 * Cancels the scheduled deletion. | 1171 * Cancels the scheduled deletion. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1120 */ | 1228 */ |
1121 FileCopyManager.prototype.sendDeleteEvent_ = function(task, reason) { | 1229 FileCopyManager.prototype.sendDeleteEvent_ = function(task, reason) { |
1122 this.sendEvent_('delete', { | 1230 this.sendEvent_('delete', { |
1123 reason: reason, | 1231 reason: reason, |
1124 id: task.id, | 1232 id: task.id, |
1125 urls: task.entries.map(function(e) { | 1233 urls: task.entries.map(function(e) { |
1126 return util.makeFilesystemUrl(e.fullPath); | 1234 return util.makeFilesystemUrl(e.fullPath); |
1127 }) | 1235 }) |
1128 }); | 1236 }); |
1129 }; | 1237 }; |
OLD | NEW |