Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(407)

Unified Diff: chrome/browser/resources/print_preview/data/destination_store.js

Issue 10450022: Print Preview Print Destination Search Widget (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Set --bary flag Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/print_preview/data/destination_store.js
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index 69f766ad9c88fde6636ea1d7cb1b367fc266c3bb..6c8d52db851509039e935d30397f763f6f8b256c 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -8,20 +8,36 @@ cr.define('print_preview', function() {
/**
* A data store that stores destinations and dispatches events when the data
* store changes.
+ * @param {!print_preview.NativeLayer} nativeLayer Used to fetch local print
+ * destinations.
* @constructor
* @extends {cr.EventTarget}
*/
- function DestinationStore() {
+ function DestinationStore(nativeLayer) {
cr.EventTarget.call(this);
/**
+ * Used to fetch local print destinations.
+ * @type {!print_preview.NativeLayer}
+ * @private
+ */
+ this.nativeLayer_ = nativeLayer;
+
+ /**
* Internal backing store for the data store.
- * @type {!Array.<print_preview.Destination>}
+ * @type {!Array.<!print_preview.Destination>}
* @private
*/
this.destinations_ = [];
/**
+ * Cache used for constant lookup of printers.
+ * @type {object.<string, !print_preview.Destination>}
+ * @private
+ */
+ this.destinationMap_ = {};
+
+ /**
* Currently selected destination.
* @type {print_preview.Destination}
* @private
@@ -44,6 +60,41 @@ cr.define('print_preview', function() {
* @private
*/
this.isInAutoSelectMode_ = false;
+
+ /**
+ * Event tracker used to track event listeners of the destination store.
+ * @type {!EventTracker}
+ * @private
+ */
+ this.tracker_ = new EventTracker();
+
+ /**
+ * Used to fetch cloud-based print destinations.
+ * @type {print_preview.CloudPrintInterface}
+ * @private
+ */
+ this.cloudPrintInterface_ = null;
+
+ /**
+ * Whether the destination store has already loaded or is loading all cloud
+ * destinations.
+ * @type {boolean}
+ * @private
+ */
+ this.hasLoadedAllCloudDestinations_ = false;
+
+ /**
+ * ID of a timeout after the initial destination ID is set. If no inserted
+ * destination matches the initial destination ID after the specified
+ * timeout, the first destination in the store will be automatically
+ * selected.
+ * @type {?number}
+ * @private
+ */
+ this.autoSelectTimeout_ = null;
+
+ this.addEventListeners_();
+ this.reset_();
};
/**
@@ -53,7 +104,44 @@ cr.define('print_preview', function() {
DestinationStore.EventType = {
DESTINATIONS_INSERTED:
'print_preview.DestinationStore.DESTINATIONS_INSERTED',
- DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT'
+ DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT',
+ SELECTED_DESTINATION_CAPABILITIES_READY:
+ 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY'
+ };
+
+ /**
+ * Delay in milliseconds before the destination store ignores the initial
+ * destination ID and just selects any printer (since the initial destination
+ * was not found).
+ * @type {number}
+ * @const
+ * @private
+ */
+ DestinationStore.AUTO_SELECT_TIMEOUT_ = 2000;
+
+ /**
+ * Creates a local PDF print destination.
+ * @return {!print_preview.Destination} Created print destination.
+ * @private
+ */
+ DestinationStore.createLocalPdfPrintDestination_ = function() {
+ var dest = new print_preview.Destination(
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
+ print_preview.Destination.Type.LOCAL,
+ localStrings.getString('printToPDF'),
+ false /*isRecent*/);
+ dest.capabilities = new print_preview.ChromiumCapabilities(
+ false /*hasCopiesCapability*/,
+ '1' /*defaultCopiesStr*/,
+ false /*hasCollateCapability*/,
+ false /*defaultIsCollateEnabled*/,
+ false /*hasDuplexCapability*/,
+ false /*defaultIsDuplexEnabled*/,
+ true /*hasOrientationCapability*/,
+ false /*defaultIsLandscapeEnabled*/,
+ true /*hasColorCapability*/,
+ true /*defaultIsColorEnabled*/);
+ return dest;
};
DestinationStore.prototype = {
@@ -80,31 +168,68 @@ cr.define('print_preview', function() {
* match this ID, that destination will be automatically selected. This
* occurs only once for every time this setter is called or if the store is
* cleared.
- * @param {string} ID of the destination that should be selected
- * automatically when added to the store.
+ * @param {?string} ID of the destination that should be selected
+ * automatically when added to the store or {@code null} if the first
+ * destination that is inserted should be selected.
*/
setInitialDestinationId: function(initialDestinationId) {
this.initialDestinationId_ = initialDestinationId;
this.isInAutoSelectMode_ = true;
- if (this.initialDestinationId_ == null && this.destinations_.length > 0) {
+ if (this.initialDestinationId_ == null) {
+ assert(this.destinations_.length > 0,
+ 'No destinations available to select');
this.selectDestination(this.destinations_[0]);
- } else if (this.initialDestinationId_ != null) {
- for (var dest, i = 0; dest = this.destinations_[i]; i++) {
- if (dest.id == initialDestinationId) {
- this.selectDestination(dest);
- break;
- }
+ } else {
+ var candidate = this.destinationMap_[this.initialDestinationId_];
+ if (candidate != null) {
+ this.selectDestination(candidate);
}
}
},
+ /**
+ * Sets the destination store's Google Cloud Print interface.
+ * @param {!print_preview.CloudPrintInterface} cloudPrintInterface Interface
+ * to set.
+ */
+ setCloudPrintInterface: function(cloudPrintInterface) {
+ this.cloudPrintInterface_ = cloudPrintInterface;
+ this.tracker_.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.SEARCH_DONE,
+ this.onCloudPrintSearchDone_.bind(this));
+ this.tracker_.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.PRINTER_DONE,
+ this.onCloudPrintPrinterDone_.bind(this));
+ },
+
/** @param {!print_preview.Destination} Destination to select. */
selectDestination: function(destination) {
this.selectedDestination_ = destination;
this.selectedDestination_.isRecent = true;
this.isInAutoSelectMode_ = false;
+ if (this.autoSelectTimeout_ != null) {
+ clearTimeout(this.autoSelectTimeout_);
+ this.autoSelectTimeout_ = null;
+ }
cr.dispatchSimpleEvent(
this, DestinationStore.EventType.DESTINATION_SELECT);
+ if (destination.capabilities == null) {
+ if (destination.isLocal) {
+ this.nativeLayer_.startGetLocalDestinationCapabilities(
+ destination.id);
+ } else {
+ assert(this.cloudPrintInterface_ != null,
+ 'Selected destination is a cloud destination, but Google ' +
+ 'Cloud Print is not enabled');
+ this.cloudPrintInterface_.printer(destination.id);
+ }
+ } else {
+ cr.dispatchSimpleEvent(
+ this,
+ DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
+ }
},
/**
@@ -115,16 +240,13 @@ cr.define('print_preview', function() {
* insert.
*/
insertDestination: function(destination) {
- this.destinations_.push(destination);
- cr.dispatchSimpleEvent(
- this, DestinationStore.EventType.DESTINATIONS_INSERTED);
- if (this.isInAutoSelectMode_) {
- if (this.initialDestinationId_ == null) {
+ if (this.insertDestination_(destination)) {
+ cr.dispatchSimpleEvent(
+ this, DestinationStore.EventType.DESTINATIONS_INSERTED);
+ if (this.isInAutoSelectMode_ &&
+ (this.initialDestinationId_ == null ||
+ destination.id == this.initialDestinationId_)) {
this.selectDestination(destination);
- } else {
- if (destination.id == this.initialDestinationId_) {
- this.selectDestination(destination);
- }
}
}
},
@@ -137,20 +259,25 @@ cr.define('print_preview', function() {
* destinations to insert.
*/
insertDestinations: function(destinations) {
- this.destinations_ = this.destinations_.concat(destinations);
- cr.dispatchSimpleEvent(
- this, DestinationStore.EventType.DESTINATIONS_INSERTED);
- if (this.isInAutoSelectMode_) {
- if (this.initialDestinationId_ == null && destinations.length > 0) {
- this.selectDestination(destinations[0]);
- } else if (this.initialDestinationId_ != null) {
- for (var dest, i = 0; dest = destinations[i]; i++) {
- if (dest.id == this.initialDestinationId_) {
- this.selectDestination(dest);
- break;
- }
+ var insertedDestination = false;
+ var destinationToAutoSelect = null;
+ destinations.forEach(function(dest) {
+ if (this.insertDestination_(dest)) {
+ insertedDestination = true;
+ if (this.isInAutoSelectMode_ &&
+ destinationToAutoSelect == null &&
+ (this.initialDestinationId_ == null ||
+ dest.id == this.initialDestinationId_)) {
+ destinationToAutoSelect = dest;
}
}
+ }, this);
+ if (insertedDestination) {
+ cr.dispatchSimpleEvent(
+ this, DestinationStore.EventType.DESTINATIONS_INSERTED);
+ }
+ if (destinationToAutoSelect != null) {
+ this.selectDestination(destinationToAutoSelect);
}
},
@@ -162,14 +289,8 @@ cr.define('print_preview', function() {
* updated.
*/
updateDestination: function(destination) {
- var existingDestination = null;
- for (var d, i = 0; d = this.destinations_[i]; i++) {
- if (destination.id == d.id) {
- existingDestination = d;
- break;
- }
- }
- if (existingDestination) {
+ var existingDestination = this.destinationMap_[destination.id];
+ if (existingDestination != null) {
existingDestination.capabilities = destination.capabilities;
return existingDestination;
} else {
@@ -177,11 +298,163 @@ cr.define('print_preview', function() {
}
},
- /** Clears all print destinations. */
- clear: function() {
+ /** Initiates loading of local print destinations. */
+ startLoadLocalDestinations: function() {
+ this.nativeLayer_.startGetLocalDestinations();
+ },
+
+ /** Initiates loading of recent cloud destinations. */
+ startLoadRecentCloudDestinations: function() {
+ if (this.cloudPrintInterface_ != null) {
+ this.cloudPrintInterface_.search(true /*isRecent*/);
+ }
+ },
+
+ /** Initiates loading of all cloud destinations. */
+ startLoadAllCloudDestinations: function() {
+ if (this.cloudPrintInterface_ != null &&
+ !this.hasLoadedAllCloudDestinations_) {
+ this.cloudPrintInterface_.search(false /*isRecent*/);
+ this.hasLoadedAllCloudDestinations_ = true;
+ }
+ },
+
+ /**
+ * Inserts a destination into the store without dispatching any events.
+ * @return {boolean} Whether the inserted destination was not already in the
+ * store.
+ * @private
+ */
+ insertDestination_: function(destination) {
+ if (this.destinationMap_[destination.id] == null) {
+ this.destinations_.push(destination);
+ this.destinationMap_[destination.id] = destination;
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Binds handlers to events.
+ * @private
+ */
+ addEventListeners_: function() {
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.LOCAL_DESTINATIONS_SET,
+ this.onLocalDestinationsSet_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.CAPABILITIES_SET,
+ this.onLocalDestinationCapabilitiesSet_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.DESTINATIONS_RELOAD,
+ this.onDestinationsReload_.bind(this));
+ },
+
+ /**
+ * Resets the state of the destination store to its initial state.
+ * @private
+ */
+ reset_: function() {
this.destinations_ = [];
+ this.destinationMap_ = {};
this.selectedDestination_ = null;
+ this.hasLoadedAllCloudDestinations_ = false;
+ this.insertDestination(
+ DestinationStore.createLocalPdfPrintDestination_());
+ this.autoSelectTimeout_ = setTimeout(
+ this.onAutoSelectTimeoutExpired_.bind(this),
+ DestinationStore.AUTO_SELECT_TIMEOUT_);
+ },
+
+ /**
+ * Called when the local destinations have been got from the native layer.
+ * @param {cr.Event} Contains the local destinations.
+ * @private
+ */
+ onLocalDestinationsSet_: function(event) {
+ var localDestinations = event.destinationInfos.map(function(destInfo) {
+ return print_preview.LocalDestinationParser.parse(destInfo);
+ });
+ this.insertDestinations(localDestinations);
+ },
+
+ /**
+ * Called when the native layer retrieves the capabilities for the selected
+ * local destination.
+ * @param {cr.Event} event Contains the capabilities of the local print
+ * destination.
+ * @private
+ */
+ onLocalDestinationCapabilitiesSet_: function(event) {
+ // TODO(rltoscano): There may be a race condition here. This method is
+ // assumed to return capabilities for the currently selected printer. But
+ // between the time the local printer was selected and the capabilities
+ // were retrieved, the selected printer can change. One way to address
+ // this is to include the destination ID in the event.settingsInfo
+ // parameter.
+ if (this.selectedDestination_ && this.selectedDestination_.isLocal) {
+ var capabilities = print_preview.LocalCapabilitiesParser.parse(
+ event.settingsInfo);
+ this.selectedDestination_.capabilities = capabilities;
+ cr.dispatchSimpleEvent(
+ this,
+ DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
+ }
+ },
+
+ /**
+ * Called when the /search call completes. Adds the fetched printers to the
+ * destination store.
+ * @param {cr.Event} event Contains the fetched printers.
+ * @private
+ */
+ onCloudPrintSearchDone_: function(event) {
+ this.insertDestinations(event.printers);
+ },
+
+ /**
+ * Called when /printer call completes. Updates the specified destination's
+ * print capabilities.
+ * @param {cr.Event} event Contains detailed information about the
+ * destination.
+ * @private
+ */
+ onCloudPrintPrinterDone_: function(event) {
+ var dest = this.updateDestination(event.printer);
+ if (this.selectedDestination_ == dest) {
+ cr.dispatchSimpleEvent(
+ this,
+ DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
+ }
+ },
+
+ /**
+ * Called from native layer after the user was requested to sign in, and did
+ * so successfully.
+ * @private
+ */
+ onDestinationsReload_: function() {
+ this.reset_();
this.isInAutoSelectMode_ = true;
+ this.startLoadLocalDestinations();
+ this.startLoadRecentCloudDestinations();
+ this.startLoadAllCloudDestinations();
+ },
+
+ /**
+ * Called when no destination was auto-selected after some timeout. Selects
+ * the first destination in store.
+ * @private
+ */
+ onAutoSelectTimeoutExpired_: function() {
+ this.autoSelectTimeout_ = null;
+ assert(this.destinations_.length > 0,
+ 'No destinations were loaded before auto-select timeout expired');
+ this.selectDestination(this.destinations_[0]);
}
};

Powered by Google App Engine
This is Rietveld 408576698