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

Side by Side 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, 6 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 cr.define('print_preview', function() { 5 cr.define('print_preview', function() {
6 'use strict'; 6 'use strict';
7 7
8 /** 8 /**
9 * A data store that stores destinations and dispatches events when the data 9 * A data store that stores destinations and dispatches events when the data
10 * store changes. 10 * store changes.
11 * @param {!print_preview.NativeLayer} nativeLayer Used to fetch local print
12 * destinations.
11 * @constructor 13 * @constructor
12 * @extends {cr.EventTarget} 14 * @extends {cr.EventTarget}
13 */ 15 */
14 function DestinationStore() { 16 function DestinationStore(nativeLayer) {
15 cr.EventTarget.call(this); 17 cr.EventTarget.call(this);
16 18
17 /** 19 /**
20 * Used to fetch local print destinations.
21 * @type {!print_preview.NativeLayer}
22 * @private
23 */
24 this.nativeLayer_ = nativeLayer;
25
26 /**
18 * Internal backing store for the data store. 27 * Internal backing store for the data store.
19 * @type {!Array.<print_preview.Destination>} 28 * @type {!Array.<!print_preview.Destination>}
20 * @private 29 * @private
21 */ 30 */
22 this.destinations_ = []; 31 this.destinations_ = [];
23 32
24 /** 33 /**
34 * Cache used for constant lookup of printers.
35 * @type {object.<string, !print_preview.Destination>}
36 * @private
37 */
38 this.destinationMap_ = {};
39
40 /**
25 * Currently selected destination. 41 * Currently selected destination.
26 * @type {print_preview.Destination} 42 * @type {print_preview.Destination}
27 * @private 43 * @private
28 */ 44 */
29 this.selectedDestination_ = null; 45 this.selectedDestination_ = null;
30 46
31 /** 47 /**
32 * Initial destination ID used to auto-select the first inserted destination 48 * Initial destination ID used to auto-select the first inserted destination
33 * that matches. If {@code null}, the first destination inserted into the 49 * that matches. If {@code null}, the first destination inserted into the
34 * store will be selected. 50 * store will be selected.
35 * @type {?string} 51 * @type {?string}
36 * @private 52 * @private
37 */ 53 */
38 this.initialDestinationId_ = null; 54 this.initialDestinationId_ = null;
39 55
40 /** 56 /**
41 * Whether the destination store will auto select the destination that 57 * Whether the destination store will auto select the destination that
42 * matches the initial destination. 58 * matches the initial destination.
43 * @type {boolean} 59 * @type {boolean}
44 * @private 60 * @private
45 */ 61 */
46 this.isInAutoSelectMode_ = false; 62 this.isInAutoSelectMode_ = false;
63
64 /**
65 * Event tracker used to track event listeners of the destination store.
66 * @type {!EventTracker}
67 * @private
68 */
69 this.tracker_ = new EventTracker();
70
71 /**
72 * Used to fetch cloud-based print destinations.
73 * @type {print_preview.CloudPrintInterface}
74 * @private
75 */
76 this.cloudPrintInterface_ = null;
77
78 /**
79 * Whether the destination store has already loaded or is loading all cloud
80 * destinations.
81 * @type {boolean}
82 * @private
83 */
84 this.hasLoadedAllCloudDestinations_ = false;
85
86 /**
87 * ID of a timeout after the initial destination ID is set. If no inserted
88 * destination matches the initial destination ID after the specified
89 * timeout, the first destination in the store will be automatically
90 * selected.
91 * @type {?number}
92 * @private
93 */
94 this.autoSelectTimeout_ = null;
95
96 this.addEventListeners_();
97 this.reset_();
47 }; 98 };
48 99
49 /** 100 /**
50 * Event types dispatched by the data store. 101 * Event types dispatched by the data store.
51 * @enum {string} 102 * @enum {string}
52 */ 103 */
53 DestinationStore.EventType = { 104 DestinationStore.EventType = {
54 DESTINATIONS_INSERTED: 105 DESTINATIONS_INSERTED:
55 'print_preview.DestinationStore.DESTINATIONS_INSERTED', 106 'print_preview.DestinationStore.DESTINATIONS_INSERTED',
56 DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT' 107 DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT',
108 SELECTED_DESTINATION_CAPABILITIES_READY:
109 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY'
110 };
111
112 /**
113 * Delay in milliseconds before the destination store ignores the initial
114 * destination ID and just selects any printer (since the initial destination
115 * was not found).
116 * @type {number}
117 * @const
118 * @private
119 */
120 DestinationStore.AUTO_SELECT_TIMEOUT_ = 2000;
121
122 /**
123 * Creates a local PDF print destination.
124 * @return {!print_preview.Destination} Created print destination.
125 * @private
126 */
127 DestinationStore.createLocalPdfPrintDestination_ = function() {
128 var dest = new print_preview.Destination(
129 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
130 print_preview.Destination.Type.LOCAL,
131 localStrings.getString('printToPDF'),
132 false /*isRecent*/);
133 dest.capabilities = new print_preview.ChromiumCapabilities(
134 false /*hasCopiesCapability*/,
135 '1' /*defaultCopiesStr*/,
136 false /*hasCollateCapability*/,
137 false /*defaultIsCollateEnabled*/,
138 false /*hasDuplexCapability*/,
139 false /*defaultIsDuplexEnabled*/,
140 true /*hasOrientationCapability*/,
141 false /*defaultIsLandscapeEnabled*/,
142 true /*hasColorCapability*/,
143 true /*defaultIsColorEnabled*/);
144 return dest;
57 }; 145 };
58 146
59 DestinationStore.prototype = { 147 DestinationStore.prototype = {
60 __proto__: cr.EventTarget.prototype, 148 __proto__: cr.EventTarget.prototype,
61 149
62 /** 150 /**
63 * @return {!Array.<!print_preview.Destination>} List of destinations in 151 * @return {!Array.<!print_preview.Destination>} List of destinations in
64 * the store. 152 * the store.
65 */ 153 */
66 get destinations() { 154 get destinations() {
67 return this.destinations_.slice(0); 155 return this.destinations_.slice(0);
68 }, 156 },
69 157
70 /** 158 /**
71 * @return {print_preview.Destination} The currently selected destination or 159 * @return {print_preview.Destination} The currently selected destination or
72 * {@code null} if none is selected. 160 * {@code null} if none is selected.
73 */ 161 */
74 get selectedDestination() { 162 get selectedDestination() {
75 return this.selectedDestination_; 163 return this.selectedDestination_;
76 }, 164 },
77 165
78 /** 166 /**
79 * Sets the initially selected destination. If any inserted destinations 167 * Sets the initially selected destination. If any inserted destinations
80 * match this ID, that destination will be automatically selected. This 168 * match this ID, that destination will be automatically selected. This
81 * occurs only once for every time this setter is called or if the store is 169 * occurs only once for every time this setter is called or if the store is
82 * cleared. 170 * cleared.
83 * @param {string} ID of the destination that should be selected 171 * @param {?string} ID of the destination that should be selected
84 * automatically when added to the store. 172 * automatically when added to the store or {@code null} if the first
173 * destination that is inserted should be selected.
85 */ 174 */
86 setInitialDestinationId: function(initialDestinationId) { 175 setInitialDestinationId: function(initialDestinationId) {
87 this.initialDestinationId_ = initialDestinationId; 176 this.initialDestinationId_ = initialDestinationId;
88 this.isInAutoSelectMode_ = true; 177 this.isInAutoSelectMode_ = true;
89 if (this.initialDestinationId_ == null && this.destinations_.length > 0) { 178 if (this.initialDestinationId_ == null) {
179 assert(this.destinations_.length > 0,
180 'No destinations available to select');
90 this.selectDestination(this.destinations_[0]); 181 this.selectDestination(this.destinations_[0]);
91 } else if (this.initialDestinationId_ != null) { 182 } else {
92 for (var dest, i = 0; dest = this.destinations_[i]; i++) { 183 var candidate = this.destinationMap_[this.initialDestinationId_];
93 if (dest.id == initialDestinationId) { 184 if (candidate != null) {
94 this.selectDestination(dest); 185 this.selectDestination(candidate);
95 break;
96 }
97 } 186 }
98 } 187 }
99 }, 188 },
100 189
190 /**
191 * Sets the destination store's Google Cloud Print interface.
192 * @param {!print_preview.CloudPrintInterface} cloudPrintInterface Interface
193 * to set.
194 */
195 setCloudPrintInterface: function(cloudPrintInterface) {
196 this.cloudPrintInterface_ = cloudPrintInterface;
197 this.tracker_.add(
198 this.cloudPrintInterface_,
199 cloudprint.CloudPrintInterface.EventType.SEARCH_DONE,
200 this.onCloudPrintSearchDone_.bind(this));
201 this.tracker_.add(
202 this.cloudPrintInterface_,
203 cloudprint.CloudPrintInterface.EventType.PRINTER_DONE,
204 this.onCloudPrintPrinterDone_.bind(this));
205 },
206
101 /** @param {!print_preview.Destination} Destination to select. */ 207 /** @param {!print_preview.Destination} Destination to select. */
102 selectDestination: function(destination) { 208 selectDestination: function(destination) {
103 this.selectedDestination_ = destination; 209 this.selectedDestination_ = destination;
104 this.selectedDestination_.isRecent = true; 210 this.selectedDestination_.isRecent = true;
105 this.isInAutoSelectMode_ = false; 211 this.isInAutoSelectMode_ = false;
212 if (this.autoSelectTimeout_ != null) {
213 clearTimeout(this.autoSelectTimeout_);
214 this.autoSelectTimeout_ = null;
215 }
106 cr.dispatchSimpleEvent( 216 cr.dispatchSimpleEvent(
107 this, DestinationStore.EventType.DESTINATION_SELECT); 217 this, DestinationStore.EventType.DESTINATION_SELECT);
218 if (destination.capabilities == null) {
219 if (destination.isLocal) {
220 this.nativeLayer_.startGetLocalDestinationCapabilities(
221 destination.id);
222 } else {
223 assert(this.cloudPrintInterface_ != null,
224 'Selected destination is a cloud destination, but Google ' +
225 'Cloud Print is not enabled');
226 this.cloudPrintInterface_.printer(destination.id);
227 }
228 } else {
229 cr.dispatchSimpleEvent(
230 this,
231 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
232 }
108 }, 233 },
109 234
110 /** 235 /**
111 * Inserts a print destination to the data store and dispatches a 236 * Inserts a print destination to the data store and dispatches a
112 * DESTINATIONS_INSERTED event. If the destination matches the initial 237 * DESTINATIONS_INSERTED event. If the destination matches the initial
113 * destination ID, then the destination will be automatically selected. 238 * destination ID, then the destination will be automatically selected.
114 * @param {!print_preview.Destination} destination Print destination to 239 * @param {!print_preview.Destination} destination Print destination to
115 * insert. 240 * insert.
116 */ 241 */
117 insertDestination: function(destination) { 242 insertDestination: function(destination) {
118 this.destinations_.push(destination); 243 if (this.insertDestination_(destination)) {
119 cr.dispatchSimpleEvent( 244 cr.dispatchSimpleEvent(
120 this, DestinationStore.EventType.DESTINATIONS_INSERTED); 245 this, DestinationStore.EventType.DESTINATIONS_INSERTED);
121 if (this.isInAutoSelectMode_) { 246 if (this.isInAutoSelectMode_ &&
122 if (this.initialDestinationId_ == null) { 247 (this.initialDestinationId_ == null ||
248 destination.id == this.initialDestinationId_)) {
123 this.selectDestination(destination); 249 this.selectDestination(destination);
124 } else {
125 if (destination.id == this.initialDestinationId_) {
126 this.selectDestination(destination);
127 }
128 } 250 }
129 } 251 }
130 }, 252 },
131 253
132 /** 254 /**
133 * Inserts multiple print destinations to the data store and dispatches one 255 * Inserts multiple print destinations to the data store and dispatches one
134 * DESTINATIONS_INSERTED event. If any of the destinations match the initial 256 * DESTINATIONS_INSERTED event. If any of the destinations match the initial
135 * destination ID, then that destination will be automatically selected. 257 * destination ID, then that destination will be automatically selected.
136 * @param {!Array.<print_preview.Destination>} destinations Print 258 * @param {!Array.<print_preview.Destination>} destinations Print
137 * destinations to insert. 259 * destinations to insert.
138 */ 260 */
139 insertDestinations: function(destinations) { 261 insertDestinations: function(destinations) {
140 this.destinations_ = this.destinations_.concat(destinations); 262 var insertedDestination = false;
141 cr.dispatchSimpleEvent( 263 var destinationToAutoSelect = null;
142 this, DestinationStore.EventType.DESTINATIONS_INSERTED); 264 destinations.forEach(function(dest) {
143 if (this.isInAutoSelectMode_) { 265 if (this.insertDestination_(dest)) {
144 if (this.initialDestinationId_ == null && destinations.length > 0) { 266 insertedDestination = true;
145 this.selectDestination(destinations[0]); 267 if (this.isInAutoSelectMode_ &&
146 } else if (this.initialDestinationId_ != null) { 268 destinationToAutoSelect == null &&
147 for (var dest, i = 0; dest = destinations[i]; i++) { 269 (this.initialDestinationId_ == null ||
148 if (dest.id == this.initialDestinationId_) { 270 dest.id == this.initialDestinationId_)) {
149 this.selectDestination(dest); 271 destinationToAutoSelect = dest;
150 break;
151 }
152 } 272 }
153 } 273 }
274 }, this);
275 if (insertedDestination) {
276 cr.dispatchSimpleEvent(
277 this, DestinationStore.EventType.DESTINATIONS_INSERTED);
278 }
279 if (destinationToAutoSelect != null) {
280 this.selectDestination(destinationToAutoSelect);
154 } 281 }
155 }, 282 },
156 283
157 /** 284 /**
158 * Updates an existing print destination with capabilities information. If 285 * Updates an existing print destination with capabilities information. If
159 * the destination doesn't already exist, it will be added. 286 * the destination doesn't already exist, it will be added.
160 * @param {!print_preview.Destination} destination Destination to update. 287 * @param {!print_preview.Destination} destination Destination to update.
161 * @return {!print_preview.Destination} The existing destination that was 288 * @return {!print_preview.Destination} The existing destination that was
162 * updated. 289 * updated.
163 */ 290 */
164 updateDestination: function(destination) { 291 updateDestination: function(destination) {
165 var existingDestination = null; 292 var existingDestination = this.destinationMap_[destination.id];
166 for (var d, i = 0; d = this.destinations_[i]; i++) { 293 if (existingDestination != null) {
167 if (destination.id == d.id) {
168 existingDestination = d;
169 break;
170 }
171 }
172 if (existingDestination) {
173 existingDestination.capabilities = destination.capabilities; 294 existingDestination.capabilities = destination.capabilities;
174 return existingDestination; 295 return existingDestination;
175 } else { 296 } else {
176 this.insertDestination(destination); 297 this.insertDestination(destination);
177 } 298 }
178 }, 299 },
179 300
180 /** Clears all print destinations. */ 301 /** Initiates loading of local print destinations. */
181 clear: function() { 302 startLoadLocalDestinations: function() {
303 this.nativeLayer_.startGetLocalDestinations();
304 },
305
306 /** Initiates loading of recent cloud destinations. */
307 startLoadRecentCloudDestinations: function() {
308 if (this.cloudPrintInterface_ != null) {
309 this.cloudPrintInterface_.search(true /*isRecent*/);
310 }
311 },
312
313 /** Initiates loading of all cloud destinations. */
314 startLoadAllCloudDestinations: function() {
315 if (this.cloudPrintInterface_ != null &&
316 !this.hasLoadedAllCloudDestinations_) {
317 this.cloudPrintInterface_.search(false /*isRecent*/);
318 this.hasLoadedAllCloudDestinations_ = true;
319 }
320 },
321
322 /**
323 * Inserts a destination into the store without dispatching any events.
324 * @return {boolean} Whether the inserted destination was not already in the
325 * store.
326 * @private
327 */
328 insertDestination_: function(destination) {
329 if (this.destinationMap_[destination.id] == null) {
330 this.destinations_.push(destination);
331 this.destinationMap_[destination.id] = destination;
332 return true;
333 } else {
334 return false;
335 }
336 },
337
338 /**
339 * Binds handlers to events.
340 * @private
341 */
342 addEventListeners_: function() {
343 this.tracker_.add(
344 this.nativeLayer_,
345 print_preview.NativeLayer.EventType.LOCAL_DESTINATIONS_SET,
346 this.onLocalDestinationsSet_.bind(this));
347 this.tracker_.add(
348 this.nativeLayer_,
349 print_preview.NativeLayer.EventType.CAPABILITIES_SET,
350 this.onLocalDestinationCapabilitiesSet_.bind(this));
351 this.tracker_.add(
352 this.nativeLayer_,
353 print_preview.NativeLayer.EventType.DESTINATIONS_RELOAD,
354 this.onDestinationsReload_.bind(this));
355 },
356
357 /**
358 * Resets the state of the destination store to its initial state.
359 * @private
360 */
361 reset_: function() {
182 this.destinations_ = []; 362 this.destinations_ = [];
363 this.destinationMap_ = {};
183 this.selectedDestination_ = null; 364 this.selectedDestination_ = null;
365 this.hasLoadedAllCloudDestinations_ = false;
366 this.insertDestination(
367 DestinationStore.createLocalPdfPrintDestination_());
368 this.autoSelectTimeout_ = setTimeout(
369 this.onAutoSelectTimeoutExpired_.bind(this),
370 DestinationStore.AUTO_SELECT_TIMEOUT_);
371 },
372
373 /**
374 * Called when the local destinations have been got from the native layer.
375 * @param {cr.Event} Contains the local destinations.
376 * @private
377 */
378 onLocalDestinationsSet_: function(event) {
379 var localDestinations = event.destinationInfos.map(function(destInfo) {
380 return print_preview.LocalDestinationParser.parse(destInfo);
381 });
382 this.insertDestinations(localDestinations);
383 },
384
385 /**
386 * Called when the native layer retrieves the capabilities for the selected
387 * local destination.
388 * @param {cr.Event} event Contains the capabilities of the local print
389 * destination.
390 * @private
391 */
392 onLocalDestinationCapabilitiesSet_: function(event) {
393 // TODO(rltoscano): There may be a race condition here. This method is
394 // assumed to return capabilities for the currently selected printer. But
395 // between the time the local printer was selected and the capabilities
396 // were retrieved, the selected printer can change. One way to address
397 // this is to include the destination ID in the event.settingsInfo
398 // parameter.
399 if (this.selectedDestination_ && this.selectedDestination_.isLocal) {
400 var capabilities = print_preview.LocalCapabilitiesParser.parse(
401 event.settingsInfo);
402 this.selectedDestination_.capabilities = capabilities;
403 cr.dispatchSimpleEvent(
404 this,
405 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
406 }
407 },
408
409 /**
410 * Called when the /search call completes. Adds the fetched printers to the
411 * destination store.
412 * @param {cr.Event} event Contains the fetched printers.
413 * @private
414 */
415 onCloudPrintSearchDone_: function(event) {
416 this.insertDestinations(event.printers);
417 },
418
419 /**
420 * Called when /printer call completes. Updates the specified destination's
421 * print capabilities.
422 * @param {cr.Event} event Contains detailed information about the
423 * destination.
424 * @private
425 */
426 onCloudPrintPrinterDone_: function(event) {
427 var dest = this.updateDestination(event.printer);
428 if (this.selectedDestination_ == dest) {
429 cr.dispatchSimpleEvent(
430 this,
431 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
432 }
433 },
434
435 /**
436 * Called from native layer after the user was requested to sign in, and did
437 * so successfully.
438 * @private
439 */
440 onDestinationsReload_: function() {
441 this.reset_();
184 this.isInAutoSelectMode_ = true; 442 this.isInAutoSelectMode_ = true;
443 this.startLoadLocalDestinations();
444 this.startLoadRecentCloudDestinations();
445 this.startLoadAllCloudDestinations();
446 },
447
448 /**
449 * Called when no destination was auto-selected after some timeout. Selects
450 * the first destination in store.
451 * @private
452 */
453 onAutoSelectTimeoutExpired_: function() {
454 this.autoSelectTimeout_ = null;
455 assert(this.destinations_.length > 0,
456 'No destinations were loaded before auto-select timeout expired');
457 this.selectDestination(this.destinations_[0]);
185 } 458 }
186 }; 459 };
187 460
188 // Export 461 // Export
189 return { 462 return {
190 DestinationStore: DestinationStore 463 DestinationStore: DestinationStore
191 }; 464 };
192 }); 465 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698