Index: chrome/browser/resources/file_manager/js/directory_model.js |
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js |
index 0cc59331dc9f9b8719b390d0b09362e8b5c02c60..b85f495e174fe702c5878d4e3ddecb59cfc93b2c 100644 |
--- a/chrome/browser/resources/file_manager/js/directory_model.js |
+++ b/chrome/browser/resources/file_manager/js/directory_model.js |
@@ -57,6 +57,21 @@ function DirectoryModel(root, singleSelection, showGData, metadataCache) { |
* @type {Object.<string, boolean>} |
*/ |
this.volumeReadOnlyStatus_ = {}; |
+ |
+ /** |
+ * Directory in which search results are displayed. Not null iff search |
+ * results are being displayed. |
+ * @private |
+ * @type {Entry} |
+ */ |
+ this.searchDirEntry_ = null; |
+ |
+ /** |
+ * Is search in progress. |
+ * @private |
+ * @type {boolean} |
+ */ |
+ this.isSearching_ = false; |
} |
/** |
@@ -93,6 +108,21 @@ DirectoryModel.DOWNLOADS_DIRECTORY = 'Downloads'; |
DirectoryModel.GDATA_DIRECTORY = 'gdata'; |
/** |
+ * Root path used for displaying gdata content search results. |
+ * Search results will be shown in directory 'GDATA_SEARCH_ROOT_PATH/query'. |
+ * |
+ * @const |
+ * @type {string} |
+ */ |
+DirectoryModel.GDATA_SEARCH_ROOT_PATH = '/gdata/.search'; |
+ |
+/** |
+ * @const |
+ * @type {Array.<string>} |
+ */ |
+DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS = ['', 'gdata', '.search']; |
+ |
+/** |
* DirectoryModel extends cr.EventTarget. |
*/ |
DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype; |
@@ -150,6 +180,20 @@ DirectoryModel.prototype.isReadOnly = function() { |
}; |
/** |
+ * @return {boolean} True if search is in progress. |
+ */ |
+DirectoryModel.prototype.isSearching = function() { |
+ return this.isSearching_; |
+}; |
+ |
+/** |
+ * @return {boolean} True if we are currently showing search results. |
+ */ |
+DirectoryModel.prototype.isOnGDataSearchDir = function() { |
+ return this.getSearchOrCurrentDirEntry() != this.getCurrentDirEntry(); |
+}; |
+ |
+/** |
* @param {strin} path Path to check. |
* @return {boolean} True if the |path| is read only. |
*/ |
@@ -205,6 +249,16 @@ DirectoryModel.prototype.getCurrentDirEntry = function() { |
}; |
/** |
+ * If search results are being displayed, returns search directory, else returns |
+ * current directory. |
+ * |
+ * @return {DirectoryEntry} search or directory entry. |
+ */ |
+DirectoryModel.prototype.getSearchOrCurrentDirEntry = function() { |
+ return this.searchDirEntry_ || this.currentDirEntry_; |
+}; |
+ |
+/** |
* @return {string} Path for the current directory. |
*/ |
DirectoryModel.prototype.getCurrentDirPath = function() { |
@@ -409,7 +463,7 @@ DirectoryModel.prototype.createScanner_ = function(list, successCallback) { |
} |
return new DirectoryModel.Scanner( |
- this.currentDirEntry_, |
+ this.getSearchOrCurrentDirEntry(), |
list, |
onSuccess, |
onFailure, |
@@ -497,6 +551,38 @@ DirectoryModel.prototype.prefetchCacheForSorting_ = function(entries, |
}; |
/** |
+ * Gets name that should be displayed in the UI for the entry. |
+ * @param {string} path Full path of the entry whose display name we are |
+ * getting. |
+ * @param {string} defaultName Default name to use if no name is calculated. |
+ * @return {string} Name to be used for display. |
+ */ |
+DirectoryModel.prototype.getDisplayName = function(path, defaultName) { |
+ var searchResultName = util.getFileAndDisplayNameForGDataSearchResult(path); |
+ return searchResultName ? searchResultName.displayName : defaultName; |
+}; |
+ |
+/** |
+ * Creates file name that should be used as a new file name in filesystem |
+ * operations while renaming. It the given entry is not a gdata search result |
dgozman
2012/05/15 11:25:06
typo: it -> if
tbarzic
2012/05/16 03:50:04
Done.
|
+ * entry, |newName| will be used. |
dgozman
2012/05/15 11:25:06
typo: newName -> displayName
tbarzic
2012/05/16 03:50:04
Done.
|
+ * |
+ * @private |
+ * @param {Entry} entry Entry which is being renamed. |
+ * @param {string} displayName The new file name provided by user. |
+ * @return {string} File name that should be used in renaming filesystem |
+ * operations. |
+ */ |
+DirectoryModel.prototype.getEntryName_ = function(entry, displayName) { |
dgozman
2012/05/15 11:25:06
Confusing name. I'd say that getEntryName == entry
tbarzic
2012/05/16 03:50:04
Done.
|
+ // If we are renaming gdata search result, we'll have to format newName to |
+ // use in file system operation like: <resource_id>.<file_name>. |
+ var searchResultName = |
+ util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath); |
+ return searchResultName ? searchResultName.resourceId + '.' + displayName : |
+ displayName; |
+}; |
+ |
+/** |
* Delete the list of files and directories from filesystem and |
* update the file list. |
* @param {Array.<Entry>} entries Entries to delete. |
@@ -533,11 +619,16 @@ DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { |
* @param {string} name Filename. |
*/ |
DirectoryModel.prototype.onEntryChanged = function(name) { |
- var currentEntry = this.currentDirEntry_; |
+ var currentEntry = this.getSearchOrCurrentDirEntry(); |
+ if (currentEntry != this.currentDirEntry_) |
+ return; |
var dm = this.fileList_; |
var self = this; |
function onEntryFound(entry) { |
+ // Do nothing if current directory changed during async operations. |
+ if (self.currentDirEntry_ != currentEntry) |
dgozman
2012/05/15 11:25:06
This should probably be:
if (self.getSearchOrCurre
tbarzic
2012/05/16 03:50:04
Done.
|
+ return; |
self.prefetchCacheForSorting_([entry], function() { |
// Do nothing if current directory changed during async operations. |
if (self.currentDirEntry_ != currentEntry) |
@@ -565,7 +656,7 @@ DirectoryModel.prototype.onEntryChanged = function(name) { |
dm.splice(index, 1); |
}; |
- util.resolvePath(this.currentDirEntry_, name, onEntryFound, onError); |
+ util.resolvePath(currentEntry, name, onEntryFound, onError); |
}; |
/** |
@@ -584,11 +675,12 @@ DirectoryModel.prototype.findIndexByName_ = function(name) { |
/** |
* Rename the entry in the filesystem and update the file list. |
* @param {Entry} entry Entry to rename. |
- * @param {string} newName New name. |
+ * @param {string} newDisplayName New name. |
* @param {function} errorCallback Called on error. |
* @param {function} opt_successCallback Called on success. |
*/ |
-DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, |
+DirectoryModel.prototype.renameEntry = function(entry, newDisplayName, |
+ errorCallback, |
opt_successCallback) { |
var self = this; |
function onSuccess(newEntry) { |
@@ -597,25 +689,31 @@ DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, |
var index = fileList.indexOf(entry); |
if (index >= 0) |
fileList.splice(index, 1, newEntry); |
- self.selectEntry(newName); |
+ self.selectEntry(newEntry.name); |
// If the entry doesn't exist in the list it mean that it updated from |
// outside (probably by directory rescan). |
if (opt_successCallback) |
opt_successCallback(); |
}); |
} |
- entry.moveTo(this.currentDirEntry_, newName, onSuccess, errorCallback); |
+ |
+ var newEntryName = this.getEntryName_(entry, newDisplayName); |
+ entry.moveTo(this.getSearchOrCurrentDirEntry(), newEntryName, onSuccess, |
+ errorCallback); |
}; |
/** |
* Checks if current directory contains a file or directory with this name. |
- * @param {string} newName Name to check. |
+ * @param {string} entry Entry to which newName will be given. |
+ * @param {string} displayName Name to check. |
* @param {function(boolean, boolean?)} callback Called when the result's |
* available. First parameter is true if the entry exists and second |
* is true if it's a file. |
*/ |
-DirectoryModel.prototype.doesExist = function(newName, callback) { |
- util.resolvePath(this.currentDirEntry_, newName, |
+DirectoryModel.prototype.doesExist = function(entry, displayName, callback) { |
+ var entryName = this.getEntryName_(entry, displayName); |
+ |
+ util.resolvePath(this.getSearchOrCurrentDirEntry(), entryName, |
dgozman
2012/05/15 11:25:06
What if new renamed name does not conform to searc
tbarzic
2012/05/16 03:50:04
this case is handled in gdata code (a bit hacky, b
|
function(entry) { |
callback(true, entry.isFile); |
}, |
@@ -661,7 +759,15 @@ DirectoryModel.prototype.createDirectory = function(name, successCallback, |
* @param {string} path New current directory path. |
*/ |
DirectoryModel.prototype.changeDirectory = function(path) { |
- this.resolveDirectory(path, function(directoryEntry) { |
+ var targetPath = path; |
+ // We should not be changing directory to gdata search path. If we do, default |
+ // to gdata root. |
+ if (DirectoryModel.isGDataSearchPath(path)) { |
+ console.error('Attempt to change directory to search path.'); |
+ targetPath = '/' + DirectoryModel.GDATA_DIRECTORY; |
+ } |
+ |
+ this.resolveDirectory(targetPath, function(directoryEntry) { |
this.changeDirectoryEntry_(false, directoryEntry); |
}.bind(this), function(error) { |
console.error('Error changing directory to ' + path + ': ', error); |
@@ -731,6 +837,7 @@ DirectoryModel.prototype.changeDirectoryOrRoot = function(path) { |
*/ |
DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, |
opt_callback) { |
+ this.clearSearch_(); |
var previous = this.currentDirEntry_; |
this.currentDirEntry_ = dirEntry; |
function onRescanComplete() { |
@@ -1109,6 +1216,56 @@ DirectoryModel.prototype.prepareUnmount = function(rootPath) { |
}; |
/** |
+ * Performs search and displays results. The search type is dependent on the |
+ * current directory. If we are currently on gdata, server side content search |
+ * over gdata mount point. If the current directory is not on the gdata, file |
+ * name search over current directory wil be performed. |
+ * |
+ * @param {string} query Query that will be searched for. |
+ */ |
+DirectoryModel.prototype.search = function(query) { |
+ if (!query) { |
+ this.clearSearch_(); |
+ return; |
+ } |
+ |
+ this.isSearching_ = true; |
+ |
+ // If we are offline, let's fallback to file name search inside dir. |
+ if (this.getRootType() == DirectoryModel.RootType.GDATA && |
+ !util.isOffline()) { |
+ var self = this; |
+ // Create shadow directory which will contein search results. |
dgozman
2012/05/15 11:25:06
typo: contein
tbarzic
2012/05/16 03:50:04
Done.
|
+ this.root_.getDirectory(DirectoryModel.createGDataSearchPath(query), |
+ {create: false}, |
+ function(dir) { |
+ self.searchDirEntry_ = dir; |
+ self.rescanSoon(); |
+ }, |
+ this.clearSearch_.bind(this)); |
+ } else { |
+ this.searchDirEntry_ = this.currentDirEntry_; |
+ this.addFilter( |
+ 'searchbox', |
+ function(e) { |
+ return e.name.substring(0, query.length) == query; |
+ }); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Clears any state set by previous searches. |
+ * @private |
+ */ |
+DirectoryModel.prototype.clearSearch_ = function() { |
+ this.searchDirEntry_ = null; |
+ this.isSearching_ = false; |
+ // This will trigger rescan. |
+ this.removeFilter('searchbox'); |
dgozman
2012/05/15 11:25:06
We may not have this filter present. This will pro
tbarzic
2012/05/16 03:50:04
I haven't seen the exception when we are removing
|
+}; |
+ |
+/** |
* @param {string} path Any path. |
* @return {string} The root path. |
*/ |
@@ -1173,6 +1330,28 @@ DirectoryModel.isRootPath = function(path) { |
}; |
/** |
+ * Checks if the provided path is under gdata search. |
+ * |
+ * @param {string} path Path to be tested. |
+ * @return {boolean} Is the path gdata search path. |
+ */ |
+DirectoryModel.isGDataSearchPath = function(path) { |
+ return path == DirectoryModel.GDATA_SEARCH_ROOT_PATH || |
+ path.search(DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/') == 0; |
dgozman
2012/05/15 11:25:06
search -> indexOf ?
tbarzic
2012/05/16 03:50:04
Done.
|
+}; |
+ |
+/** |
+ * Creates directory path in which gdata content search results for |query| |
+ * should be displayed. |
+ * |
+ * @param {string} query Search query. |
+ * @return {string} Virtual directory path for search results. |
+ */ |
+DirectoryModel.createGDataSearchPath = function(query) { |
+ return DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/' + query; |
+}; |
+ |
+/** |
* @constructor |
* @extends cr.EventTarget |
* @param {DirectoryEntry} dir Directory to scan. |