blob: 2fdd88118b41169c327934e5041cac593bfd1aef [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Handler for scan related events of DirectoryModel.
*
* @param {!DirectoryModel} directoryModel
* @param {!ListContainer} listContainer
* @param {!SpinnerController} spinnerController
* @param {!CommandHandler} commandHandler
* @param {!FileSelectionHandler} selectionHandler
* @constructor
* @struct
*/
function ScanController(
directoryModel,
listContainer,
spinnerController,
commandHandler,
selectionHandler) {
/**
* @type {!DirectoryModel}
* @const
* @private
*/
this.directoryModel_ = directoryModel;
/**
* @type {!ListContainer}
* @const
* @private
*/
this.listContainer_ = listContainer;
/**
* @type {!SpinnerController}
* @const
* @private
*/
this.spinnerController_ = spinnerController;
/**
* @type {!CommandHandler}
* @const
* @private
*/
this.commandHandler_ = commandHandler;
/**
* @type {!FileSelectionHandler}
* @const
* @private
*/
this.selectionHandler_ = selectionHandler;
/**
* Whether a scan is in progress.
* @type {boolean}
* @private
*/
this.scanInProgress_ = false;
/**
* Whether a scan is updated at least once. If true, spinner should disappear.
* @type {boolean}
* @private
*/
this.scanUpdatedAtLeastOnceOrCompleted_ = false;
/**
* Timer ID to delay UI refresh after a scan is completed.
* @type {number}
* @private
*/
this.scanCompletedTimer_ = 0;
/**
* Timer ID to delay UI refresh after a scan is updated.
* @type {number}
* @private
*/
this.scanUpdatedTimer_ = 0;
this.directoryModel_.addEventListener(
'scan-started', this.onScanStarted_.bind(this));
this.directoryModel_.addEventListener(
'scan-completed', this.onScanCompleted_.bind(this));
this.directoryModel_.addEventListener(
'scan-failed', this.onScanCancelled_.bind(this));
this.directoryModel_.addEventListener(
'scan-cancelled', this.onScanCancelled_.bind(this));
this.directoryModel_.addEventListener(
'scan-updated', this.onScanUpdated_.bind(this));
this.directoryModel_.addEventListener(
'rescan-completed', this.onRescanCompleted_.bind(this));
}
/**
* @private
*/
ScanController.prototype.onScanStarted_ = function() {
if (this.scanInProgress_)
this.listContainer_.endBatchUpdates();
if (this.commandHandler_)
this.commandHandler_.updateAvailability();
this.listContainer_.startBatchUpdates();
this.scanInProgress_ = true;
this.scanUpdatedAtLeastOnceOrCompleted_ = false;
if (this.scanCompletedTimer_) {
clearTimeout(this.scanCompletedTimer_);
this.scanCompletedTimer_ = 0;
}
if (this.scanUpdatedTimer_) {
clearTimeout(this.scanUpdatedTimer_);
this.scanUpdatedTimer_ = 0;
}
this.spinnerController_.showLater();
};
/**
* @private
*/
ScanController.prototype.onScanCompleted_ = function() {
if (!this.scanInProgress_) {
console.error('Scan-completed event recieved. But scan is not started.');
return;
}
if (this.commandHandler_)
this.commandHandler_.updateAvailability();
this.spinnerController_.hide();
if (this.scanUpdatedTimer_) {
clearTimeout(this.scanUpdatedTimer_);
this.scanUpdatedTimer_ = 0;
}
// To avoid flickering postpone updating the ui by a small amount of time.
// There is a high chance, that metadata will be received within 50 ms.
this.scanCompletedTimer_ = setTimeout(function() {
// Check if batch updates are already finished by onScanUpdated_().
if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
this.scanUpdatedAtLeastOnceOrCompleted_ = true;
}
this.scanInProgress_ = false;
this.listContainer_.endBatchUpdates();
this.scanCompletedTimer_ = 0;
}.bind(this), 50);
};
/**
* @private
*/
ScanController.prototype.onScanUpdated_ = function() {
if (!this.scanInProgress_) {
console.error('Scan-updated event recieved. But scan is not started.');
return;
}
if (this.scanUpdatedTimer_ || this.scanCompletedTimer_)
return;
// Show contents incrementally by finishing batch updated, but only after
// 200ms elapsed, to avoid flickering when it is not necessary.
this.scanUpdatedTimer_ = setTimeout(function() {
// We need to hide the spinner only once.
if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
this.scanUpdatedAtLeastOnceOrCompleted_ = true;
this.spinnerController_.hide();
}
// Update the UI.
if (this.scanInProgress_) {
this.listContainer_.endBatchUpdates();
this.listContainer_.startBatchUpdates();
}
this.scanUpdatedTimer_ = 0;
}.bind(this), 200);
};
/**
* @private
*/
ScanController.prototype.onScanCancelled_ = function() {
if (!this.scanInProgress_) {
console.error('Scan-cancelled event recieved. But scan is not started.');
return;
}
if (this.commandHandler_)
this.commandHandler_.updateAvailability();
this.spinnerController_.hide();
if (this.scanCompletedTimer_) {
clearTimeout(this.scanCompletedTimer_);
this.scanCompletedTimer_ = 0;
}
if (this.scanUpdatedTimer_) {
clearTimeout(this.scanUpdatedTimer_);
this.scanUpdatedTimer_ = 0;
}
// Finish unfinished batch updates.
if (!this.scanUpdatedAtLeastOnceOrCompleted_) {
this.scanUpdatedAtLeastOnceOrCompleted_ = true;
}
this.scanInProgress_ = false;
this.listContainer_.endBatchUpdates();
};
/**
* Handle the 'rescan-completed' from the DirectoryModel.
* @private
*/
ScanController.prototype.onRescanCompleted_ = function() {
this.selectionHandler_.onFileSelectionChanged();
};