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; |
40 | 41 |
41 this.rootsList_ = new cr.ui.ArrayDataModel([]); | 42 this.rootsList_ = new cr.ui.ArrayDataModel([]); |
42 this.rootsListSelection_ = new cr.ui.ListSingleSelectionModel(); | 43 this.rootsListSelection_ = new cr.ui.ListSingleSelectionModel(); |
43 | 44 |
44 /** | 45 /** |
45 * A map root.fullPath -> currentDirectory.fullPath. | 46 * A map root.fullPath -> currentDirectory.fullPath. |
46 * @private | 47 * @private |
47 * @type {Object.<string, string>} | 48 * @type {Object.<string, string>} |
48 */ | 49 */ |
49 this.currentDirByRoot_ = {}; | 50 this.currentDirByRoot_ = {}; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 }; | 189 }; |
189 | 190 |
190 /** | 191 /** |
191 * @return {DirectoryEntry} Current directory. | 192 * @return {DirectoryEntry} Current directory. |
192 */ | 193 */ |
193 DirectoryModel.prototype.getCurrentDirEntry = function() { | 194 DirectoryModel.prototype.getCurrentDirEntry = function() { |
194 return this.currentDirEntry_; | 195 return this.currentDirEntry_; |
195 }; | 196 }; |
196 | 197 |
197 /** | 198 /** |
| 199 * @param {number} value New auto select index. |
| 200 */ |
| 201 DirectoryModel.prototype.setAutoSelectIndex = function(value) { |
| 202 this.autoSelectIndex_ = value; |
| 203 }; |
| 204 |
| 205 /** |
198 * @private | 206 * @private |
199 * @return {Array.<string>} Names of selected files. | 207 * @return {Array.<string>} Names of selected files. |
200 */ | 208 */ |
201 DirectoryModel.prototype.getSelectedNames_ = function() { | 209 DirectoryModel.prototype.getSelectedNames_ = function() { |
202 var indexes = this.fileListSelection_.selectedIndexes; | 210 var indexes = this.fileListSelection_.selectedIndexes; |
203 var dataModel = this.fileList_; | 211 var dataModel = this.fileList_; |
204 if (dataModel) { | 212 if (dataModel) { |
205 return indexes.map(function(i) { | 213 return indexes.map(function(i) { |
206 return dataModel.item(i).name; | 214 return dataModel.item(i).name; |
207 }); | 215 }); |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
638 onSuccess, errorCallback); | 646 onSuccess, errorCallback); |
639 }; | 647 }; |
640 | 648 |
641 /** | 649 /** |
642 * Changes directory. Causes 'directory-change' event. | 650 * Changes directory. Causes 'directory-change' event. |
643 * | 651 * |
644 * @param {string} path New current directory path. | 652 * @param {string} path New current directory path. |
645 * @param {function} opt_OnError Called if failed. | 653 * @param {function} opt_OnError Called if failed. |
646 */ | 654 */ |
647 DirectoryModel.prototype.changeDirectory = function(path, opt_OnError) { | 655 DirectoryModel.prototype.changeDirectory = function(path, opt_OnError) { |
648 var onDirectoryResolved = this.changeDirectoryEntry_.bind(this, false); | 656 var onDirectoryResolved = function(dirEntry) { |
| 657 var autoSelect = this.selectIndex.bind(this, this.autoSelectIndex_); |
| 658 this.changeDirectoryEntry_(dirEntry, autoSelect, false); |
| 659 }.bind(this); |
649 | 660 |
650 if (this.unmountedGDataEntry_ && | 661 if (this.unmountedGDataEntry_ && |
651 DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { | 662 DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { |
652 // TODO(kaznacheeev): Currently if path points to some GData subdirectory | 663 // TODO(kaznacheeev): Currently if path points to some GData subdirectory |
653 // and GData is not mounted we will change to the fake GData root and | 664 // and GData is not mounted we will change to the fake GData root and |
654 // ignore the rest of the path. Consider remembering the path and | 665 // ignore the rest of the path. Consider remembering the path and |
655 // changing to it once GDdata is mounted. This is only relevant for cases | 666 // changing to it once GDdata is mounted. This is only relevant for cases |
656 // when we open the File Manager with an URL pointing to GData (e.g. via | 667 // when we open the File Manager with an URL pointing to GData (e.g. via |
657 // a bookmark). | 668 // a bookmark). |
658 onDirectoryResolved(this.unmountedGDataEntry_); | 669 onDirectoryResolved(this.unmountedGDataEntry_); |
(...skipping 14 matching lines...) Expand all Loading... |
673 }; | 684 }; |
674 | 685 |
675 /** | 686 /** |
676 * Change the current directory to the directory represented by a | 687 * Change the current directory to the directory represented by a |
677 * DirectoryEntry. | 688 * DirectoryEntry. |
678 * | 689 * |
679 * Dispatches the 'directory-changed' event when the directory is successfully | 690 * Dispatches the 'directory-changed' event when the directory is successfully |
680 * changed. | 691 * changed. |
681 * | 692 * |
682 * @private | 693 * @private |
| 694 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. |
| 695 * @param {function} action Action executed if the directory loads |
| 696 * successfully. By default selects the first item (unless it's a save |
| 697 * dialog). |
683 * @param {boolean} initial True if it comes from setupPath and | 698 * @param {boolean} initial True if it comes from setupPath and |
684 * false if caused by an user action. | 699 * false if caused by an user action. |
685 * @param {DirectoryEntry} dirEntry A new directory entry. | |
686 */ | 700 */ |
687 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry) { | 701 DirectoryModel.prototype.changeDirectoryEntry_ = function(dirEntry, action, |
| 702 initial) { |
688 var previous = this.currentDirEntry_; | 703 var previous = this.currentDirEntry_; |
689 this.currentDirEntry_ = dirEntry; | 704 this.currentDirEntry_ = dirEntry; |
690 function onRescanComplete() { | 705 function onRescanComplete() { |
| 706 action(); |
691 // For tests that open the dialog to empty directories, everything | 707 // For tests that open the dialog to empty directories, everything |
692 // is loaded at this point. | 708 // is loaded at this point. |
693 chrome.test.sendMessage('directory-change-complete'); | 709 chrome.test.sendMessage('directory-change-complete'); |
694 } | 710 } |
695 this.updateReadonlyStatus_(); | 711 this.updateReadonlyStatus_(); |
696 this.updateVolumeMetadata_(); | 712 this.updateVolumeMetadata_(); |
697 this.updateRootsListSelection_(); | 713 this.updateRootsListSelection_(); |
698 this.scan_(onRescanComplete); | 714 this.scan_(onRescanComplete); |
699 this.currentDirByRoot_[this.getCurrentRootPath()] = dirEntry.fullPath; | 715 this.currentDirByRoot_[this.getCurrentRootPath()] = dirEntry.fullPath; |
700 | 716 |
(...skipping 25 matching lines...) Expand all Loading... |
726 var overridden = false; | 742 var overridden = false; |
727 function onExternalDirChange() { overridden = true } | 743 function onExternalDirChange() { overridden = true } |
728 this.addEventListener('directory-changed', onExternalDirChange); | 744 this.addEventListener('directory-changed', onExternalDirChange); |
729 | 745 |
730 var resolveCallback = function(exists) { | 746 var resolveCallback = function(exists) { |
731 this.removeEventListener('directory-changed', onExternalDirChange); | 747 this.removeEventListener('directory-changed', onExternalDirChange); |
732 if (opt_pathResolveCallback) | 748 if (opt_pathResolveCallback) |
733 opt_pathResolveCallback(baseName, leafName, exists && !overridden); | 749 opt_pathResolveCallback(baseName, leafName, exists && !overridden); |
734 }.bind(this); | 750 }.bind(this); |
735 | 751 |
736 var changeDirectoryEntry = function(entry, initial, exists) { | 752 var changeDirectoryEntry = function(entry, callback, initial, exists) { |
737 resolveCallback(exists); | 753 resolveCallback(exists); |
738 if (!overridden) | 754 if (!overridden) |
739 this.changeDirectoryEntry_(initial, entry); | 755 this.changeDirectoryEntry_(entry, callback, initial); |
740 }.bind(this); | 756 }.bind(this); |
741 | 757 |
742 var INITIAL = true; | 758 var INITIAL = true; |
743 var EXISTS = true; | 759 var EXISTS = true; |
744 | 760 |
745 // Split the dirname from the basename. | 761 // Split the dirname from the basename. |
746 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); | 762 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); |
| 763 var autoSelect = function() { |
| 764 this.selectIndex(this.autoSelectIndex_); |
| 765 if (opt_loadedCallback) |
| 766 opt_loadedCallback(); |
| 767 }.bind(this); |
747 | 768 |
748 if (!ary) { | 769 if (!ary) { |
749 console.warn('Unable to split default path: ' + path); | 770 console.warn('Unable to split default path: ' + path); |
750 changeDirectoryEntry(this.root_, INITIAL, !EXISTS); | 771 changeDirectoryEntry(this.root_, autoSelect, INITIAL, !EXISTS); |
751 return; | 772 return; |
752 } | 773 } |
753 | 774 |
754 var baseName = ary[1]; | 775 var baseName = ary[1]; |
755 var leafName = ary[2]; | 776 var leafName = ary[2]; |
756 | 777 |
757 function onLeafFound(baseDirEntry, leafEntry) { | 778 function onLeafFound(baseDirEntry, leafEntry) { |
758 if (leafEntry.isDirectory) { | 779 if (leafEntry.isDirectory) { |
759 baseName = path; | 780 baseName = path; |
760 leafName = ''; | 781 leafName = ''; |
761 changeDirectoryEntry(leafEntry, INITIAL, EXISTS); | 782 changeDirectoryEntry(leafEntry, autoSelect, INITIAL, EXISTS); |
762 return; | 783 return; |
763 } | 784 } |
764 | 785 |
765 // Leaf is an existing file, cd to its parent directory and select it. | 786 // Leaf is an existing file, cd to its parent directory and select it. |
766 changeDirectoryEntry(baseDirEntry, | 787 changeDirectoryEntry(baseDirEntry, |
767 function() { | 788 function() { |
768 this.selectEntry(leafEntry.name); | 789 this.selectEntry(leafEntry.name); |
769 if (opt_loadedCallback) | 790 if (opt_loadedCallback) |
770 opt_loadedCallback(); | 791 opt_loadedCallback(); |
771 }.bind(this), | 792 }.bind(this), |
772 !INITIAL /*HACK*/, | 793 !INITIAL /*HACK*/, |
773 EXISTS); | 794 EXISTS); |
774 // TODO(kaznacheev): Fix history.replaceState for the File Browser and | 795 // TODO(kaznacheev): Fix history.replaceState for the File Browser and |
775 // change !INITIAL to INITIAL. Passing |false| makes things | 796 // change !INITIAL to INITIAL. Passing |false| makes things |
776 // less ugly for now. | 797 // less ugly for now. |
777 } | 798 } |
778 | 799 |
779 function onLeafError(baseDirEntry, err) { | 800 function onLeafError(baseDirEntry, err) { |
780 // Usually, leaf does not exist, because it's just a suggested file name. | 801 // Usually, leaf does not exist, because it's just a suggested file name. |
781 if (err.code != FileError.NOT_FOUND_ERR) | 802 if (err.code != FileError.NOT_FOUND_ERR) |
782 console.log('Unexpected error resolving default leaf: ' + err); | 803 console.log('Unexpected error resolving default leaf: ' + err); |
783 changeDirectoryEntry(baseDirEntry, INITIAL, !EXISTS); | 804 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); |
784 } | 805 } |
785 | 806 |
786 var onBaseError = function(err) { | 807 var onBaseError = function(err) { |
787 console.log('Unexpected error resolving default base "' + | 808 console.log('Unexpected error resolving default base "' + |
788 baseName + '": ' + err); | 809 baseName + '": ' + err); |
789 if (path != this.getDefaultDirectory()) { | 810 if (path != this.getDefaultDirectory()) { |
790 // Can't find the provided path, let's go to default one instead. | 811 // Can't find the provided path, let's go to default one instead. |
791 resolveCallback(!EXISTS); | 812 resolveCallback(!EXISTS); |
792 if (!overridden) | 813 if (!overridden) |
793 this.setupDefaultPath(opt_loadedCallback); | 814 this.setupDefaultPath(opt_loadedCallback); |
794 } else { | 815 } else { |
795 // Well, we can't find the downloads dir. Let's just show something, | 816 // Well, we can't find the downloads dir. Let's just show something, |
796 // or we will get an infinite recursion. | 817 // or we will get an infinite recursion. |
797 changeDirectoryEntry(this.root_, opt_loadedCallback, INITIAL, !EXISTS); | 818 changeDirectoryEntry(this.root_, opt_loadedCallback, INITIAL, !EXISTS); |
798 } | 819 } |
799 }.bind(this); | 820 }.bind(this); |
800 | 821 |
801 var onBaseFound = function(baseDirEntry) { | 822 var onBaseFound = function(baseDirEntry) { |
802 if (!leafName) { | 823 if (!leafName) { |
803 // Default path is just a directory, cd to it and we're done. | 824 // Default path is just a directory, cd to it and we're done. |
804 changeDirectoryEntry(baseDirEntry, INITIAL, !EXISTS); | 825 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); |
805 return; | 826 return; |
806 } | 827 } |
807 | 828 |
808 util.resolvePath(this.root_, path, | 829 util.resolvePath(this.root_, path, |
809 onLeafFound.bind(this, baseDirEntry), | 830 onLeafFound.bind(this, baseDirEntry), |
810 onLeafError.bind(this, baseDirEntry)); | 831 onLeafError.bind(this, baseDirEntry)); |
811 }.bind(this); | 832 }.bind(this); |
812 | 833 |
813 var root = this.root_; | 834 var root = this.root_; |
814 if (!baseName) | 835 if (!baseName) |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1249 /** | 1270 /** |
1250 * @private | 1271 * @private |
1251 */ | 1272 */ |
1252 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { | 1273 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { |
1253 metrics.recordInterval('DirectoryScan'); | 1274 metrics.recordInterval('DirectoryScan'); |
1254 if (this.dir_.fullPath == | 1275 if (this.dir_.fullPath == |
1255 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 1276 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
1256 metrics.recordMediumCount('DownloadsCount', this.list_.length); | 1277 metrics.recordMediumCount('DownloadsCount', this.list_.length); |
1257 } | 1278 } |
1258 }; | 1279 }; |
OLD | NEW |