Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 }; |
| OLD | NEW |