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

Side by Side Diff: ui/file_manager/file_manager/foreground/js/directory_model.js

Issue 312493002: Files.app: Fix flakiness in chaining directory (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 'use strict'; 5 'use strict';
6 6
7 // If directory files changes too often, don't rescan directory more than once 7 // If directory files changes too often, don't rescan directory more than once
8 // per specified interval 8 // per specified interval
9 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; 9 var SIMULTANEOUS_RESCAN_INTERVAL = 1000;
10 // Used for operations that require almost instant rescan. 10 // Used for operations that require almost instant rescan.
(...skipping 14 matching lines...) Expand all
25 metadataCache, volumeManager) { 25 metadataCache, volumeManager) {
26 this.fileListSelection_ = singleSelection ? 26 this.fileListSelection_ = singleSelection ?
27 new cr.ui.ListSingleSelectionModel() : new cr.ui.ListSelectionModel(); 27 new cr.ui.ListSingleSelectionModel() : new cr.ui.ListSelectionModel();
28 28
29 this.runningScan_ = null; 29 this.runningScan_ = null;
30 this.pendingScan_ = null; 30 this.pendingScan_ = null;
31 this.rescanTime_ = null; 31 this.rescanTime_ = null;
32 this.scanFailures_ = 0; 32 this.scanFailures_ = 0;
33 this.changeDirectorySequence_ = 0; 33 this.changeDirectorySequence_ = 0;
34 34
35 this.directoryChangeQueue_ = new AsyncUtil.Queue();
36
35 this.fileFilter_ = fileFilter; 37 this.fileFilter_ = fileFilter;
36 this.fileFilter_.addEventListener('changed', 38 this.fileFilter_.addEventListener('changed',
37 this.onFilterChanged_.bind(this)); 39 this.onFilterChanged_.bind(this));
38 40
39 this.currentFileListContext_ = new FileListContext( 41 this.currentFileListContext_ = new FileListContext(
40 fileFilter, metadataCache); 42 fileFilter, metadataCache);
41 this.currentDirContents_ = 43 this.currentDirContents_ =
42 DirectoryContents.createForDirectory(this.currentFileListContext_, null); 44 DirectoryContents.createForDirectory(this.currentFileListContext_, null);
43 45
44 this.metadataCache_ = metadataCache; 46 this.metadataCache_ = metadataCache;
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 * a single refresh. 273 * a single refresh.
272 * @param {number} delay Delay in ms after which the rescan will be performed. 274 * @param {number} delay Delay in ms after which the rescan will be performed.
273 */ 275 */
274 DirectoryModel.prototype.scheduleRescan = function(delay) { 276 DirectoryModel.prototype.scheduleRescan = function(delay) {
275 if (this.rescanTime_) { 277 if (this.rescanTime_) {
276 if (this.rescanTime_ <= Date.now() + delay) 278 if (this.rescanTime_ <= Date.now() + delay)
277 return; 279 return;
278 clearTimeout(this.rescanTimeoutId_); 280 clearTimeout(this.rescanTimeoutId_);
279 } 281 }
280 282
283 var tracker = this.createDirectoryChangeTracker();
hirono 2014/06/02 09:18:03 It looks tracker does not detect starting search,
yoshiki 2014/06/02 11:37:11 Good catch. search should be detected, since it ch
284 tracker.start();
285
281 this.rescanTime_ = Date.now() + delay; 286 this.rescanTime_ = Date.now() + delay;
282 this.rescanTimeoutId_ = setTimeout(this.rescan.bind(this), delay); 287 this.rescanTimeoutId_ = setTimeout(function() {
288 this.rescanTimeoutId_ = null;
289 tracker.stop();
290 if (!tracker.hasChanged)
291 this.rescan();
292 }.bind(this), delay);
283 }; 293 };
284 294
285 /** 295 /**
286 * Cancel a rescan on timeout if it is scheduled. 296 * Cancel a rescan on timeout if it is scheduled.
287 * @private 297 * @private
288 */ 298 */
289 DirectoryModel.prototype.clearRescanTimeout_ = function() { 299 DirectoryModel.prototype.clearRescanTimeout_ = function() {
290 this.rescanTime_ = null; 300 this.rescanTime_ = null;
291 if (this.rescanTimeoutId_) { 301 if (this.rescanTimeoutId_) {
292 clearTimeout(this.rescanTimeoutId_); 302 clearTimeout(this.rescanTimeoutId_);
(...skipping 12 matching lines...) Expand all
305 DirectoryModel.prototype.rescan = function() { 315 DirectoryModel.prototype.rescan = function() {
306 this.clearRescanTimeout_(); 316 this.clearRescanTimeout_();
307 if (this.runningScan_) { 317 if (this.runningScan_) {
308 this.pendingRescan_ = true; 318 this.pendingRescan_ = true;
309 return; 319 return;
310 } 320 }
311 321
312 var dirContents = this.currentDirContents_.clone(); 322 var dirContents = this.currentDirContents_.clone();
313 dirContents.setFileList([]); 323 dirContents.setFileList([]);
314 324
325 var tracker = this.createDirectoryChangeTracker();
326 tracker.start();
327
315 var successCallback = (function() { 328 var successCallback = (function() {
316 this.replaceDirectoryContents_(dirContents); 329 tracker.stop();
330 if (!tracker.hasChanged)
331 this.replaceDirectoryContents_(dirContents);
317 cr.dispatchSimpleEvent(this, 'rescan-completed'); 332 cr.dispatchSimpleEvent(this, 'rescan-completed');
318 }).bind(this); 333 }).bind(this);
319 334
320 this.scan_(dirContents, 335 this.scan_(dirContents,
321 successCallback, function() {}, function() {}, function() {}); 336 successCallback, function() {}, function() {}, function() {});
322 }; 337 };
323 338
324 /** 339 /**
325 * Run scan on the current DirectoryContents. The active fileList is cleared and 340 * Run scan on the current DirectoryContents. The active fileList is cleared and
326 * the entries are added directly. 341 * the entries are added directly.
327 * 342 *
328 * This should be used when changing directory or initiating a new search. 343 * This should be used when changing directory or initiating a new search.
329 * 344 *
330 * @param {DirectoryContentes} newDirContents New DirectoryContents instance to 345 * @param {DirectoryContentes} newDirContents New DirectoryContents instance to
331 * replace currentDirContents_. 346 * replace currentDirContents_.
332 * @param {function()=} opt_callback Called on success. 347 * @param {function()} callback Callback.
hirono 2014/06/02 09:18:03 Boolean is needed as an argument?
yoshiki 2014/06/02 11:37:11 Done.
333 * @private 348 * @private
334 */ 349 */
335 DirectoryModel.prototype.clearAndScan_ = function(newDirContents, 350 DirectoryModel.prototype.clearAndScan_ = function(newDirContents,
336 opt_callback) { 351 callback) {
337 if (this.currentDirContents_.isScanning()) 352 if (this.currentDirContents_.isScanning())
338 this.currentDirContents_.cancelScan(); 353 this.currentDirContents_.cancelScan();
339 this.currentDirContents_ = newDirContents; 354 this.currentDirContents_ = newDirContents;
340 this.clearRescanTimeout_(); 355 this.clearRescanTimeout_();
341 356
342 if (this.pendingScan_) 357 if (this.pendingScan_)
343 this.pendingScan_ = false; 358 this.pendingScan_ = false;
344 359
345 if (this.runningScan_) { 360 if (this.runningScan_) {
346 if (this.runningScan_.isScanning()) 361 if (this.runningScan_.isScanning())
347 this.runningScan_.cancelScan(); 362 this.runningScan_.cancelScan();
348 this.runningScan_ = null; 363 this.runningScan_ = null;
349 } 364 }
350 365
366 var sequence = this.changeDirectorySequence_;
367 var cancelled = false;
368
351 var onDone = function() { 369 var onDone = function() {
370 if (cancelled)
371 return;
372
352 cr.dispatchSimpleEvent(this, 'scan-completed'); 373 cr.dispatchSimpleEvent(this, 'scan-completed');
353 if (opt_callback) 374 callback(true);
354 opt_callback();
355 }.bind(this); 375 }.bind(this);
356 376
357 var onFailed = function() { 377 var onFailed = function() {
378 if (cancelled)
379 return;
380
358 cr.dispatchSimpleEvent(this, 'scan-failed'); 381 cr.dispatchSimpleEvent(this, 'scan-failed');
382 callback(false);
359 }.bind(this); 383 }.bind(this);
360 384
361 var onUpdated = function() { 385 var onUpdated = function() {
386 if (cancelled)
387 return;
388
389 if (this.changeDirectorySequence_ !== sequence) {
390 cancelled = true;
391 cr.dispatchSimpleEvent(this, 'scan-cancelled');
392 callback(false);
393 return;
394 }
395
362 cr.dispatchSimpleEvent(this, 'scan-updated'); 396 cr.dispatchSimpleEvent(this, 'scan-updated');
363 }.bind(this); 397 }.bind(this);
364 398
365 var onCancelled = function() { 399 var onCancelled = function() {
400 if (cancelled)
401 return;
402
403 cancelled = true;
366 cr.dispatchSimpleEvent(this, 'scan-cancelled'); 404 cr.dispatchSimpleEvent(this, 'scan-cancelled');
405 callback(false);
367 }.bind(this); 406 }.bind(this);
368 407
369 // Clear the table, and start scanning. 408 // Clear the table, and start scanning.
370 cr.dispatchSimpleEvent(this, 'scan-started'); 409 cr.dispatchSimpleEvent(this, 'scan-started');
371 var fileList = this.getFileList(); 410 var fileList = this.getFileList();
372 fileList.splice(0, fileList.length); 411 fileList.splice(0, fileList.length);
373 this.scan_(this.currentDirContents_, 412 this.scan_(this.currentDirContents_,
374 onDone, onFailed, onUpdated, onCancelled); 413 onDone, onFailed, onUpdated, onCancelled);
375 }; 414 };
376 415
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 * be opened. 700 * be opened.
662 * @param {function()=} opt_callback Executed if the directory loads 701 * @param {function()=} opt_callback Executed if the directory loads
663 * successfully. 702 * successfully.
664 */ 703 */
665 DirectoryModel.prototype.changeDirectoryEntry = function( 704 DirectoryModel.prototype.changeDirectoryEntry = function(
666 dirEntry, opt_callback) { 705 dirEntry, opt_callback) {
667 // Increment the sequence value. 706 // Increment the sequence value.
668 this.changeDirectorySequence_++; 707 this.changeDirectorySequence_++;
669 this.clearSearch_(); 708 this.clearSearch_();
670 709
671 var promise = new Promise( 710 this.directoryChangeQueue_.run(function(sequence, callback) {
hirono 2014/06/02 09:18:03 Maybe more specific name is needed for callback, s
yoshiki 2014/06/02 11:37:11 Done.
672 function(onFulfilled, onRejected) { 711 this.fileWatcher_.changeWatchedDirectory(
673 this.fileWatcher_.changeWatchedDirectory(dirEntry, onFulfilled); 712 dirEntry,
674 }.bind(this)). 713 function() {
675 714 if (this.changeDirectorySequence_ !== sequence) {
676 then(function(sequence) { 715 callback();
677 return new Promise(function(onFulfilled, onRejected) {
678 if (this.changeDirectorySequence_ !== sequence)
679 return; 716 return;
717 }
680 718
681 var newDirectoryContents = this.createDirectoryContents_( 719 var newDirectoryContents = this.createDirectoryContents_(
682 this.currentFileListContext_, dirEntry, ''); 720 this.currentFileListContext_, dirEntry, '');
683 if (!newDirectoryContents) 721 if (!newDirectoryContents) {
722 callback();
684 return; 723 return;
724 }
685 725
686 var previousDirEntry = this.currentDirContents_.getDirectoryEntry(); 726 var previousDirEntry =
687 this.clearAndScan_(newDirectoryContents, opt_callback); 727 this.currentDirContents_.getDirectoryEntry();
728 this.clearAndScan_(
729 newDirectoryContents,
730 function(result) {
731 // Calls the callback when successful.
732 if (result && opt_callback)
733 opt_callback();
734 callback();
735 });
688 736
689 // For tests that open the dialog to empty directories, everything is 737 // For tests that open the dialog to empty directories, everything
690 // loaded at this point. 738 // is loaded at this point.
691 util.testSendMessage('directory-change-complete'); 739 util.testSendMessage('directory-change-complete');
692 740
693 var event = new Event('directory-changed'); 741 var event = new Event('directory-changed');
694 event.previousDirEntry = previousDirEntry; 742 event.previousDirEntry = previousDirEntry;
695 event.newDirEntry = dirEntry; 743 event.newDirEntry = dirEntry;
696 this.dispatchEvent(event); 744 this.dispatchEvent(event);
697 }.bind(this)); 745 }.bind(this));
698 }.bind(this, this.changeDirectorySequence_)); 746 }.bind(this, this.changeDirectorySequence_));
699 }; 747 };
700 748
701 /** 749 /**
702 * Activates the given directry. 750 * Activates the given directry.
703 * This method: 751 * This method:
704 * - Changes the current directory, if the given directory is the current 752 * - Changes the current directory, if the given directory is the current
705 * directory. 753 * directory.
706 * - Clears the selection, if the given directory is the current directory. 754 * - Clears the selection, if the given directory is the current directory.
707 * 755 *
708 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to 756 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 DirectoryModel.prototype.search = function(query, 944 DirectoryModel.prototype.search = function(query,
897 onSearchRescan, 945 onSearchRescan,
898 onClearSearch) { 946 onClearSearch) {
899 this.clearSearch_(); 947 this.clearSearch_();
900 var currentDirEntry = this.getCurrentDirEntry(); 948 var currentDirEntry = this.getCurrentDirEntry();
901 if (!currentDirEntry) { 949 if (!currentDirEntry) {
902 // Not yet initialized. Do nothing. 950 // Not yet initialized. Do nothing.
903 return; 951 return;
904 } 952 }
905 953
906 if (!(query || '').trimLeft()) { 954 this.changeDirectorySequence_++;
907 if (this.isSearching()) { 955 this.directoryChangeQueue_.run(function(sequence, callback) {
908 var newDirContents = this.createDirectoryContents_( 956 if (this.changeDirectorySequence_ !== sequence) {
909 this.currentFileListContext_, 957 callback();
910 currentDirEntry); 958 return;
911 this.clearAndScan_(newDirContents);
912 } 959 }
913 return;
914 }
915 960
916 var newDirContents = this.createDirectoryContents_( 961 if (!(query || '').trimLeft()) {
917 this.currentFileListContext_, currentDirEntry, query); 962 if (this.isSearching()) {
918 if (!newDirContents) 963 var newDirContents = this.createDirectoryContents_(
919 return; 964 this.currentFileListContext_,
965 currentDirEntry);
966 this.clearAndScan_(newDirContents,
967 sequence,
968 callback);
969 } else {
970 callback();
971 }
972 return;
973 }
920 974
921 this.onSearchCompleted_ = onSearchRescan; 975 var newDirContents = this.createDirectoryContents_(
922 this.onClearSearch_ = onClearSearch; 976 this.currentFileListContext_, currentDirEntry, query);
923 this.addEventListener('scan-completed', this.onSearchCompleted_); 977 if (!newDirContents) {
924 this.clearAndScan_(newDirContents); 978 callback();
979 return;
980 }
981
982 this.onSearchCompleted_ = onSearchRescan;
983 this.onClearSearch_ = onClearSearch;
984 this.addEventListener('scan-completed', this.onSearchCompleted_);
985 this.clearAndScan_(newDirContents,
986 sequence,
987 callback);
988 }.bind(this, this.changeDirectorySequence_));
925 }; 989 };
926 990
927 /** 991 /**
928 * In case the search was active, remove listeners and send notifications on 992 * In case the search was active, remove listeners and send notifications on
929 * its canceling. 993 * its canceling.
930 * @private 994 * @private
931 */ 995 */
932 DirectoryModel.prototype.clearSearch_ = function() { 996 DirectoryModel.prototype.clearSearch_ = function() {
933 if (!this.isSearching()) 997 if (!this.isSearching())
934 return; 998 return;
935 999
936 if (this.onSearchCompleted_) { 1000 if (this.onSearchCompleted_) {
937 this.removeEventListener('scan-completed', this.onSearchCompleted_); 1001 this.removeEventListener('scan-completed', this.onSearchCompleted_);
938 this.onSearchCompleted_ = null; 1002 this.onSearchCompleted_ = null;
939 } 1003 }
940 1004
941 if (this.onClearSearch_) { 1005 if (this.onClearSearch_) {
942 this.onClearSearch_(); 1006 this.onClearSearch_();
943 this.onClearSearch_ = null; 1007 this.onClearSearch_ = null;
944 } 1008 }
945 }; 1009 };
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698