Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / file_manager / background / js / file_operation_handler.js
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 };