| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 'use strict'; | |
| 6 | |
| 7 /** | |
| 8 * An event handler of the background page for file operations. | |
| 9 * @param {Background} background Background page. | |
| 10 * @constructor | |
| 11 */ | |
| 12 var FileOperationHandler = function(background) { | |
| 13 /** | |
| 14 * Background page. | |
| 15 * @type {Background} | |
| 16 * @private | |
| 17 */ | |
| 18 this.background_ = background; | |
| 19 | |
| 20 /** | |
| 21 * File operation manager. | |
| 22 * @type {FileOperationManager} | |
| 23 * @private | |
| 24 */ | |
| 25 this.fileOperationManager_ = background.fileOperationManager; | |
| 26 | |
| 27 /** | |
| 28 * Progress center. | |
| 29 * @type {progressCenter} | |
| 30 * @private | |
| 31 */ | |
| 32 this.progressCenter_ = background.progressCenter; | |
| 33 | |
| 34 /** | |
| 35 * Pending items of delete operation. | |
| 36 * | |
| 37 * Delete operations are usually complete quickly. | |
| 38 * So we would not like to show the progress bar at first. | |
| 39 * If the operation takes more than FileOperationHandler.PENDING_TIME_MS_, | |
| 40 * we adds the item to the progress center. | |
| 41 * | |
| 42 * @type {Object.<string, ProgressCenterItem>}} | |
| 43 * @private | |
| 44 */ | |
| 45 this.pendingItems_ = {}; | |
| 46 | |
| 47 // Register event. | |
| 48 this.fileOperationManager_.addEventListener( | |
| 49 'copy-progress', | |
| 50 this.onCopyProgress_.bind(this)); | |
| 51 this.fileOperationManager_.addEventListener( | |
| 52 'delete', | |
| 53 this.onDeleteProgress_.bind(this)); | |
| 54 | |
| 55 // Seal the object. | |
| 56 Object.seal(this); | |
| 57 }; | |
| 58 | |
| 59 /** | |
| 60 * Pending time before a delete item is added to the progress center. | |
| 61 * | |
| 62 * @type {number} | |
| 63 * @const | |
| 64 * @private | |
| 65 */ | |
| 66 FileOperationHandler.PENDING_TIME_MS_ = 500; | |
| 67 | |
| 68 /** | |
| 69 * Generate a progress message from the event. | |
| 70 * @param {Event} event Progress event. | |
| 71 * @return {string} message. | |
| 72 * @private | |
| 73 */ | |
| 74 FileOperationHandler.getMessage_ = function(event) { | |
| 75 if (event.reason === 'ERROR') { | |
| 76 switch (event.error.code) { | |
| 77 case util.FileOperationErrorType.TARGET_EXISTS: | |
| 78 var name = event.error.data.name; | |
| 79 if (event.error.data.isDirectory) | |
| 80 name += '/'; | |
| 81 switch (event.status.operationType) { | |
| 82 case 'COPY': return strf('COPY_TARGET_EXISTS_ERROR', name); | |
| 83 case 'MOVE': return strf('MOVE_TARGET_EXISTS_ERROR', name); | |
| 84 case 'ZIP': return strf('ZIP_TARGET_EXISTS_ERROR', name); | |
| 85 default: return strf('TRANSFER_TARGET_EXISTS_ERROR', name); | |
| 86 } | |
| 87 | |
| 88 case util.FileOperationErrorType.FILESYSTEM_ERROR: | |
| 89 var detail = util.getFileErrorString(event.error.data.name); | |
| 90 switch (event.status.operationType) { | |
| 91 case 'COPY': return strf('COPY_FILESYSTEM_ERROR', detail); | |
| 92 case 'MOVE': return strf('MOVE_FILESYSTEM_ERROR', detail); | |
| 93 case 'ZIP': return strf('ZIP_FILESYSTEM_ERROR', detail); | |
| 94 default: return strf('TRANSFER_FILESYSTEM_ERROR', detail); | |
| 95 } | |
| 96 | |
| 97 default: | |
| 98 switch (event.status.operationType) { | |
| 99 case 'COPY': return strf('COPY_UNEXPECTED_ERROR', event.error.code); | |
| 100 case 'MOVE': return strf('MOVE_UNEXPECTED_ERROR', event.error.code); | |
| 101 case 'ZIP': return strf('ZIP_UNEXPECTED_ERROR', event.error.code); | |
| 102 default: return strf('TRANSFER_UNEXPECTED_ERROR', event.error.code); | |
| 103 } | |
| 104 } | |
| 105 } else if (event.status.numRemainingItems === 1) { | |
| 106 var name = event.status.processingEntryName; | |
| 107 switch (event.status.operationType) { | |
| 108 case 'COPY': return strf('COPY_FILE_NAME', name); | |
| 109 case 'MOVE': return strf('MOVE_FILE_NAME', name); | |
| 110 case 'ZIP': return strf('ZIP_FILE_NAME', name); | |
| 111 default: return strf('TRANSFER_FILE_NAME', name); | |
| 112 } | |
| 113 } else { | |
| 114 var remainNumber = event.status.numRemainingItems; | |
| 115 switch (event.status.operationType) { | |
| 116 case 'COPY': return strf('COPY_ITEMS_REMAINING', remainNumber); | |
| 117 case 'MOVE': return strf('MOVE_ITEMS_REMAINING', remainNumber); | |
| 118 case 'ZIP': return strf('ZIP_ITEMS_REMAINING', remainNumber); | |
| 119 default: return strf('TRANSFER_ITEMS_REMAINING', remainNumber); | |
| 120 } | |
| 121 } | |
| 122 }; | |
| 123 | |
| 124 /** | |
| 125 * Generates a delete message from the event. | |
| 126 * @param {Event} event Progress event. | |
| 127 * @return {string} message. | |
| 128 * @private | |
| 129 */ | |
| 130 FileOperationHandler.getDeleteMessage_ = function(event) { | |
| 131 if (event.reason === 'ERROR') { | |
| 132 return str('DELETE_ERROR'); | |
| 133 } else if (event.entries.length == 1) { | |
| 134 var fileName = event.entries[0].name; | |
| 135 return strf('DELETE_FILE_NAME', fileName); | |
| 136 } else if (event.entries.length > 1) { | |
| 137 return strf('DELETE_ITEMS_REMAINING', event.entries.length); | |
| 138 } else { | |
| 139 return ''; | |
| 140 } | |
| 141 }; | |
| 142 | |
| 143 /** | |
| 144 * Obtains ProgressItemType from OperationType of FileTransferManager. | |
| 145 * @param {string} operationType OperationType of FileTransferManager. | |
| 146 * @return {ProgressItemType} ProgreeType corresponding to the specified | |
| 147 * operation type. | |
| 148 * @private | |
| 149 */ | |
| 150 FileOperationHandler.getType_ = function(operationType) { | |
| 151 switch (operationType) { | |
| 152 case 'COPY': return ProgressItemType.COPY; | |
| 153 case 'MOVE': return ProgressItemType.MOVE; | |
| 154 case 'ZIP': return ProgressItemType.ZIP; | |
| 155 default: | |
| 156 console.error('Unknown operation type.'); | |
| 157 return ProgressItemType.TRANSFER; | |
| 158 } | |
| 159 }; | |
| 160 | |
| 161 /** | |
| 162 * Handles the copy-progress event. | |
| 163 * @param {Event} event The copy-progress event. | |
| 164 * @private | |
| 165 */ | |
| 166 FileOperationHandler.prototype.onCopyProgress_ = function(event) { | |
| 167 // If the copy is finished, may be we can close the background page. | |
| 168 if (event.reason !== 'BEGIN' && event.reason !== 'PROGRESS') | |
| 169 this.background_.tryClose(); | |
| 170 | |
| 171 // Update progress center. | |
| 172 var progressCenter = this.progressCenter_; | |
| 173 var item; | |
| 174 switch (event.reason) { | |
| 175 case 'BEGIN': | |
| 176 item = new ProgressCenterItem(); | |
| 177 item.id = event.taskId; | |
| 178 item.type = FileOperationHandler.getType_(event.status.operationType); | |
| 179 item.message = FileOperationHandler.getMessage_(event); | |
| 180 item.progressMax = event.status.totalBytes; | |
| 181 item.progressValue = event.status.processedBytes; | |
| 182 item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind( | |
| 183 this.fileOperationManager_, | |
| 184 event.taskId); | |
| 185 progressCenter.updateItem(item); | |
| 186 break; | |
| 187 | |
| 188 case 'PROGRESS': | |
| 189 item = progressCenter.getItemById(event.taskId); | |
| 190 if (!item) { | |
| 191 console.error('Cannot find copying item.'); | |
| 192 return; | |
| 193 } | |
| 194 item.message = FileOperationHandler.getMessage_(event); | |
| 195 item.progressValue = event.status.processedBytes; | |
| 196 progressCenter.updateItem(item); | |
| 197 break; | |
| 198 | |
| 199 case 'SUCCESS': | |
| 200 case 'CANCELED': | |
| 201 case 'ERROR': | |
| 202 item = progressCenter.getItemById(event.taskId); | |
| 203 if (!item) { | |
| 204 // ERROR events can be dispatched before BEGIN events. | |
| 205 item = new ProgressCenterItem(); | |
| 206 item.type = FileOperationHandler.getType_(event.status.operationType); | |
| 207 item.id = event.taskId; | |
| 208 item.progressMax = 1; | |
| 209 } | |
| 210 if (event.reason === 'SUCCESS') { | |
| 211 item.message = ''; | |
| 212 item.state = ProgressItemState.COMPLETED; | |
| 213 item.progressValue = item.progressMax; | |
| 214 } else if (event.reason === 'CANCELED') { | |
| 215 item.message = ''; | |
| 216 item.state = ProgressItemState.CANCELED; | |
| 217 } else { | |
| 218 item.message = FileOperationHandler.getMessage_(event); | |
| 219 item.state = ProgressItemState.ERROR; | |
| 220 } | |
| 221 progressCenter.updateItem(item); | |
| 222 break; | |
| 223 } | |
| 224 }; | |
| 225 | |
| 226 /** | |
| 227 * Handles the delete event. | |
| 228 * @param {Event} event The delete event. | |
| 229 * @private | |
| 230 */ | |
| 231 FileOperationHandler.prototype.onDeleteProgress_ = function(event) { | |
| 232 // If the copy is finished, may be we can close the background page. | |
| 233 if (event.reason !== 'BEGIN' && event.reason !== 'PROGRESS') | |
| 234 this.background_.tryClose(); | |
| 235 | |
| 236 // Update progress center. | |
| 237 var progressCenter = this.progressCenter_; | |
| 238 var item; | |
| 239 var pending; | |
| 240 switch (event.reason) { | |
| 241 case 'BEGIN': | |
| 242 item = new ProgressCenterItem(); | |
| 243 item.id = event.taskId; | |
| 244 item.type = ProgressItemType.DELETE; | |
| 245 item.message = FileOperationHandler.getDeleteMessage_(event); | |
| 246 item.progressMax = event.totalBytes; | |
| 247 item.progressValue = event.processedBytes; | |
| 248 item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind( | |
| 249 this.fileOperationManager_, | |
| 250 event.taskId); | |
| 251 this.pendingItems_[item.id] = item; | |
| 252 setTimeout(this.showPendingItem_.bind(this, item), | |
| 253 FileOperationHandler.PENDING_TIME_MS_); | |
| 254 break; | |
| 255 | |
| 256 case 'PROGRESS': | |
| 257 pending = event.taskId in this.pendingItems_; | |
| 258 item = this.pendingItems_[event.taskId] || | |
| 259 progressCenter.getItemById(event.taskId); | |
| 260 if (!item) { | |
| 261 console.error('Cannot find deleting item.'); | |
| 262 return; | |
| 263 } | |
| 264 item.message = FileOperationHandler.getDeleteMessage_(event); | |
| 265 item.progressMax = event.totalBytes; | |
| 266 item.progressValue = event.processedBytes; | |
| 267 if (!pending) | |
| 268 progressCenter.updateItem(item); | |
| 269 break; | |
| 270 | |
| 271 case 'SUCCESS': | |
| 272 case 'CANCELED': | |
| 273 case 'ERROR': | |
| 274 // Obtain working variable. | |
| 275 pending = event.taskId in this.pendingItems_; | |
| 276 item = this.pendingItems_[event.taskId] || | |
| 277 progressCenter.getItemById(event.taskId); | |
| 278 if (!item) { | |
| 279 console.error('Cannot find deleting item.'); | |
| 280 return; | |
| 281 } | |
| 282 | |
| 283 // Update the item. | |
| 284 item.message = FileOperationHandler.getDeleteMessage_(event); | |
| 285 if (event.reason === 'SUCCESS') { | |
| 286 item.state = ProgressItemState.COMPLETED; | |
| 287 item.progressValue = item.progressMax; | |
| 288 } else if (event.reason === 'CANCELED') { | |
| 289 item.state = ProgressItemState.CANCELED; | |
| 290 } else { | |
| 291 item.state = ProgressItemState.ERROR; | |
| 292 } | |
| 293 | |
| 294 // Apply the change. | |
| 295 if (!pending || event.reason === 'ERROR') | |
| 296 progressCenter.updateItem(item); | |
| 297 if (pending) | |
| 298 delete this.pendingItems_[event.taskId]; | |
| 299 break; | |
| 300 } | |
| 301 }; | |
| 302 | |
| 303 /** | |
| 304 * Shows the pending item. | |
| 305 * | |
| 306 * @param {ProgressCenterItem} item Pending item. | |
| 307 * @private | |
| 308 */ | |
| 309 FileOperationHandler.prototype.showPendingItem_ = function(item) { | |
| 310 // The item is already gone. | |
| 311 if (!this.pendingItems_[item.id]) | |
| 312 return; | |
| 313 delete this.pendingItems_[item.id]; | |
| 314 this.progressCenter_.updateItem(item); | |
| 315 }; | |
| OLD | NEW |