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

Side by Side Diff: chrome/browser/resources/file_manager/foreground/js/directory_model.js

Issue 151413002: Files.app: Clean DirectoryModel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed a test. Created 6 years, 10 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 '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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 }; 66 };
67 67
68 /** 68 /**
69 * @return {cr.ui.ArrayDataModel} Files in the current directory. 69 * @return {cr.ui.ArrayDataModel} Files in the current directory.
70 */ 70 */
71 DirectoryModel.prototype.getFileList = function() { 71 DirectoryModel.prototype.getFileList = function() {
72 return this.currentFileListContext_.fileList; 72 return this.currentFileListContext_.fileList;
73 }; 73 };
74 74
75 /** 75 /**
76 * Sort the file list.
77 * @param {string} sortField Sort field.
78 * @param {string} sortDirection "asc" or "desc".
79 */
80 DirectoryModel.prototype.sortFileList = function(sortField, sortDirection) {
81 this.getFileList().sort(sortField, sortDirection);
82 };
83
84 /**
85 * @return {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} Selection 76 * @return {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} Selection
86 * in the fileList. 77 * in the fileList.
87 */ 78 */
88 DirectoryModel.prototype.getFileListSelection = function() { 79 DirectoryModel.prototype.getFileListSelection = function() {
89 return this.fileListSelection_; 80 return this.fileListSelection_;
90 }; 81 };
91 82
92 /** 83 /**
93 * @return {?RootType} Root type of current root, or null if not found. 84 * @return {?RootType} Root type of current root, or null if not found.
94 */ 85 */
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 }; 179 };
189 180
190 /** 181 /**
191 * @return {DirectoryEntry} Current directory. 182 * @return {DirectoryEntry} Current directory.
192 */ 183 */
193 DirectoryModel.prototype.getCurrentDirEntry = function() { 184 DirectoryModel.prototype.getCurrentDirEntry = function() {
194 return this.currentDirContents_.getDirectoryEntry(); 185 return this.currentDirContents_.getDirectoryEntry();
195 }; 186 };
196 187
197 /** 188 /**
198 * @return {Array.<Entry>} Array of selected entries.. 189 * @return {Array.<Entry>} Array of selected entries.
199 * @private 190 * @private
200 */ 191 */
201 DirectoryModel.prototype.getSelectedEntries_ = function() { 192 DirectoryModel.prototype.getSelectedEntries_ = function() {
202 var indexes = this.fileListSelection_.selectedIndexes; 193 var indexes = this.fileListSelection_.selectedIndexes;
203 var fileList = this.getFileList(); 194 var fileList = this.getFileList();
204 if (fileList) { 195 if (fileList) {
205 return indexes.map(function(i) { 196 return indexes.map(function(i) {
206 return fileList.item(i); 197 return fileList.item(i);
207 }); 198 });
208 } 199 }
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 this.fileListSelection_.endChange(); 612 this.fileListSelection_.endChange();
622 successCallback(newEntry); 613 successCallback(newEntry);
623 } 614 }
624 }.bind(this), function(reason) { 615 }.bind(this), function(reason) {
625 tracker.stop(); 616 tracker.stop();
626 errorCallback(reason); 617 errorCallback(reason);
627 }); 618 });
628 }; 619 };
629 620
630 /** 621 /**
631 * @param {DirectoryEntry} dirEntry The entry of the new directory.
632 * @param {function()=} opt_callback Executed if the directory loads
633 * successfully.
634 * @private
635 */
636 DirectoryModel.prototype.changeDirectoryEntrySilent_ = function(dirEntry,
637 opt_callback) {
638 var onScanComplete = function() {
639 if (opt_callback)
640 opt_callback();
641 // For tests that open the dialog to empty directories, everything
642 // is loaded at this point.
643 chrome.test.sendMessage('directory-change-complete');
644 };
645 this.clearAndScan_(
646 DirectoryContents.createForDirectory(this.currentFileListContext_,
647 dirEntry),
648 onScanComplete.bind(this));
649 };
650
651 /**
652 * Change the current directory to the directory represented by 622 * Change the current directory to the directory represented by
653 * a DirectoryEntry or a fake entry. 623 * a DirectoryEntry or a fake entry.
654 * 624 *
655 * Dispatches the 'directory-changed' event when the directory is successfully 625 * Dispatches the 'directory-changed' event when the directory is successfully
656 * changed. 626 * changed.
657 * 627 *
658 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to 628 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to
659 * be opened. 629 * be opened.
660 * @param {function()=} opt_callback Executed if the directory loads 630 * @param {function()=} opt_callback Executed if the directory loads
661 * successfully. 631 * successfully.
662 */ 632 */
663 DirectoryModel.prototype.changeDirectoryEntry = function( 633 DirectoryModel.prototype.changeDirectoryEntry = function(
664 dirEntry, opt_callback) { 634 dirEntry, opt_callback) {
665 if (util.isFakeEntry(dirEntry)) {
666 this.specialSearch(dirEntry);
667 if (opt_callback)
668 opt_callback();
669 return;
670 }
671
672 // Increment the sequence value. 635 // Increment the sequence value.
673 this.changeDirectorySequence_++; 636 this.changeDirectorySequence_++;
637 this.clearSearch_();
674 638
675 this.fileWatcher_.changeWatchedDirectory(dirEntry, function(sequence) { 639 var promise = new Promise(
676 if (this.changeDirectorySequence_ !== sequence) 640 function(onFulfilled, onRejected) {
677 return; 641 this.fileWatcher_.changeWatchedDirectory(dirEntry, onFulfilled);
678 var previous = this.currentDirContents_.getDirectoryEntry(); 642 }.bind(this)).
679 this.clearSearch_();
680 this.changeDirectoryEntrySilent_(dirEntry, opt_callback);
681 643
682 var e = new Event('directory-changed'); 644 then(function(sequence) {
683 e.previousDirEntry = previous; 645 return new Promise(function(onFulfilled, onRejected) {
684 e.newDirEntry = dirEntry; 646 if (this.changeDirectorySequence_ !== sequence)
685 this.dispatchEvent(e); 647 return;
686 }.bind(this, this.changeDirectorySequence_)); 648
649 var newDirectoryContents = this.createDirectoryContents_(
650 this.currentFileListContext_, dirEntry, '');
651 if (!newDirectoryContents)
652 return;
653
654 var previousDirEntry = this.currentDirContents_.getDirectoryEntry();
655 this.clearAndScan_(newDirectoryContents, opt_callback);
656
657 // For tests that open the dialog to empty directories, everything is
658 // loaded at this point.
659 chrome.test.sendMessage('directory-change-complete');
660
661 var event = new Event('directory-changed');
662 event.previousDirEntry = previousDirEntry;
663 event.newDirEntry = dirEntry;
664 this.dispatchEvent(event);
665 }.bind(this));
666 }.bind(this, this.changeDirectorySequence_));
687 }; 667 };
688 668
689 /** 669 /**
690 * Creates an object which could say whether directory has changed while it has 670 * Creates an object which could say whether directory has changed while it has
691 * been active or not. Designed for long operations that should be cancelled 671 * been active or not. Designed for long operations that should be cancelled
692 * if the used change current directory. 672 * if the used change current directory.
693 * @return {Object} Created object. 673 * @return {Object} Created object.
694 */ 674 */
695 DirectoryModel.prototype.createDirectoryChangeTracker = function() { 675 DirectoryModel.prototype.createDirectoryChangeTracker = function() {
696 var tracker = { 676 var tracker = {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 DirectoryModel.prototype.selectIndex = function(index) { 738 DirectoryModel.prototype.selectIndex = function(index) {
759 // this.focusCurrentList_(); 739 // this.focusCurrentList_();
760 if (index >= this.getFileList().length) 740 if (index >= this.getFileList().length)
761 return; 741 return;
762 742
763 // If a list bound with the model it will do scrollIndexIntoView(index). 743 // If a list bound with the model it will do scrollIndexIntoView(index).
764 this.fileListSelection_.selectedIndex = index; 744 this.fileListSelection_.selectedIndex = index;
765 }; 745 };
766 746
767 /** 747 /**
768 * Called when VolumeInfoList is updated. 748 * Handles update of VolumeInfoList.
769 * @param {Event} event Event of VolumeInfoList's 'splice'. 749 * @param {Event} event Event of VolumeInfoList's 'splice'.
770 * @private 750 * @private
771 */ 751 */
772 DirectoryModel.prototype.onVolumeInfoListUpdated_ = function(event) { 752 DirectoryModel.prototype.onVolumeInfoListUpdated_ = function(event) {
773 // When the volume where we are is unmounted, fallback to the default volume's 753 // When the volume where we are is unmounted, fallback to the default volume's
774 // root. If current directory path is empty, stop the fallback 754 // root. If current directory path is empty, stop the fallback
775 // since the current directory is initializing now. 755 // since the current directory is initializing now.
776 if (this.getCurrentDirEntry() && 756 if (this.getCurrentDirEntry() &&
777 !this.volumeManager_.getVolumeInfo(this.getCurrentDirEntry())) { 757 !this.volumeManager_.getVolumeInfo(this.getCurrentDirEntry())) {
778 this.volumeManager_.getDefaultDisplayRoot(function(displayRoot) { 758 this.volumeManager_.getDefaultDisplayRoot(function(displayRoot) {
779 this.changeDirectoryEntry(displayRoot); 759 this.changeDirectoryEntry(displayRoot);
780 }.bind(this)); 760 }.bind(this));
781 } 761 }
782 }; 762 };
783 763
784 /** 764 /**
765 * Creates directory contents for the entry and query.
766 *
767 * @param {FileListContext} context File list context.
768 * @param {DirectoryEntry} entry Current directory.
769 * @param {string=} opt_query Search query string.
770 * @return {DirectoryContents} Directory contents.
771 * @private
772 */
773 DirectoryModel.prototype.createDirectoryContents_ =
774 function(context, entry, opt_query) {
775 var query = (opt_query || '').trimLeft();
776 var locationInfo = this.volumeManager_.getLocationInfo(entry);
777 if (!locationInfo)
778 return null;
779 var canUseDriveSearch = this.volumeManager_.getDriveConnectionState().type !==
780 util.DriveConnectionType.OFFLINE &&
781 locationInfo.isDriveBased;
782
783 if (query && canUseDriveSearch) {
784 // Drive search.
785 return DirectoryContents.createForDriveSearch(context, entry, query);
786 } else if (query) {
787 // Local search.
788 return DirectoryContents.createForLocalSearch(context, entry, query);
789 } if (locationInfo.isSpecialSearchRoot) {
790 // Drive special search.
791 var searchType;
792 switch (locationInfo.rootType) {
793 case RootType.DRIVE_OFFLINE:
794 searchType =
795 DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE;
796 break;
797 case RootType.DRIVE_SHARED_WITH_ME:
798 searchType =
799 DriveMetadataSearchContentScanner.SearchType.SEARCH_SHARED_WITH_ME;
800 break;
801 case RootType.DRIVE_RECENT:
802 searchType =
803 DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES;
804 break;
805 default:
806 // Unknown special search entry.
807 throw new Error('Unknown special search type.');
808 }
809 return DirectoryContents.createForDriveMetadataSearch(
810 context,
811 entry,
812 searchType);
813 } else {
814 // Local fetch or search.
815 return DirectoryContents.createForDirectory(context, entry);
816 }
817 };
818
819 /**
785 * Performs search and displays results. The search type is dependent on the 820 * Performs search and displays results. The search type is dependent on the
786 * current directory. If we are currently on drive, server side content search 821 * current directory. If we are currently on drive, server side content search
787 * over drive mount point. If the current directory is not on the drive, file 822 * over drive mount point. If the current directory is not on the drive, file
788 * name search over current directory will be performed. 823 * name search over current directory will be performed.
789 * 824 *
790 * @param {string} query Query that will be searched for. 825 * @param {string} query Query that will be searched for.
791 * @param {function(Event)} onSearchRescan Function that will be called when the 826 * @param {function(Event)} onSearchRescan Function that will be called when the
792 * search directory is rescanned (i.e. search results are displayed). 827 * search directory is rescanned (i.e. search results are displayed).
793 * @param {function()} onClearSearch Function to be called when search state 828 * @param {function()} onClearSearch Function to be called when search state
794 * gets cleared. 829 * gets cleared.
795 * TODO(olege): Change callbacks to events. 830 * TODO(olege): Change callbacks to events.
796 */ 831 */
797 DirectoryModel.prototype.search = function(query, 832 DirectoryModel.prototype.search = function(query,
798 onSearchRescan, 833 onSearchRescan,
799 onClearSearch) { 834 onClearSearch) {
800 query = query.trimLeft();
801
802 this.clearSearch_(); 835 this.clearSearch_();
803
804 var currentDirEntry = this.getCurrentDirEntry(); 836 var currentDirEntry = this.getCurrentDirEntry();
805 if (!currentDirEntry) { 837 if (!currentDirEntry) {
806 // Not yet initialized. Do nothing. 838 // Not yet initialized. Do nothing.
807 return; 839 return;
808 } 840 }
809 841
810 if (!query) { 842 if (!(query || '').trimLeft()) {
811 if (this.isSearching()) { 843 if (this.isSearching()) {
812 var newDirContents = DirectoryContents.createForDirectory( 844 var newDirContents = DirectoryContents.createForDirectory(
813 this.currentFileListContext_, 845 this.currentFileListContext_,
814 this.currentDirContents_.getLastNonSearchDirectoryEntry()); 846 currentDirEntry);
815 this.clearAndScan_(newDirContents); 847 this.clearAndScan_(newDirContents);
816 } 848 }
817 return; 849 return;
818 } 850 }
819 851
852 var newDirContents = this.createDirectoryContents_(
853 this.currentFileListContext_, currentDirEntry, query);
854 if (!newDirContents)
855 return;
856
820 this.onSearchCompleted_ = onSearchRescan; 857 this.onSearchCompleted_ = onSearchRescan;
821 this.onClearSearch_ = onClearSearch; 858 this.onClearSearch_ = onClearSearch;
822
823 this.addEventListener('scan-completed', this.onSearchCompleted_); 859 this.addEventListener('scan-completed', this.onSearchCompleted_);
824
825 // If we are offline, let's fallback to file name search inside dir.
826 // A search initiated from directories in Drive or special search results
827 // should trigger Drive search.
828 var newDirContents;
829 var isDriveOffline = this.volumeManager_.getDriveConnectionState().type ===
830 util.DriveConnectionType.OFFLINE;
831 var locationInfo = this.volumeManager_.getLocationInfo(currentDirEntry);
832 if (!isDriveOffline && locationInfo && locationInfo.isDriveBased) {
833 // Drive search is performed over the whole drive, so pass drive root as
834 // |directoryEntry|.
835 newDirContents = DirectoryContents.createForDriveSearch(
836 this.currentFileListContext_,
837 currentDirEntry,
838 this.currentDirContents_.getLastNonSearchDirectoryEntry(),
839 query);
840 } else {
841 newDirContents = DirectoryContents.createForLocalSearch(
842 this.currentFileListContext_, currentDirEntry, query);
843 }
844 this.clearAndScan_(newDirContents); 860 this.clearAndScan_(newDirContents);
845 }; 861 };
846 862
847 /** 863 /**
848 * Performs special search and displays results. e.g. Drive files available
849 * offline, shared-with-me files, recently modified files.
850 * @param {Object} fakeEntry Fake entry representing a special search.
851 * @param {string=} opt_query Query string used for the search.
852 */
853 DirectoryModel.prototype.specialSearch = function(fakeEntry, opt_query) {
854 var query = opt_query || '';
855
856 // Increment the sequence value.
857 this.changeDirectorySequence_++;
858
859 this.clearSearch_();
860 this.onSearchCompleted_ = null;
861 this.onClearSearch_ = null;
862
863 // Obtains a volume information.
864 // TODO(hirono): Obtain the proper profile's volume information.
865 var volumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo(
866 util.VolumeType.DRIVE);
867 if (!volumeInfo) {
868 // It seems that the volume is already unmounted or drive is disable.
869 return;
870 }
871
872 var onDriveDirectoryResolved = function(sequence, driveRoot) {
873 if (this.changeDirectorySequence_ !== sequence)
874 return;
875
876 var locationInfo = this.volumeManager_.getLocationInfo(fakeEntry);
877 if (!locationInfo)
878 return;
879
880 var searchOption;
881 switch (locationInfo.rootType) {
882 case RootType.DRIVE_OFFLINE:
883 searchOption =
884 DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE;
885 break;
886 case RootType.DRIVE_SHARED_WITH_ME:
887 searchOption =
888 DriveMetadataSearchContentScanner.SearchType.SEARCH_SHARED_WITH_ME;
889 break;
890 case RootType.DRIVE_RECENT:
891 searchOption =
892 DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES;
893 break;
894 default:
895 // Unknown special search entry.
896 throw new Error('Unknown special search type.');
897 }
898
899 var newDirContents = DirectoryContents.createForDriveMetadataSearch(
900 this.currentFileListContext_,
901 fakeEntry, driveRoot, query, searchOption);
902 var previous = this.currentDirContents_.getDirectoryEntry();
903 this.clearAndScan_(newDirContents);
904
905 var e = new Event('directory-changed');
906 e.previousDirEntry = previous;
907 e.newDirEntry = fakeEntry;
908 this.dispatchEvent(e);
909 }.bind(this, this.changeDirectorySequence_);
910
911 volumeInfo.resolveDisplayRoot(
912 onDriveDirectoryResolved /* success */, function() {} /* failed */);
913 };
914
915 /**
916 * In case the search was active, remove listeners and send notifications on 864 * In case the search was active, remove listeners and send notifications on
917 * its canceling. 865 * its canceling.
918 * @private 866 * @private
919 */ 867 */
920 DirectoryModel.prototype.clearSearch_ = function() { 868 DirectoryModel.prototype.clearSearch_ = function() {
921 if (!this.isSearching()) 869 if (!this.isSearching())
922 return; 870 return;
923 871
924 if (this.onSearchCompleted_) { 872 if (this.onSearchCompleted_) {
925 this.removeEventListener('scan-completed', this.onSearchCompleted_); 873 this.removeEventListener('scan-completed', this.onSearchCompleted_);
926 this.onSearchCompleted_ = null; 874 this.onSearchCompleted_ = null;
927 } 875 }
928 876
929 if (this.onClearSearch_) { 877 if (this.onClearSearch_) {
930 this.onClearSearch_(); 878 this.onClearSearch_();
931 this.onClearSearch_ = null; 879 this.onClearSearch_ = null;
932 } 880 }
933 }; 881 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698