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.
8 * An event handler of the background page for file operations.
9 * @param {Background} background Background page.
12 var FileOperationHandler = function(background) {
18 this.background_ = background;
21 * File operation manager.
22 * @type {FileOperationManager}
25 this.fileOperationManager_ = background.fileOperationManager;
29 * @type {progressCenter}
32 this.progressCenter_ = background.progressCenter;
35 * Pending items of delete operation.
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.
42 * @type {Object.<string, ProgressCenterItem>}}
45 this.pendingItems_ = {};
48 this.fileOperationManager_.addEventListener(
50 this.onCopyProgress_.bind(this));
51 this.fileOperationManager_.addEventListener(
53 this.onDeleteProgress_.bind(this));
60 * Pending time before a delete item is added to the progress center.
66 FileOperationHandler.PENDING_TIME_MS_ = 500;
69 * Generate a progress message from the event.
70 * @param {Event} event Progress event.
71 * @return {string} message.
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)
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);
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);
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);
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);
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);
125 * Generates a delete message from the event.
126 * @param {Event} event Progress event.
127 * @return {string} message.
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);
144 * Obtains ProgressItemType from OperationType of FileTransferManager.
145 * @param {string} operationType OperationType of FileTransferManager.
146 * @return {ProgressItemType} ProgreeType corresponding to the specified
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;
156 console.error('Unknown operation type.');
157 return ProgressItemType.TRANSFER;
162 * Handles the copy-progress event.
163 * @param {Event} event The copy-progress event.
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();
171 // Update progress center.
172 var progressCenter = this.progressCenter_;
174 switch (event.reason) {
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_,
185 progressCenter.updateItem(item);
189 item = progressCenter.getItemById(event.taskId);
191 console.error('Cannot find copying item.');
194 item.message = FileOperationHandler.getMessage_(event);
195 item.progressValue = event.status.processedBytes;
196 progressCenter.updateItem(item);
202 item = progressCenter.getItemById(event.taskId);
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;
210 if (event.reason === 'SUCCESS') {
212 item.state = ProgressItemState.COMPLETED;
213 item.progressValue = item.progressMax;
214 } else if (event.reason === 'CANCELED') {
216 item.state = ProgressItemState.CANCELED;
218 item.message = FileOperationHandler.getMessage_(event);
219 item.state = ProgressItemState.ERROR;
221 progressCenter.updateItem(item);
227 * Handles the delete event.
228 * @param {Event} event The delete event.
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();
236 // Update progress center.
237 var progressCenter = this.progressCenter_;
240 switch (event.reason) {
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_,
251 this.pendingItems_[item.id] = item;
252 setTimeout(this.showPendingItem_.bind(this, item),
253 FileOperationHandler.PENDING_TIME_MS_);
257 pending = event.taskId in this.pendingItems_;
258 item = this.pendingItems_[event.taskId] ||
259 progressCenter.getItemById(event.taskId);
261 console.error('Cannot find deleting item.');
264 item.message = FileOperationHandler.getDeleteMessage_(event);
265 item.progressMax = event.totalBytes;
266 item.progressValue = event.processedBytes;
268 progressCenter.updateItem(item);
274 // Obtain working variable.
275 pending = event.taskId in this.pendingItems_;
276 item = this.pendingItems_[event.taskId] ||
277 progressCenter.getItemById(event.taskId);
279 console.error('Cannot find deleting 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;
291 item.state = ProgressItemState.ERROR;
295 if (!pending || event.reason === 'ERROR')
296 progressCenter.updateItem(item);
298 delete this.pendingItems_[event.taskId];
304 * Shows the pending item.
306 * @param {ProgressCenterItem} item Pending item.
309 FileOperationHandler.prototype.showPendingItem_ = function(item) {
310 // The item is already gone.
311 if (!this.pendingItems_[item.id])
313 delete this.pendingItems_[item.id];
314 this.progressCenter_.updateItem(item);