Index: ui/file_manager/file_manager/foreground/js/import_controller.js |
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js |
index b6f99d4d09ac9c18fe272a07b5e45f4f7f58179c..578ea182588c66022e206eb187a3731a1a6c0c8f 100644 |
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js |
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js |
@@ -10,6 +10,7 @@ importer.ResponseId = { |
HIDDEN: 'hidden', |
SCANNING: 'scanning', |
NO_MEDIA: 'no_media', |
+ NO_SPACE: 'no_spcae', |
Steve McKay
2015/01/26 18:08:43
INSUFFICIENT_SPACE: 'insufficient_space'
|
EXECUTABLE: 'executable' |
}; |
@@ -55,9 +56,15 @@ importer.ImportController = |
/** |
* A cache of scans by volumeId, directory URL. |
* Currently only scans of directories are cached. |
- * @private {!Object.<string, !Object.<string, !importer.ScanResult>>} |
+ * @private {!importer.ScanCache} |
+ * @const |
*/ |
- this.cachedScans_ = {}; |
+ this.scanCache_ = new importer.ScanCache(); |
+ |
+ /** |
+ * @private {number} |
+ */ |
+ this.localVolumeAvilableSize_ = 0; |
var listener = this.onScanEvent_.bind(this); |
this.scanner_.addObserver(listener); |
@@ -65,8 +72,6 @@ importer.ImportController = |
window.addEventListener('pagehide', function() { |
this.scanner_.removeObserver(listener); |
}.bind(this)); |
- this.environment_.addVolumeUnmountListener( |
- this.onVolumeUnmounted_.bind(this)); |
}; |
/** |
@@ -77,17 +82,16 @@ importer.ImportController = |
*/ |
importer.ImportController.prototype.onScanEvent_ = function(event, result) { |
if (event === importer.ScanEvent.INVALIDATED) { |
- for (var key in this.cachedScans_) { |
- for (var url in this.cachedScans_[key]) { |
- if (this.cachedScans_[key][url].isInvalidated()) { |
- delete this.cachedScans_[key][url]; |
- } |
- } |
+ if (this.scanCache_.currentCache.isInvalidated()) { |
Steve McKay
2015/01/26 18:08:43
Let's keep this super simple for now. When *any* s
|
+ this.scanCache_.clear(); |
} |
} |
if (event === importer.ScanEvent.FINALIZED || |
event === importer.ScanEvent.INVALIDATED) { |
- this.updateCommands_(); |
+ this.environment_.getLocalVolumeAvailableSize().then(function(size) { |
Steve McKay
2015/01/26 18:08:43
Please wrap before anonymous functions. NOT wrappi
|
+ this.localVolumeAvilableSize_ = size; |
+ this.updateCommands_(); |
+ }.bind(this)); |
} |
}; |
@@ -98,7 +102,7 @@ importer.ImportController.prototype.onScanEvent_ = function(event, result) { |
*/ |
importer.ImportController.prototype.execute = function() { |
metrics.recordEnum('CloudImport.UserAction', 'IMPORT_INITIATED'); |
- var result = this.getScanForImport_(); |
+ var result = assert(this.getScanForImport_()); |
var importTask = this.importRunner_.importFromScanResult(result); |
importTask.getDestination().then( |
@@ -120,25 +124,15 @@ importer.ImportController.prototype.getCommandUpdate = function() { |
// If there is no Google Drive mount, Drive may be disabled |
// or the machine may be running in guest mode. |
if (this.environment_.isGoogleDriveMounted()) { |
- var entries = this.environment_.getSelection(); |
- |
- // Enabled if user has a selection and it consists entirely of files |
- // that: |
- // 1) are of a recognized media type |
- // 2) reside on a removable media device |
- // 3) in the DCIM directory |
- if (entries.length) { |
- if (entries.every( |
- importer.isEligibleEntry.bind(null, this.environment_))) { |
- return importer.ImportController.createUpdate_( |
- importer.ResponseId.EXECUTABLE, entries.length); |
- } |
- } else if (this.isCurrentDirectoryScannable_()) { |
- var scan = this.getCurrentDirectoryScan_(); |
+ var scan = this.getScanForImport_(); |
+ if (scan) { |
if (scan.isFinal()) { |
if (scan.getFileEntries().length === 0) { |
return importer.ImportController.createUpdate_( |
importer.ResponseId.NO_MEDIA); |
+ } else if (scan.getTotalBytes() > this.localVolumeAvilableSize_) { |
+ return importer.ImportController.createUpdate_( |
+ importer.ResponseId.NO_SPACE); |
} else { |
return importer.ImportController.createUpdate_( |
importer.ResponseId.EXECUTABLE, |
@@ -186,12 +180,19 @@ importer.ImportController.createUpdate_ = |
executable: false, |
label: str('CLOUD_IMPORT_EMPTY_SCAN_BUTTON_LABEL') |
}; |
+ case importer.ResponseId.NO_SPACE: |
+ return { |
+ id: responseId, |
+ visible: true, |
+ executable: false, |
+ label: str('CLOUD_IMPORT_INSUFFICIENT_SPACE_BUTTON_LABEL'), |
+ }; |
case importer.ResponseId.EXECUTABLE: |
return { |
id: responseId, |
- label: strf('CLOUD_IMPORT_BUTTON_LABEL', opt_fileCount), |
visible: true, |
- executable: true |
+ executable: true, |
+ label: strf('CLOUD_IMPORT_BUTTON_LABEL', opt_fileCount), |
}; |
default: |
assertNotReached('Unrecognized response id: ' + responseId); |
@@ -199,75 +200,44 @@ importer.ImportController.createUpdate_ = |
}; |
/** |
- * @return {boolean} true if the current directory is scan eligible. |
- * @private |
- */ |
-importer.ImportController.prototype.isCurrentDirectoryScannable_ = |
- function() { |
- var directory = this.environment_.getCurrentDirectory(); |
- return !!directory && |
- importer.isMediaDirectory(directory, this.environment_); |
-}; |
- |
-/** |
* Get or create scan for the current directory or file selection. |
* |
- * @return {!importer.ScanResult} A scan result object that may be |
- * actively scanning. |
+ * @return {importer.ScanResult} A scan result object that may be |
+ * actively scanning. Can be null. |
* @private |
*/ |
importer.ImportController.prototype.getScanForImport_ = function() { |
Steve McKay
2015/01/26 18:08:43
Move this logic into ScanCache and rename that cla
|
var entries = this.environment_.getSelection(); |
- |
+ var targetEntries = null; |
if (entries.length) { |
if (entries.every( |
importer.isEligibleEntry.bind(null, this.environment_))) { |
- return this.scanner_.scan(entries); |
+ // Enabled if user has a selection and it consists entirely of files |
+ // that: |
+ // 1) are of a recognized media type |
+ // 2) reside on a removable media device |
+ // 3) in the DCIM directory |
+ targetEntries = entries; |
} |
} else { |
- return this.getCurrentDirectoryScan_(); |
- } |
-}; |
- |
-/** |
- * Get or create scan for the current directory. |
- * |
- * @return {!importer.ScanResult} A scan result object that may be |
- * actively scanning. |
- * @private |
- */ |
-importer.ImportController.prototype.getCurrentDirectoryScan_ = function() { |
- console.assert(this.isCurrentDirectoryScannable_()); |
- var directory = this.environment_.getCurrentDirectory(); |
- var volumeId = this.environment_.getVolumeInfo(directory).volumeId; |
- |
- // Lazily initialize the cache for volumeId. |
- if (!this.cachedScans_.hasOwnProperty(volumeId)) { |
- this.cachedScans_[volumeId] = {}; |
+ var directory = this.environment_.getCurrentDirectory(); |
+ if (!!directory && |
+ importer.isMediaDirectory(directory, this.environment_)) { |
+ targetEntries = [directory]; |
+ } |
} |
- |
- var url = directory.toURL(); |
- var scan = this.cachedScans_[volumeId][url]; |
+ if (!targetEntries) |
+ return null; |
+ var scan = this.scanCache_.getForEntries(targetEntries); |
Steve McKay
2015/01/26 18:08:43
We can't throw away directory scans. A recursive s
|
if (!scan) { |
- scan = this.scanner_.scan([directory]); |
- this.cachedScans_[volumeId][url] = scan; |
+ scan = this.scanner_.scan(targetEntries); |
+ this.scanCache_.putForEntries(targetEntries, scan); |
} |
assert(!scan.isInvalidated()); |
return scan; |
}; |
/** |
- * @param {string} volumeId |
- * @private |
- */ |
-importer.ImportController.prototype.onVolumeUnmounted_ = function(volumeId) { |
- // Forget all scans related to the unmounted volume volume. |
- if (this.cachedScans_.hasOwnProperty(volumeId)) { |
- delete this.cachedScans_[volumeId]; |
- } |
-}; |
- |
-/** |
* Interface abstracting away the concrete file manager available |
* to commands. By hiding file manager we make it easy to test |
* ImportController. |
@@ -301,11 +271,9 @@ importer.ControllerEnvironment.prototype.setCurrentDirectory; |
importer.ControllerEnvironment.prototype.isGoogleDriveMounted; |
/** |
- * Installs an 'unmount' listener. Listener is called with |
- * the corresponding volume id when a volume is unmounted. |
- * @param {function(string)} listener |
+ * @return {!Promise<number>} |
*/ |
-importer.ControllerEnvironment.prototype.addVolumeUnmountListener; |
Steve McKay
2015/01/26 18:08:44
We still need to invalidate scans when a volume is
|
+importer.ControllerEnvironment.prototype.getLocalVolumeAvailableSize; |
/** |
* Class providing access to various pieces of information in the |
@@ -356,16 +324,74 @@ importer.RuntimeControllerEnvironment.prototype.isGoogleDriveMounted = |
}; |
/** @override */ |
-importer.RuntimeControllerEnvironment.prototype.addVolumeUnmountListener = |
- function(listener) { |
- chrome.fileManagerPrivate.onMountCompleted.addListener( |
- /** |
- * @param {!MountCompletedEvent} event |
- * @this {importer.RuntimeControllerEnvironment} |
- */ |
- function(event) { |
- if (event.eventType === 'unmount') { |
- listener(event.volumeMetadata.volumeId); |
- } |
- }); |
+importer.RuntimeControllerEnvironment.prototype.getLocalVolumeAvailableSize = |
+ function() { |
+ var localVolumeInfo = |
+ this.fileManager_.volumeManager.getCurrentProfileVolumeInfo( |
+ VolumeManagerCommon.VolumeType.DOWNLOADS); |
+ return new Promise(function(fulfill, reject) { |
+ chrome.fileManagerPrivate.getSizeStats( |
+ localVolumeInfo.volumeId, |
+ function(stats) { |
+ if (stats && !chrome.runtime.lastError) { |
+ fulfill(stats.remainingSize); |
+ } else { |
+ reject('Failed to obtain remaining size.'); |
+ } |
+ }); |
+ }); |
+}; |
+ |
+/** |
+ * Cache for scan. |
+ * @constructor |
+ */ |
+importer.ScanCache = function() { |
+ /** |
+ * Cache key |
+ * @private {string} |
+ */ |
+ this.cacheKey_ = ''; |
+ |
+ /** |
+ * Cached scan. |
+ * @public {importer.ScanResult} |
+ */ |
+ this.currentCache = null; |
+}; |
+ |
+/** |
+ * Creates cache key for the entries. |
+ * @param {!Array<!Entry>} entries |
+ * @return {string} |
+ * @private |
+ */ |
+importer.ScanCache.createKey_ = function(entries) { |
+ return util.entriesToURLs(entries).sort().join('\n'); |
+}; |
+ |
+/** |
+ * Puts scan result for the entries into the cache. |
+ * @param {!Array<!Entry>} entries |
+ * @param {importer.ScanResult} scan |
+ */ |
+importer.ScanCache.prototype.putForEntries = function(entries, scan) { |
+ this.cacheKey_ = importer.ScanCache.createKey_(entries); |
+ this.currentCache = scan; |
+}; |
+ |
+/** |
+ * Gets cached scan result for the entries. |
+ */ |
+importer.ScanCache.prototype.getForEntries = function(entries) { |
+ var key = importer.ScanCache.createKey_(entries); |
+ return this.cacheKey_ === key ? this.currentCache : null; |
+}; |
+ |
+/** |
+ * Clears the cached scan result. |
+ */ |
+importer.ScanCache.prototype.clear = function() { |
+ this.cacheKey_ = ''; |
+ this.currentCache = null; |
}; |