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 |