Commit 0a0291c6 authored by yoshiki@chromium.org's avatar yoshiki@chromium.org

Files.app: Update the list partially when changed

This patch makes the list redraw partially instead of full-redraw when some contents are changed in the directory. This should improve the performance of redraw.

In addition, as the result of the fix, the cache is not flashed on partial redraw, and the issue 374713 has gone.

BUG=374713
TEST=manaul tested

Review URL: https://codereview.chromium.org/486783006

Cr-Commit-Position: refs/heads/master@{#291366}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291366 0039d316-1c4b-4281-b951-d872f2087c98
parent e4abc5e7
...@@ -662,6 +662,53 @@ DirectoryContents.prototype.scan = function(refresh) { ...@@ -662,6 +662,53 @@ DirectoryContents.prototype.scan = function(refresh) {
errorCallback.bind(this)); errorCallback.bind(this));
}; };
/**
* Adds/removes/updates items of file list.
* @param {Array.<Entry>} updatedEntries Entries of updated/added files.
* @param {Array.<string>} removedUrls URLs of removed files.
*/
DirectoryContents.prototype.update = function(updatedEntries, removedUrls) {
var removedMap = {};
for (var i = 0; i < removedUrls.length; i++) {
removedMap[removedUrls[i]] = true;
}
var updatedMap = {};
for (var i = 0; i < updatedEntries.length; i++) {
updatedMap[updatedEntries[i].toURL()] = updatedEntries[i];
}
var updatedList = [];
for (var i = 0; i < this.fileList_.length; i++) {
var url = this.fileList_.item(i).toURL();
if (url in removedMap) {
this.fileList_.splice(i, 1);
i--;
continue;
}
if (url in updatedMap) {
updatedList.push(updatedMap[url]);
delete updatedMap[url];
}
}
var addedList = [];
for (var url in updatedMap) {
addedList.push(updatedMap[url]);
}
if (removedUrls.length > 0)
this.fileList_.metadataCache_.clearByUrl(removedUrls, '*');
this.prefetchMetadata(updatedList, true, function() {
this.onNewEntries_(true, addedList);
this.onScanFinished_();
this.onScanCompleted_();
}.bind(this));
};
/** /**
* Cancels the running scan. * Cancels the running scan.
*/ */
......
...@@ -171,21 +171,21 @@ DirectoryModel.prototype.onWatcherDirectoryChanged_ = function(event) { ...@@ -171,21 +171,21 @@ DirectoryModel.prototype.onWatcherDirectoryChanged_ = function(event) {
var directoryEntry = this.getCurrentDirEntry(); var directoryEntry = this.getCurrentDirEntry();
if (event.changedFiles) { if (event.changedFiles) {
var urls = event.changedFiles.map(function(change) { return change.url; }); var addedOrUpdatedFileUrls = [];
util.URLsToEntries(urls).then(function(result) { var deletedFileUrls = [];
// Removes the metadata of invalid entries. event.changedFiles.forEach(function(change) {
if (result.failureUrls.length > 0) if (change.changes.length === 1 && change.changes[0] === 'delete')
this.metadataCache_.clearByUrl(result.failureUrls, '*'); deletedFileUrls.push(change.url);
else
// Rescans after force-refreshing the metadata of the changed entries. addedOrUpdatedFileUrls.push(change.url);
var entries = result.entries; });
if (entries.length) {
this.currentDirContents_.prefetchMetadata(entries, true, function() { util.URLsToEntries(addedOrUpdatedFileUrls).then(function(result) {
this.rescanSoon(false); deletedFileUrls = deletedFileUrls.concat(result.failureUrls);
}.bind(this));
} else { // Passing the resolved entries and failed URLs as the removed files.
this.rescanSoon(false); // The URLs are removed files and they chan't be resolved.
} this.partialUpdate_(result.entries, deletedFileUrls);
}.bind(this)).catch(function(error) { }.bind(this)).catch(function(error) {
console.error('Error in proceeding the changed event.', error, console.error('Error in proceeding the changed event.', error,
'Fallback to force-refresh'); 'Fallback to force-refresh');
...@@ -445,6 +445,64 @@ DirectoryModel.prototype.clearAndScan_ = function(newDirContents, ...@@ -445,6 +445,64 @@ DirectoryModel.prototype.clearAndScan_ = function(newDirContents,
onDone, onFailed, onUpdated, onCancelled); onDone, onFailed, onUpdated, onCancelled);
}; };
/**
* Adds/removes/updates items of file list.
* @param {Array.<Entry>} updatedEntries Entries of updated/added files.
* @param {Array.<string>} removedUrls URLs of removed files.
* @private
*/
DirectoryModel.prototype.partialUpdate_ =
function(changedEntries, removedUrls) {
// This update should be included in the current running update.
if (this.pendingScan_)
return;
if (this.runningScan_) {
// Do update after the current scan is finished.
var previousScan = this.runningScan_;
var onPreviousScanCompleted = function() {
previousScan.removeEventListener('scan-completed',
onPreviousScanCompleted);
// Run the update asynchronously.
Promise.resolve().then(function() {
if (!this.runningScan_)
this.partialUpdate_(changedEntries, removedUrls);
}.bind(this));
}.bind(this);
previousScan.addEventListener('scan-completed', onPreviousScanCompleted);
return;
}
var onFinish = function() {
this.runningScan_ = null;
this.currentDirContents_.removeEventListener(
'scan-completed', onCompleted);
this.currentDirContents_.removeEventListener('scan-failed', onFailure);
this.currentDirContents_.removeEventListener(
'scan-cancelled', onCancelled);
}.bind(this);
var onCompleted = function() {
onFinish();
cr.dispatchSimpleEvent(this, 'rescan-completed');
}.bind(this);
var onFailure = function() {
onFinish();
};
var onCancelled = function() {
onFinish();
};
this.runningScan_ = this.currentDirContents_;
this.currentDirContents_.addEventListener('scan-completed', onCompleted);
this.currentDirContents_.addEventListener('scan-failed', onFailure);
this.currentDirContents_.addEventListener('scan-cancelled', onCancelled);
this.currentDirContents_.update(changedEntries, removedUrls);
};
/** /**
* Perform a directory contents scan. Should be called only from rescan() and * Perform a directory contents scan. Should be called only from rescan() and
* clearAndScan_(). * clearAndScan_().
...@@ -480,7 +538,16 @@ DirectoryModel.prototype.scan_ = function( ...@@ -480,7 +538,16 @@ DirectoryModel.prototype.scan_ = function(
return false; return false;
}.bind(this); }.bind(this);
var onFinished = function() {
dirContents.removeEventListener('scan-completed', onSuccess);
dirContents.removeEventListener('scan-updated', updatedCallback);
dirContents.removeEventListener('scan-failed', onFailure);
dirContents.removeEventListener('scan-cancelled', cancelledCallback);
};
var onSuccess = function() { var onSuccess = function() {
onFinished();
// Record metric for Downloads directory. // Record metric for Downloads directory.
if (!dirContents.isSearch()) { if (!dirContents.isSearch()) {
var locationInfo = var locationInfo =
...@@ -500,6 +567,8 @@ DirectoryModel.prototype.scan_ = function( ...@@ -500,6 +567,8 @@ DirectoryModel.prototype.scan_ = function(
}.bind(this); }.bind(this);
var onFailure = function() { var onFailure = function() {
onFinished();
this.runningScan_ = null; this.runningScan_ = null;
this.scanFailures_++; this.scanFailures_++;
failureCallback(); failureCallback();
...@@ -511,12 +580,17 @@ DirectoryModel.prototype.scan_ = function( ...@@ -511,12 +580,17 @@ DirectoryModel.prototype.scan_ = function(
this.rescanLater(refresh); this.rescanLater(refresh);
}.bind(this); }.bind(this);
var onCancelled = function() {
onFinished();
cancelledCallback();
};
this.runningScan_ = dirContents; this.runningScan_ = dirContents;
dirContents.addEventListener('scan-completed', onSuccess); dirContents.addEventListener('scan-completed', onSuccess);
dirContents.addEventListener('scan-updated', updatedCallback); dirContents.addEventListener('scan-updated', updatedCallback);
dirContents.addEventListener('scan-failed', onFailure); dirContents.addEventListener('scan-failed', onFailure);
dirContents.addEventListener('scan-cancelled', cancelledCallback); dirContents.addEventListener('scan-cancelled', onCancelled);
dirContents.scan(refresh); dirContents.scan(refresh);
}; };
...@@ -595,7 +669,7 @@ DirectoryModel.prototype.onEntriesChanged = function(kind, entries) { ...@@ -595,7 +669,7 @@ DirectoryModel.prototype.onEntriesChanged = function(kind, entries) {
entriesToAdd.push(entries[i]); entriesToAdd.push(entries[i]);
} }
} }
this.getFileList().push.apply(this.getFileList(), entriesToAdd); this.partialUpdate_(entriesToAdd, []);
}.bind(this)).catch(function(error) { }.bind(this)).catch(function(error) {
console.error(error.stack || error); console.error(error.stack || error);
}); });
...@@ -603,11 +677,7 @@ DirectoryModel.prototype.onEntriesChanged = function(kind, entries) { ...@@ -603,11 +677,7 @@ DirectoryModel.prototype.onEntriesChanged = function(kind, entries) {
case util.EntryChangedKind.DELETED: case util.EntryChangedKind.DELETED:
// This is the delete event. // This is the delete event.
for (var i = 0; i < entries.length; i++) { this.partialUpdate_([], util.entriesToURLs(entries));
var index = this.findIndexByEntry_(entries[i]);
if (index >= 0)
this.getFileList().splice(index, 1);
}
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment