Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(512)

Side by Side Diff: chrome/browser/resources/file_manager/js/file_copy_manager.js

Issue 9652024: Only show progress bar after 500ms (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Address Rick's review. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 function FileCopyManager() { 5 function FileCopyManager() {
6 this.copyTasks_ = []; 6 this.copyTasks_ = [];
7 this.cancelObservers_ = []; 7 this.cancelObservers_ = [];
8 this.cancelRequested_ = false; 8 this.cancelRequested_ = false;
9 } 9 }
10 10
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 self.pendingDirectories = result.dirEntries; 49 self.pendingDirectories = result.dirEntries;
50 self.pendingFiles = result.fileEntries; 50 self.pendingFiles = result.fileEntries;
51 self.pendingBytes = result.fileBytes; 51 self.pendingBytes = result.fileBytes;
52 callback(); 52 callback();
53 } 53 }
54 54
55 this.originalEntries = entries; 55 this.originalEntries = entries;
56 util.recurseAndResolveEntries(entries, onEntriesRecursed); 56 util.recurseAndResolveEntries(entries, onEntriesRecursed);
57 } 57 }
58 58
59 FileCopyManager.Task.prototype.takeNextEntry = function() { 59 FileCopyManager.Task.prototype.getNextEntry = function() {
60 // We should keep the file in pending list and remove it after complete.
61 // Otherwise, if we try to get status in the middle of copying. The returned
62 // status is wrong (miss count the pasting item in totalItems).
60 if (this.pendingDirectories.length) 63 if (this.pendingDirectories.length)
61 return this.pendingDirectories.shift(); 64 return this.pendingDirectories[0];
62 65
63 if (this.pendingFiles.length) 66 if (this.pendingFiles.length)
64 return this.pendingFiles.shift(); 67 return this.pendingFiles[0];
65 68
66 return null; 69 return null;
67 }; 70 };
68 71
69 FileCopyManager.Task.prototype.markEntryComplete = function(entry, size) { 72 FileCopyManager.Task.prototype.markEntryComplete = function(entry, size) {
70 if (entry.isDirectory) { 73 if (entry.isDirectory) {
71 this.completedDirectories.push(entry); 74 this.completedDirectories.push(entry);
75 this.pendingDirectories.shift();
72 } else { 76 } else {
73 this.completedFiles.push(entry); 77 this.completedFiles.push(entry);
74 this.completedBytes += size; 78 this.completedBytes += size;
79 this.pendingFiles.shift();
75 } 80 }
76 }; 81 };
77 82
78 FileCopyManager.Task.prototype.registerRename = function(fromName, toName) { 83 FileCopyManager.Task.prototype.registerRename = function(fromName, toName) {
79 this.renamedDirectories_.push({from: fromName + '/', to: toName + '/'}); 84 this.renamedDirectories_.push({from: fromName + '/', to: toName + '/'});
80 }; 85 };
81 86
82 FileCopyManager.Task.prototype.applyRenames = function(path) { 87 FileCopyManager.Task.prototype.applyRenames = function(path) {
83 // Directories are processed in pre-order, so we will store only the first 88 // Directories are processed in pre-order, so we will store only the first
84 // renaming point: 89 // renaming point:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 completedFiles: 0, 127 completedFiles: 0,
123 completedDirectories: 0, 128 completedDirectories: 0,
124 completedBytes: 0 129 completedBytes: 0
125 }; 130 };
126 131
127 for (var i = 0; i < this.copyTasks_.length; i++) { 132 for (var i = 0; i < this.copyTasks_.length; i++) {
128 var task = this.copyTasks_[i]; 133 var task = this.copyTasks_[i];
129 rv.pendingFiles += task.pendingFiles.length; 134 rv.pendingFiles += task.pendingFiles.length;
130 rv.pendingDirectories += task.pendingDirectories.length; 135 rv.pendingDirectories += task.pendingDirectories.length;
131 rv.pendingBytes += task.pendingBytes; 136 rv.pendingBytes += task.pendingBytes;
132 rv.pendingItems += rv.pendingFiles + rv.pendingDirectories;
133 137
134 rv.completedFiles += task.completedFiles.length; 138 rv.completedFiles += task.completedFiles.length;
135 rv.completedDirectories += task.completedDirectories.length; 139 rv.completedDirectories += task.completedDirectories.length;
136 rv.completedBytes += task.completedBytes; 140 rv.completedBytes += task.completedBytes;
137 rv.completedItems += rv.completedFiles + rv.completedDirectories;
138
139 } 141 }
142 rv.pendingItems = rv.pendingFiles + rv.pendingDirectories;
143 rv.completedItems = rv.completedFiles + rv.completedDirectories;
140 144
141 rv.totalFiles = rv.pendingFiles + rv.completedFiles; 145 rv.totalFiles = rv.pendingFiles + rv.completedFiles;
142 rv.totalDirectories = rv.pendingDirectories + rv.completedDirectories; 146 rv.totalDirectories = rv.pendingDirectories + rv.completedDirectories;
143 rv.totalItems = rv.pendingItems + rv.completedItems; 147 rv.totalItems = rv.pendingItems + rv.completedItems;
144 rv.totalBytes = rv.pendingBytes + rv.completedBytes; 148 rv.totalBytes = rv.pendingBytes + rv.completedBytes;
145 149
146 return rv; 150 return rv;
147 }; 151 };
148 152
153 FileCopyManager.prototype.getProgress = function() {
Rick Byers 2012/03/12 14:20:08 Since this is a public function you should have a
bshe 2012/03/12 16:41:19 Done.
154 var status = this.getStatus();
155 var result = {
Rick Byers 2012/03/12 14:20:08 No need to create a variable and initializing to 0
bshe 2012/03/12 16:41:19 Done.
156 percentage: 0,
157 pendingItems: 0
158 };
159
160 // TODO(bshe): Need to figure out a way to get completed bytes in real
161 // time. We currently use completedItems and totalItems to estimate the
162 // progress. There are completeBytes and totalBytes ready to use.
163 // However, the completedBytes is not in real time. It only updates
164 // itself after each item finished. So if there is a large item to
165 // copy, the progress bar will stop moving until it finishes and jump
166 // a large portion of the bar.
167 // There is case that when user copy a large file, we want to show an
168 // 100% animated progress bar. So we use completedItems + 1 here.
169 result.percentage = (status.completedItems + 1) / status.totalItems;
170
171 result.pendingItems = status.pendingItems;
172 return result;
173 };
174
149 /** 175 /**
150 * Completely clear out the copy queue, either because we encountered an error 176 * Completely clear out the copy queue, either because we encountered an error
151 * or completed successfully. 177 * or completed successfully.
152 */ 178 */
153 FileCopyManager.prototype.resetQueue_ = function() { 179 FileCopyManager.prototype.resetQueue_ = function() {
154 for (var i = 0; i < this.cancelObservers_.length; i++) 180 for (var i = 0; i < this.cancelObservers_.length; i++)
155 this.cancelObservers_[i](); 181 this.cancelObservers_[i]();
156 182
157 this.copyTasks_ = []; 183 this.copyTasks_ = [];
158 this.cancelObservers_ = []; 184 this.cancelObservers_ = [];
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 entries, 290 entries,
265 deleteAfterCopy) { 291 deleteAfterCopy) {
266 var self = this; 292 var self = this;
267 var copyTask = new FileCopyManager.Task(sourceDirEntry, targetDirEntry); 293 var copyTask = new FileCopyManager.Task(sourceDirEntry, targetDirEntry);
268 copyTask.deleteAfterCopy = deleteAfterCopy; 294 copyTask.deleteAfterCopy = deleteAfterCopy;
269 copyTask.setEntries(entries, function() { 295 copyTask.setEntries(entries, function() {
270 self.copyTasks_.push(copyTask); 296 self.copyTasks_.push(copyTask);
271 if (self.copyTasks_.length == 1) { 297 if (self.copyTasks_.length == 1) {
272 // This moved us from 0 to 1 active tasks, let the servicing begin! 298 // This moved us from 0 to 1 active tasks, let the servicing begin!
273 self.serviceAllTasks_(); 299 self.serviceAllTasks_();
300 } else {
301 // Force to update the progress of butter bar when there are new tasks
302 // coming while servicing current task.
303 var event = new cr.Event('copy-progress');
304 event.reason = 'PROGRESS';
305 self.dispatchEvent(event);
274 } 306 }
275 }); 307 });
276 308
277 return copyTask; 309 return copyTask;
278 }; 310 };
279 311
280 /** 312 /**
281 * Service all pending tasks, as well as any that might appear during the 313 * Service all pending tasks, as well as any that might appear during the
282 * copy. 314 * copy.
283 */ 315 */
284 FileCopyManager.prototype.serviceAllTasks_ = function() { 316 FileCopyManager.prototype.serviceAllTasks_ = function() {
285 var self = this; 317 var self = this;
286 318
287 function onTaskError(err) { 319 function onTaskError(err) {
288 var event = new cr.Event('copy-progress'); 320 var event = new cr.Event('copy-progress');
289 event.reason = 'ERROR'; 321 event.reason = 'ERROR';
290 event.error = err; 322 event.error = err;
291 self.dispatchEvent(event); 323 self.dispatchEvent(event);
292 self.resetQueue_(); 324 self.resetQueue_();
293 } 325 }
294 326
295 function onTaskSuccess(task) { 327 function onTaskSuccess(task) {
296 if (task == null) { 328 if (!self.copyTasks_.length) {
297 // All tasks have been serviced, clean up and exit. 329 // All tasks have been serviced, clean up and exit.
298 var event = new cr.Event('copy-progress'); 330 var event = new cr.Event('copy-progress');
299 event.reason = 'SUCCESS'; 331 event.reason = 'SUCCESS';
300 self.dispatchEvent(event); 332 self.dispatchEvent(event);
301 self.resetQueue_(); 333 self.resetQueue_();
302 return; 334 return;
303 } 335 }
304 336
337 // We want to dispatch a PROGRESS event when there are more tasks to serve
338 // right after one task finished in the queue. We treat all tasks as one
339 // big task logically, so there is only one BEGIN/SUCCESS event pair for
340 // these continuous tasks.
341 var event = new cr.Event('copy-progress');
342 event.reason = 'PROGRESS';
343 self.dispatchEvent(event);
Rick Byers 2012/03/12 14:20:08 Probably worth encapsulating these 3 lines in a si
bshe 2012/03/12 16:41:19 Done.
344
305 self.serviceNextTask_(onTaskSuccess, onTaskError); 345 self.serviceNextTask_(onTaskSuccess, onTaskError);
306 } 346 }
307 347
308 // If the queue size is 1 after pushing our task, it was empty before, 348 // If the queue size is 1 after pushing our task, it was empty before,
309 // so we need to kick off queue processing. 349 // so we need to kick off queue processing and dispatch BEGIN event.
350
351 var event = new cr.Event('copy-progress');
352 event.reason = 'BEGIN';
353 this.dispatchEvent(event);
310 this.serviceNextTask_(onTaskSuccess, onTaskError); 354 this.serviceNextTask_(onTaskSuccess, onTaskError);
311 }; 355 };
312 356
313 /** 357 /**
314 * Service all entries in the next copy task. 358 * Service all entries in the next copy task.
315 */ 359 */
316 FileCopyManager.prototype.serviceNextTask_ = function( 360 FileCopyManager.prototype.serviceNextTask_ = function(
317 successCallback, errorCallback) { 361 successCallback, errorCallback) {
318 if (this.maybeCancel_()) 362 if (this.maybeCancel_())
319 return; 363 return;
320 364
321 if (!this.copyTasks_.length) {
322 successCallback(null);
323 return;
324 }
325
326 var self = this; 365 var self = this;
327 var task = this.copyTasks_[0]; 366 var task = this.copyTasks_[0];
328 367
329 function onFilesystemError(err) { 368 function onFilesystemError(err) {
330 errorCallback(new FileCopyManager.Error('FILESYSTEM_ERROR', err)); 369 errorCallback(new FileCopyManager.Error('FILESYSTEM_ERROR', err));
331 } 370 }
332 371
333 function onTaskComplete() { 372 function onTaskComplete() {
334 self.copyTasks_.shift(); 373 self.copyTasks_.shift();
335 successCallback(task); 374 successCallback(task);
336 } 375 }
337 376
338 function deleteOriginals() { 377 function deleteOriginals() {
339 var count = task.originalEntries.length; 378 var count = task.originalEntries.length;
340 379
341 function onEntryDeleted() { 380 function onEntryDeleted() {
342 count--; 381 count--;
343 if (!count) 382 if (!count)
344 onTaskComplete(); 383 onTaskComplete();
345 } 384 }
346 385
347 for (var i = 0; i < task.originalEntries.length; i++) { 386 for (var i = 0; i < task.originalEntries.length; i++) {
348 util.removeFileOrDirectory( 387 util.removeFileOrDirectory(
349 task.originalEntries[i], onEntryDeleted, onFilesystemError); 388 task.originalEntries[i], onEntryDeleted, onFilesystemError);
350 } 389 }
351 } 390 }
352 391
353 function onEntryServiced(targetEntry, size) { 392 function onEntryServiced(targetEntry, size) {
354 if (!targetEntry) { 393 // We should not dispatch a PROGRESS event when there is no pending items
394 // in the task.
395 if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
355 // All done with the entries in this task. 396 // All done with the entries in this task.
356 if (task.deleteAfterCopy) { 397 if (task.deleteAfterCopy) {
357 deleteOriginals() 398 deleteOriginals()
358 } else { 399 } else {
359 onTaskComplete(); 400 onTaskComplete();
360 } 401 }
361 return; 402 return;
362 } 403 }
363 404
364 var event = new cr.Event('copy-progress'); 405 var event = new cr.Event('copy-progress');
365 event.reason = 'PROGRESS'; 406 event.reason = 'PROGRESS';
366 self.dispatchEvent(event); 407 self.dispatchEvent(event);
367 408
368 // We yield a few ms between copies to give the browser a chance to service 409 // We yield a few ms between copies to give the browser a chance to service
369 // events (like perhaps the user clicking to cancel the copy, for example). 410 // events (like perhaps the user clicking to cancel the copy, for example).
370 setTimeout(function() { 411 setTimeout(function() {
371 self.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); 412 self.serviceNextTaskEntry_(task, onEntryServiced, errorCallback);
372 }, 10); 413 }, 10);
373 } 414 }
374 415
375 var event = new cr.Event('copy-progress');
376 event.reason = 'BEGIN';
377 this.dispatchEvent(event);
378 this.serviceNextTaskEntry_(task, onEntryServiced, errorCallback); 416 this.serviceNextTaskEntry_(task, onEntryServiced, errorCallback);
379 } 417 }
380 418
381 /** 419 /**
382 * Service the next entry in a given task. 420 * Service the next entry in a given task.
383 */ 421 */
384 FileCopyManager.prototype.serviceNextTaskEntry_ = function( 422 FileCopyManager.prototype.serviceNextTaskEntry_ = function(
385 task, successCallback, errorCallback) { 423 task, successCallback, errorCallback) {
386 if (this.maybeCancel_()) 424 if (this.maybeCancel_())
387 return; 425 return;
388 426
389 var self = this; 427 var self = this;
390 var sourceEntry = task.takeNextEntry(); 428 var sourceEntry = task.getNextEntry();
391 429
392 if (!sourceEntry) { 430 if (!sourceEntry) {
393 // All entries in this task have been copied. 431 // All entries in this task have been copied.
394 successCallback(null); 432 successCallback(null);
395 return; 433 return;
396 } 434 }
397 435
398 var sourcePath = task.sourceDirEntry.fullPath; 436 var sourcePath = task.sourceDirEntry.fullPath;
399 if (sourceEntry.fullPath.substr(0, sourcePath.length) != sourcePath) { 437 if (sourceEntry.fullPath.substr(0, sourcePath.length) != sourcePath) {
400 // We found an entry in the list that is not relative to the base source 438 // We found an entry in the list that is not relative to the base source
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 onFilesystemError)); 513 onFilesystemError));
476 } else { 514 } else {
477 targetDirEntry.getFile( 515 targetDirEntry.getFile(
478 targetRelativePath, 516 targetRelativePath,
479 {create: true, exclusive: true}, 517 {create: true, exclusive: true},
480 function(targetEntry) { 518 function(targetEntry) {
481 self.copyEntry_(sourceEntry, targetEntry, 519 self.copyEntry_(sourceEntry, targetEntry,
482 onCopyComplete, onError); 520 onCopyComplete, onError);
483 }, 521 },
484 util.flog('Error getting file: ' + targetRelativePath, 522 util.flog('Error getting file: ' + targetRelativePath,
485 onFilesystemError)); 523 onFilesystemError));
Rick Byers 2012/03/12 14:20:08 Remove added extra space
bshe 2012/03/12 16:41:19 Done.
486 } 524 }
487 } 525 }
488 526
489 function tryNextCopy() { 527 function tryNextCopy() {
490 targetRelativePath = targetRelativePrefix; 528 targetRelativePath = targetRelativePrefix;
491 if (copyNumber > 0) { 529 if (copyNumber > 0) {
492 targetRelativePath += ' (' + copyNumber + ')'; 530 targetRelativePath += ' (' + copyNumber + ')';
493 } 531 }
494 targetRelativePath += targetExt; 532 targetRelativePath += targetExt;
495 533
(...skipping 23 matching lines...) Expand all
519 successCallback(targetEntry, file.size) 557 successCallback(targetEntry, file.size)
520 }; 558 };
521 writer.write(file); 559 writer.write(file);
522 } 560 }
523 561
524 targetEntry.createWriter(onWriterCreated, errorCallback); 562 targetEntry.createWriter(onWriterCreated, errorCallback);
525 } 563 }
526 564
527 sourceEntry.file(onSourceFileFound, errorCallback); 565 sourceEntry.file(onSourceFileFound, errorCallback);
528 }; 566 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698