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 // 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 |