| 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 // If directory files changes too often, don't rescan directory more than once | 5 // If directory files changes too often, don't rescan directory more than once |
| 6 // per specified interval | 6 // per specified interval |
| 7 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; | 7 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; |
| 8 // Used for operations that require almost instant rescan. | 8 // Used for operations that require almost instant rescan. |
| 9 var SHORT_RESCAN_INTERVAL = 100; | 9 var SHORT_RESCAN_INTERVAL = 100; |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 this.runningScan_ = null; | 31 this.runningScan_ = null; |
| 32 this.pendingScan_ = null; | 32 this.pendingScan_ = null; |
| 33 this.rescanTimeout_ = undefined; | 33 this.rescanTimeout_ = undefined; |
| 34 this.scanFailures_ = 0; | 34 this.scanFailures_ = 0; |
| 35 | 35 |
| 36 // DirectoryEntry representing the current directory of the dialog. | 36 // DirectoryEntry representing the current directory of the dialog. |
| 37 this.currentDirEntry_ = root; | 37 this.currentDirEntry_ = root; |
| 38 | 38 |
| 39 this.fileList_.prepareSort = this.prepareSort_.bind(this); | 39 this.fileList_.prepareSort = this.prepareSort_.bind(this); |
| 40 this.autoSelectIndex_ = 0; | |
| 41 | 40 |
| 42 this.rootsList_ = new cr.ui.ArrayDataModel([]); | 41 this.rootsList_ = new cr.ui.ArrayDataModel([]); |
| 43 this.rootsListSelection_ = new cr.ui.ListSingleSelectionModel(); | 42 this.rootsListSelection_ = new cr.ui.ListSingleSelectionModel(); |
| 44 | 43 |
| 45 /** | 44 /** |
| 46 * A map root.fullPath -> currentDirectory.fullPath. | 45 * A map root.fullPath -> currentDirectory.fullPath. |
| 47 * @private | 46 * @private |
| 48 * @type {Object.<string, string>} | 47 * @type {Object.<string, string>} |
| 49 */ | 48 */ |
| 50 this.currentDirByRoot_ = {}; | 49 this.currentDirByRoot_ = {}; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 }; | 195 }; |
| 197 | 196 |
| 198 /** | 197 /** |
| 199 * @return {DirectoryEntry} Current directory. | 198 * @return {DirectoryEntry} Current directory. |
| 200 */ | 199 */ |
| 201 DirectoryModel.prototype.getCurrentDirEntry = function() { | 200 DirectoryModel.prototype.getCurrentDirEntry = function() { |
| 202 return this.currentDirEntry_; | 201 return this.currentDirEntry_; |
| 203 }; | 202 }; |
| 204 | 203 |
| 205 /** | 204 /** |
| 206 * @param {number} value New auto select index. | |
| 207 */ | |
| 208 DirectoryModel.prototype.setAutoSelectIndex = function(value) { | |
| 209 this.autoSelectIndex_ = value; | |
| 210 }; | |
| 211 | |
| 212 /** | |
| 213 * @private | 205 * @private |
| 214 * @return {Array.<string>} Names of selected files. | 206 * @return {Array.<string>} Names of selected files. |
| 215 */ | 207 */ |
| 216 DirectoryModel.prototype.getSelectedNames_ = function() { | 208 DirectoryModel.prototype.getSelectedNames_ = function() { |
| 217 var indexes = this.fileListSelection_.selectedIndexes; | 209 var indexes = this.fileListSelection_.selectedIndexes; |
| 218 var dataModel = this.fileList_; | 210 var dataModel = this.fileList_; |
| 219 if (dataModel) { | 211 if (dataModel) { |
| 220 return indexes.map(function(i) { | 212 return indexes.map(function(i) { |
| 221 return dataModel.item(i).name; | 213 return dataModel.item(i).name; |
| 222 }); | 214 }); |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 onSuccess, errorCallback); | 645 onSuccess, errorCallback); |
| 654 }; | 646 }; |
| 655 | 647 |
| 656 /** | 648 /** |
| 657 * Changes directory. Causes 'directory-change' event. | 649 * Changes directory. Causes 'directory-change' event. |
| 658 * | 650 * |
| 659 * @param {string} path New current directory path. | 651 * @param {string} path New current directory path. |
| 660 * @param {function} opt_OnError Called if failed. | 652 * @param {function} opt_OnError Called if failed. |
| 661 */ | 653 */ |
| 662 DirectoryModel.prototype.changeDirectory = function(path, opt_OnError) { | 654 DirectoryModel.prototype.changeDirectory = function(path, opt_OnError) { |
| 663 var onDirectoryResolved = function(dirEntry) { | 655 var onDirectoryResolved = this.changeDirectoryEntry_.bind(this, false); |
| 664 var autoSelect = this.selectIndex.bind(this, this.autoSelectIndex_); | |
| 665 this.changeDirectoryEntry_(dirEntry, autoSelect, false); | |
| 666 }.bind(this); | |
| 667 | 656 |
| 668 if (this.unmountedGDataEntry_ && | 657 if (this.unmountedGDataEntry_ && |
| 669 DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { | 658 DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { |
| 670 // TODO(kaznacheeev): Currently if path points to some GData subdirectory | 659 // TODO(kaznacheeev): Currently if path points to some GData subdirectory |
| 671 // and GData is not mounted we will change to the fake GData root and | 660 // and GData is not mounted we will change to the fake GData root and |
| 672 // ignore the rest of the path. Consider remembering the path and | 661 // ignore the rest of the path. Consider remembering the path and |
| 673 // changing to it once GDdata is mounted. This is only relevant for cases | 662 // changing to it once GDdata is mounted. This is only relevant for cases |
| 674 // when we open the File Manager with an URL pointing to GData (e.g. via | 663 // when we open the File Manager with an URL pointing to GData (e.g. via |
| 675 // a bookmark). | 664 // a bookmark). |
| 676 onDirectoryResolved(this.unmountedGDataEntry_); | 665 onDirectoryResolved(this.unmountedGDataEntry_); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 691 }; | 680 }; |
| 692 | 681 |
| 693 /** | 682 /** |
| 694 * Change the current directory to the directory represented by a | 683 * Change the current directory to the directory represented by a |
| 695 * DirectoryEntry. | 684 * DirectoryEntry. |
| 696 * | 685 * |
| 697 * Dispatches the 'directory-changed' event when the directory is successfully | 686 * Dispatches the 'directory-changed' event when the directory is successfully |
| 698 * changed. | 687 * changed. |
| 699 * | 688 * |
| 700 * @private | 689 * @private |
| 701 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. | |
| 702 * @param {function} action Action executed if the directory loads | |
| 703 * successfully. By default selects the first item (unless it's a save | |
| 704 * dialog). | |
| 705 * @param {boolean} initial True if it comes from setupPath and | 690 * @param {boolean} initial True if it comes from setupPath and |
| 706 * false if caused by an user action. | 691 * false if caused by an user action. |
| 692 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. |
| 693 * @param {function} opt_callback Executed if the directory loads successfully. |
| 707 */ | 694 */ |
| 708 DirectoryModel.prototype.changeDirectoryEntry_ = function(dirEntry, action, | 695 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, |
| 709 initial) { | 696 opt_callback) { |
| 710 var previous = this.currentDirEntry_; | 697 var previous = this.currentDirEntry_; |
| 711 this.currentDirEntry_ = dirEntry; | 698 this.currentDirEntry_ = dirEntry; |
| 712 function onRescanComplete() { | 699 function onRescanComplete() { |
| 713 action(); | 700 if (opt_callback) |
| 701 opt_callback(); |
| 714 // For tests that open the dialog to empty directories, everything | 702 // For tests that open the dialog to empty directories, everything |
| 715 // is loaded at this point. | 703 // is loaded at this point. |
| 716 chrome.test.sendMessage('directory-change-complete'); | 704 chrome.test.sendMessage('directory-change-complete'); |
| 717 } | 705 } |
| 718 this.updateRootsListSelection_(); | 706 this.updateRootsListSelection_(); |
| 719 this.scan_(onRescanComplete); | 707 this.scan_(onRescanComplete); |
| 720 this.currentDirByRoot_[this.getCurrentRootPath()] = dirEntry.fullPath; | 708 this.currentDirByRoot_[this.getCurrentRootPath()] = dirEntry.fullPath; |
| 721 | 709 |
| 722 var e = new cr.Event('directory-changed'); | 710 var e = new cr.Event('directory-changed'); |
| 723 e.previousDirEntry = previous; | 711 e.previousDirEntry = previous; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 747 var overridden = false; | 735 var overridden = false; |
| 748 function onExternalDirChange() { overridden = true } | 736 function onExternalDirChange() { overridden = true } |
| 749 this.addEventListener('directory-changed', onExternalDirChange); | 737 this.addEventListener('directory-changed', onExternalDirChange); |
| 750 | 738 |
| 751 var resolveCallback = function(exists) { | 739 var resolveCallback = function(exists) { |
| 752 this.removeEventListener('directory-changed', onExternalDirChange); | 740 this.removeEventListener('directory-changed', onExternalDirChange); |
| 753 if (opt_pathResolveCallback) | 741 if (opt_pathResolveCallback) |
| 754 opt_pathResolveCallback(baseName, leafName, exists && !overridden); | 742 opt_pathResolveCallback(baseName, leafName, exists && !overridden); |
| 755 }.bind(this); | 743 }.bind(this); |
| 756 | 744 |
| 757 var changeDirectoryEntry = function(entry, callback, initial, exists) { | 745 var changeDirectoryEntry = function(entry, initial, exists, opt_callback) { |
| 758 resolveCallback(exists); | 746 resolveCallback(exists); |
| 759 if (!overridden) | 747 if (!overridden) |
| 760 this.changeDirectoryEntry_(entry, callback, initial); | 748 this.changeDirectoryEntry_(initial, entry, opt_callback); |
| 761 }.bind(this); | 749 }.bind(this); |
| 762 | 750 |
| 763 var INITIAL = true; | 751 var INITIAL = true; |
| 764 var EXISTS = true; | 752 var EXISTS = true; |
| 765 | 753 |
| 766 // Split the dirname from the basename. | 754 // Split the dirname from the basename. |
| 767 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); | 755 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); |
| 768 var autoSelect = function() { | |
| 769 this.selectIndex(this.autoSelectIndex_); | |
| 770 if (opt_loadedCallback) | |
| 771 opt_loadedCallback(); | |
| 772 }.bind(this); | |
| 773 | 756 |
| 774 if (!ary) { | 757 if (!ary) { |
| 775 console.warn('Unable to split default path: ' + path); | 758 console.warn('Unable to split default path: ' + path); |
| 776 changeDirectoryEntry(this.root_, autoSelect, INITIAL, !EXISTS); | 759 changeDirectoryEntry(this.root_, INITIAL, !EXISTS); |
| 777 return; | 760 return; |
| 778 } | 761 } |
| 779 | 762 |
| 780 var baseName = ary[1]; | 763 var baseName = ary[1]; |
| 781 var leafName = ary[2]; | 764 var leafName = ary[2]; |
| 782 | 765 |
| 783 function onLeafFound(baseDirEntry, leafEntry) { | 766 function onLeafFound(baseDirEntry, leafEntry) { |
| 784 if (leafEntry.isDirectory) { | 767 if (leafEntry.isDirectory) { |
| 785 baseName = path; | 768 baseName = path; |
| 786 leafName = ''; | 769 leafName = ''; |
| 787 changeDirectoryEntry(leafEntry, autoSelect, INITIAL, EXISTS); | 770 changeDirectoryEntry(leafEntry, INITIAL, EXISTS); |
| 788 return; | 771 return; |
| 789 } | 772 } |
| 790 | 773 |
| 791 // Leaf is an existing file, cd to its parent directory and select it. | 774 // Leaf is an existing file, cd to its parent directory and select it. |
| 792 changeDirectoryEntry(baseDirEntry, | 775 changeDirectoryEntry(baseDirEntry, |
| 776 !INITIAL /*HACK*/, |
| 777 EXISTS, |
| 793 function() { | 778 function() { |
| 794 this.selectEntry(leafEntry.name); | 779 this.selectEntry(leafEntry.name); |
| 795 if (opt_loadedCallback) | 780 if (opt_loadedCallback) |
| 796 opt_loadedCallback(); | 781 opt_loadedCallback(); |
| 797 }.bind(this), | 782 }.bind(this)); |
| 798 !INITIAL /*HACK*/, | |
| 799 EXISTS); | |
| 800 // TODO(kaznacheev): Fix history.replaceState for the File Browser and | 783 // TODO(kaznacheev): Fix history.replaceState for the File Browser and |
| 801 // change !INITIAL to INITIAL. Passing |false| makes things | 784 // change !INITIAL to INITIAL. Passing |false| makes things |
| 802 // less ugly for now. | 785 // less ugly for now. |
| 803 } | 786 } |
| 804 | 787 |
| 805 function onLeafError(baseDirEntry, err) { | 788 function onLeafError(baseDirEntry, err) { |
| 806 // Usually, leaf does not exist, because it's just a suggested file name. | 789 // Usually, leaf does not exist, because it's just a suggested file name. |
| 807 if (err.code != FileError.NOT_FOUND_ERR) | 790 if (err.code != FileError.NOT_FOUND_ERR) |
| 808 console.log('Unexpected error resolving default leaf: ' + err); | 791 console.log('Unexpected error resolving default leaf: ' + err); |
| 809 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); | 792 changeDirectoryEntry(baseDirEntry, INITIAL, !EXISTS); |
| 810 } | 793 } |
| 811 | 794 |
| 812 var onBaseError = function(err) { | 795 var onBaseError = function(err) { |
| 813 console.log('Unexpected error resolving default base "' + | 796 console.log('Unexpected error resolving default base "' + |
| 814 baseName + '": ' + err); | 797 baseName + '": ' + err); |
| 815 if (path != this.getDefaultDirectory()) { | 798 if (path != this.getDefaultDirectory()) { |
| 816 // Can't find the provided path, let's go to default one instead. | 799 // Can't find the provided path, let's go to default one instead. |
| 817 resolveCallback(!EXISTS); | 800 resolveCallback(!EXISTS); |
| 818 if (!overridden) | 801 if (!overridden) |
| 819 this.setupDefaultPath(opt_loadedCallback); | 802 this.setupDefaultPath(opt_loadedCallback); |
| 820 } else { | 803 } else { |
| 821 // Well, we can't find the downloads dir. Let's just show something, | 804 // Well, we can't find the downloads dir. Let's just show something, |
| 822 // or we will get an infinite recursion. | 805 // or we will get an infinite recursion. |
| 823 changeDirectoryEntry(this.root_, opt_loadedCallback, INITIAL, !EXISTS); | 806 changeDirectoryEntry(this.root_, opt_loadedCallback, INITIAL, !EXISTS); |
| 824 } | 807 } |
| 825 }.bind(this); | 808 }.bind(this); |
| 826 | 809 |
| 827 var onBaseFound = function(baseDirEntry) { | 810 var onBaseFound = function(baseDirEntry) { |
| 828 if (!leafName) { | 811 if (!leafName) { |
| 829 // Default path is just a directory, cd to it and we're done. | 812 // Default path is just a directory, cd to it and we're done. |
| 830 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); | 813 changeDirectoryEntry(baseDirEntry, INITIAL, !EXISTS); |
| 831 return; | 814 return; |
| 832 } | 815 } |
| 833 | 816 |
| 834 util.resolvePath(this.root_, path, | 817 util.resolvePath(this.root_, path, |
| 835 onLeafFound.bind(this, baseDirEntry), | 818 onLeafFound.bind(this, baseDirEntry), |
| 836 onLeafError.bind(this, baseDirEntry)); | 819 onLeafError.bind(this, baseDirEntry)); |
| 837 }.bind(this); | 820 }.bind(this); |
| 838 | 821 |
| 839 var root = this.root_; | 822 var root = this.root_; |
| 840 if (!baseName) | 823 if (!baseName) |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1244 /** | 1227 /** |
| 1245 * @private | 1228 * @private |
| 1246 */ | 1229 */ |
| 1247 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { | 1230 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { |
| 1248 metrics.recordInterval('DirectoryScan'); | 1231 metrics.recordInterval('DirectoryScan'); |
| 1249 if (this.dir_.fullPath == | 1232 if (this.dir_.fullPath == |
| 1250 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 1233 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
| 1251 metrics.recordMediumCount('DownloadsCount', this.list_.length); | 1234 metrics.recordMediumCount('DownloadsCount', this.list_.length); |
| 1252 } | 1235 } |
| 1253 }; | 1236 }; |
| OLD | NEW |