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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 | 50 |
51 // The map 'name' -> callback. Callbacks are function(entry) -> boolean. | 51 // The map 'name' -> callback. Callbacks are function(entry) -> boolean. |
52 this.filters_ = {}; | 52 this.filters_ = {}; |
53 this.setFilterHidden(true); | 53 this.setFilterHidden(true); |
54 | 54 |
55 /** | 55 /** |
56 * @private | 56 * @private |
57 * @type {Object.<string, boolean>} | 57 * @type {Object.<string, boolean>} |
58 */ | 58 */ |
59 this.volumeReadOnlyStatus_ = {}; | 59 this.volumeReadOnlyStatus_ = {}; |
60 | |
61 /** | |
62 * File path of the last directory that is not under virtual search directory. | |
63 * This is the path to go to when the search box content clears on GData. | |
64 * @private | |
65 * @type {string} | |
66 */ | |
67 this.lastNonGDataSearchDir_ = null; | |
60 } | 68 } |
61 | 69 |
62 /** | 70 /** |
63 * The name of the directory containing externally | 71 * The name of the directory containing externally |
64 * mounted removable storage volumes. | 72 * mounted removable storage volumes. |
65 */ | 73 */ |
66 DirectoryModel.REMOVABLE_DIRECTORY = 'removable'; | 74 DirectoryModel.REMOVABLE_DIRECTORY = 'removable'; |
67 | 75 |
68 /** | 76 /** |
69 * The name of the directory containing externally | 77 * The name of the directory containing externally |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
490 callback) { | 498 callback) { |
491 var field = this.fileList_.sortStatus.field; | 499 var field = this.fileList_.sortStatus.field; |
492 if (field) { | 500 if (field) { |
493 this.prepareSortEntries_(entries, field, callback); | 501 this.prepareSortEntries_(entries, field, callback); |
494 } else { | 502 } else { |
495 callback(); | 503 callback(); |
496 } | 504 } |
497 }; | 505 }; |
498 | 506 |
499 /** | 507 /** |
508 * Gets name that should be dispalyed in the UI for the entry. | |
509 * @param {string} path Full path of the entry whose display name we are | |
510 * getting. | |
511 * @param {string} defaultName Default name to use if no name is calculated. | |
512 * @return {string} Name to be used for display. | |
513 */ | |
514 DirectoryModel.prototype.getDisplayName = function(path, defaultName) { | |
515 var searchResultName = util.getFileAndDisplayNameForGDataSearchResult(path); | |
516 return searchResultName ? searchResultName.displayName : defaultName; | |
517 }; | |
518 | |
519 /** | |
500 * Delete the list of files and directories from filesystem and | 520 * Delete the list of files and directories from filesystem and |
501 * update the file list. | 521 * update the file list. |
502 * @param {Array.<Entry>} entries Entries to delete. | 522 * @param {Array.<Entry>} entries Entries to delete. |
503 * @param {function()=} opt_callback Called when finished. | 523 * @param {function()=} opt_callback Called when finished. |
504 */ | 524 */ |
505 DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { | 525 DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { |
506 var downcount = entries.length + 1; | 526 var downcount = entries.length + 1; |
507 | 527 |
508 var onComplete = opt_callback ? function() { | 528 var onComplete = opt_callback ? function() { |
509 if (--downcount == 0) | 529 if (--downcount == 0) |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
590 */ | 610 */ |
591 DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, | 611 DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, |
592 opt_successCallback) { | 612 opt_successCallback) { |
593 var self = this; | 613 var self = this; |
594 function onSuccess(newEntry) { | 614 function onSuccess(newEntry) { |
595 self.prefetchCacheForSorting_([newEntry], function() { | 615 self.prefetchCacheForSorting_([newEntry], function() { |
596 var fileList = self.fileList_; | 616 var fileList = self.fileList_; |
597 var index = fileList.indexOf(entry); | 617 var index = fileList.indexOf(entry); |
598 if (index >= 0) | 618 if (index >= 0) |
599 fileList.splice(index, 1, newEntry); | 619 fileList.splice(index, 1, newEntry); |
600 self.selectEntry(newName); | 620 self.selectEntry(newEntry.name); |
601 // If the entry doesn't exist in the list it mean that it updated from | 621 // If the entry doesn't exist in the list it mean that it updated from |
602 // outside (probably by directory rescan). | 622 // outside (probably by directory rescan). |
603 if (opt_successCallback) | 623 if (opt_successCallback) |
604 opt_successCallback(); | 624 opt_successCallback(); |
605 }); | 625 }); |
606 } | 626 } |
607 entry.moveTo(this.currentDirEntry_, newName, onSuccess, errorCallback); | 627 |
628 var newNameToUse = this.getNameToUseInRenaming_(entry, newName); | |
629 entry.moveTo(this.currentDirEntry_, newNameToUse, onSuccess, errorCallback); | |
608 }; | 630 }; |
609 | 631 |
610 /** | 632 /** |
611 * Checks if current directory contains a file or directory with this name. | 633 * Checks if current directory contains a file or directory with this name. |
634 * @param {string} entry Entry to which newName will be given. | |
612 * @param {string} newName Name to check. | 635 * @param {string} newName Name to check. |
613 * @param {function(boolean, boolean?)} callback Called when the result's | 636 * @param {function(boolean, boolean?)} callback Called when the result's |
614 * available. First parameter is true if the entry exists and second | 637 * available. First parameter is true if the entry exists and second |
615 * is true if it's a file. | 638 * is true if it's a file. |
616 */ | 639 */ |
617 DirectoryModel.prototype.doesExist = function(newName, callback) { | 640 DirectoryModel.prototype.doesExist = function(entry, newName, callback) { |
SeRya
2012/05/10 08:44:16
May be rename newName to newDisplayName (here and
tbarzic
2012/05/10 23:28:02
Done.
| |
618 util.resolvePath(this.currentDirEntry_, newName, | 641 var newNameToUse = this.getNameToUseInRenaming_(entry, newName); |
642 | |
643 util.resolvePath(this.currentDirEntry_, newNameToUse, | |
619 function(entry) { | 644 function(entry) { |
620 callback(true, entry.isFile); | 645 callback(true, entry.isFile); |
621 }, | 646 }, |
622 callback.bind(window, false)); | 647 callback.bind(window, false)); |
623 }; | 648 }; |
624 | 649 |
625 /** | 650 /** |
651 * Creates file name that should be used as a new file name in filesystem | |
652 * operations while renaming. It the given entry is not a gdata search result | |
653 * entry, |newName| will be used. | |
654 * | |
655 * @private | |
656 * @param {Entry} entry Entry which is being renamed. | |
657 * @param {string} newName The new file name provided by user. | |
658 * @return {string} File name that should be used in renaming filesystem | |
659 * operations. | |
660 */ | |
661 DirectoryModel.prototype.getNameToUseInRenaming_ = function(entry, newName) { | |
SeRya
2012/05/10 08:44:16
This method effectively is opposite to getDisplayN
tbarzic
2012/05/10 23:28:02
Done.
| |
662 // If we are renaming gdata search result, we'll have to format newName to | |
663 // use in file system operation like: <resource_id>.<file_name>. | |
664 var searchResultName = | |
665 util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath); | |
666 return searchResultName ? searchResultName.resourceId + '.' + newName : | |
667 newName; | |
668 }; | |
669 | |
670 /** | |
626 * Creates directory and updates the file list. | 671 * Creates directory and updates the file list. |
627 * | 672 * |
628 * @param {string} name Directory name. | 673 * @param {string} name Directory name. |
629 * @param {function} successCallback Callback on success. | 674 * @param {function} successCallback Callback on success. |
630 * @param {function} errorCallback Callback on failure. | 675 * @param {function} errorCallback Callback on failure. |
631 */ | 676 */ |
632 DirectoryModel.prototype.createDirectory = function(name, successCallback, | 677 DirectoryModel.prototype.createDirectory = function(name, successCallback, |
633 errorCallback) { | 678 errorCallback) { |
634 var self = this; | 679 var self = this; |
635 function onSuccess(newEntry) { | 680 function onSuccess(newEntry) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
724 * changed. | 769 * changed. |
725 * | 770 * |
726 * @private | 771 * @private |
727 * @param {boolean} initial True if it comes from setupPath and | 772 * @param {boolean} initial True if it comes from setupPath and |
728 * false if caused by an user action. | 773 * false if caused by an user action. |
729 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. | 774 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. |
730 * @param {function} opt_callback Executed if the directory loads successfully. | 775 * @param {function} opt_callback Executed if the directory loads successfully. |
731 */ | 776 */ |
732 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, | 777 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, |
733 opt_callback) { | 778 opt_callback) { |
779 if (this.shouldClearSearch(this.currentDirEntry_, dirEntry)) | |
780 this.clearSearch(); | |
734 var previous = this.currentDirEntry_; | 781 var previous = this.currentDirEntry_; |
735 this.currentDirEntry_ = dirEntry; | 782 this.currentDirEntry_ = dirEntry; |
736 function onRescanComplete() { | 783 function onRescanComplete() { |
737 if (opt_callback) | 784 if (opt_callback) |
738 opt_callback(); | 785 opt_callback(); |
739 // For tests that open the dialog to empty directories, everything | 786 // For tests that open the dialog to empty directories, everything |
740 // is loaded at this point. | 787 // is loaded at this point. |
741 chrome.test.sendMessage('directory-change-complete'); | 788 chrome.test.sendMessage('directory-change-complete'); |
742 } | 789 } |
743 this.updateRootsListSelection_(); | 790 this.updateRootsListSelection_(); |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1102 // Re-place the entry into the roots data model to force re-rendering. | 1149 // Re-place the entry into the roots data model to force re-rendering. |
1103 this.rootsList_.splice(index, 1, entry); | 1150 this.rootsList_.splice(index, 1, entry); |
1104 | 1151 |
1105 if (rootPath == this.rootPath) { | 1152 if (rootPath == this.rootPath) { |
1106 // TODO(kaznacheev): Consider changing to the most recently used root. | 1153 // TODO(kaznacheev): Consider changing to the most recently used root. |
1107 this.changeDirectory(this.getDefaultDirectory()); | 1154 this.changeDirectory(this.getDefaultDirectory()); |
1108 } | 1155 } |
1109 }; | 1156 }; |
1110 | 1157 |
1111 /** | 1158 /** |
1159 * Performs search and displays results. The search type is dependent on the | |
1160 * current directory. If we are currently on gdata, server side content search | |
1161 * over gdata mount point. If the current directory is not on the gdata, file | |
1162 * name search over current directory wil be performed. | |
1163 * | |
1164 * @param {string} query Query that will be searched for. | |
1165 */ | |
1166 DirectoryModel.prototype.search = function(query) { | |
1167 if (!query) { | |
1168 this.clearSearch(); | |
1169 return; | |
1170 } | |
1171 | |
1172 // If we are offline, let's fallback to file name search inside dir. | |
1173 if (this.getRootType() == DirectoryModel.RootType.GDATA && | |
1174 !util.isOffline()) { | |
1175 var self = this; | |
1176 // Create shadow directory which will contein search results. | |
1177 this.root_.getDirectory(util.createGDataSearchPath(query), | |
1178 {create: false}, | |
1179 function(dir) { | |
1180 self.updateCurrentDirAndSearch(dir); | |
1181 }); | |
1182 } else { | |
1183 this.addFilter( | |
1184 'searchbox', | |
1185 function(e) { | |
1186 return e.name.substring(0, query.length) == query; | |
1187 }); | |
1188 } | |
1189 }; | |
1190 | |
1191 /** | |
1192 * Changed |currentDirEntry_| and triggers rescan for gdata search. | |
1193 * @param {Entry} searchDir Directory entry that will be used to collect search | |
1194 * results. | |
1195 */ | |
1196 DirectoryModel.prototype.updateCurrentDirAndSearch = function(searchDir) { | |
1197 if (!util.isGDataSearchPath(this.currentDirEntry_.fullPath)) | |
1198 this.lastNonGDataSearchDir_ = this.currentDirEntry_; | |
1199 // We have to update currentDirEntry_ so we ignore DirectoryChanged | |
1200 // notifications. | |
1201 this.currentDirEntry_ = searchDir; | |
SeRya
2012/05/10 08:44:16
It's better but still flawed. You shouldn't change
tbarzic
2012/05/10 23:28:02
Done.
| |
1202 this.rescanSoon(); | |
1203 }; | |
1204 | |
1205 /** | |
1206 * Checks if the search state of the directory should be reset when changing | |
1207 * directories. | |
1208 * @param {Entry} oldEntry Dir entry from which directory should be changed. | |
1209 * @param {Entry} newEntry Dire entry to which directory should be changed. | |
1210 * @return {boolean} Should search state be cleared. | |
1211 */ | |
1212 DirectoryModel.prototype.shouldClearSearch = function(oldEntry, newEntry) { | |
1213 var isOldOnGData = DirectoryModel.getRootType(oldEntry.fullPath) == | |
1214 DirectoryModel.RootType.GDATA; | |
1215 var isNewOnGData = DirectoryModel.getRootType(newEntry.fullPath) == | |
1216 DirectoryModel.RootType.GDATA; | |
1217 | |
1218 // Searches on gdata root and non gdata root are different, so let's just undo | |
1219 // the search if the search type for directories changes. | |
1220 // Also, if we are changing directory on gdata, We should reset directory | |
1221 // state if it was changed by a search in progress. | |
1222 return !util.isOffline() && (isNewOnGData || (isOldOnGData != isNewOnGData)); | |
1223 }; | |
1224 | |
1225 /** | |
1226 * Clears any state set by previous searches. | |
1227 */ | |
1228 DirectoryModel.prototype.clearSearch = function() { | |
1229 if (this.lastNonGDataSearchDir_) | |
1230 this.currentDirEntry_ = this.lastNonGDataSearchDir_; | |
1231 this.lastNonGDataSearchDir_ = null; | |
1232 // This will trigger rescan. | |
1233 this.removeFilter('searchbox'); | |
1234 }; | |
1235 | |
1236 /** | |
1112 * @param {string} path Any path. | 1237 * @param {string} path Any path. |
1113 * @return {string} The root path. | 1238 * @return {string} The root path. |
1114 */ | 1239 */ |
1115 DirectoryModel.getRootPath = function(path) { | 1240 DirectoryModel.getRootPath = function(path) { |
1116 var type = DirectoryModel.getRootType(path); | 1241 var type = DirectoryModel.getRootType(path); |
1117 | 1242 |
1118 if (type == DirectoryModel.RootType.DOWNLOADS) | 1243 if (type == DirectoryModel.RootType.DOWNLOADS) |
1119 return '/' + DirectoryModel.DOWNLOADS_DIRECTORY; | 1244 return '/' + DirectoryModel.DOWNLOADS_DIRECTORY; |
1120 if (type == DirectoryModel.RootType.GDATA) | 1245 if (type == DirectoryModel.RootType.GDATA) |
1121 return '/' + DirectoryModel.GDATA_DIRECTORY; | 1246 return '/' + DirectoryModel.GDATA_DIRECTORY; |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1262 /** | 1387 /** |
1263 * @private | 1388 * @private |
1264 */ | 1389 */ |
1265 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { | 1390 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { |
1266 metrics.recordInterval('DirectoryScan'); | 1391 metrics.recordInterval('DirectoryScan'); |
1267 if (this.dir_.fullPath == | 1392 if (this.dir_.fullPath == |
1268 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 1393 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
1269 metrics.recordMediumCount('DownloadsCount', this.list_.length); | 1394 metrics.recordMediumCount('DownloadsCount', this.list_.length); |
1270 } | 1395 } |
1271 }; | 1396 }; |
OLD | NEW |