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
3 // found in the LICENSE file.
5 cr.define('print_preview', function() {
8 // TODO(rltoscano): Maybe clear print ticket when destination changes. Or
9 // better yet, carry over any print ticket state that is possible. I.e. if
10 // destination changes, the new destination might not support duplex anymore,
11 // so we should clear the ticket's isDuplexEnabled state.
14 * Storage of the print ticket and document statistics. Dispatches events when
15 * the contents of the print ticket or document statistics change. Also
16 * handles validation of the print ticket against destination capabilities and
17 * against the document.
18 * @param {!print_preview.DestinationStore} destinationStore Used to
19 * understand which printer is selected.
20 * @param {!print_preview.AppState} appState Print preview application state.
21 * @param {!print_preview.DocumentInfo} documentInfo Document data model.
23 * @extends {cr.EventTarget}
25 function PrintTicketStore(destinationStore, appState, documentInfo) {
26 cr.EventTarget.call(this);
29 * Destination store used to understand which printer is selected.
30 * @type {!print_preview.DestinationStore}
33 this.destinationStore_ = destinationStore;
36 * App state used to persist and load ticket values.
37 * @type {!print_preview.AppState}
40 this.appState_ = appState;
43 * Information about the document to print.
44 * @type {!print_preview.DocumentInfo}
47 this.documentInfo_ = documentInfo;
50 * Printing capabilities of Chromium and the currently selected destination.
51 * @type {!print_preview.CapabilitiesHolder}
54 this.capabilitiesHolder_ = new print_preview.CapabilitiesHolder();
57 * Current measurement system. Used to work with margin measurements.
58 * @type {!print_preview.MeasurementSystem}
61 this.measurementSystem_ = new print_preview.MeasurementSystem(
62 ',', '.', print_preview.MeasurementSystem.UnitType.IMPERIAL);
65 * Collate ticket item.
66 * @type {!print_preview.ticket_items.Collate}
69 this.collate_ = new print_preview.ticket_items.Collate(
70 this.appState_, this.destinationStore_);
74 * @type {!print_preview.ticket_items.Color}
77 this.color_ = new print_preview.ticket_items.Color(
78 this.appState_, this.destinationStore_);
82 * @type {!print_preview.ticket_items.Copies}
86 new print_preview.ticket_items.Copies(this.destinationStore_);
90 * @type {!print_preview.ticket_items.Duplex}
93 this.duplex_ = new print_preview.ticket_items.Duplex(
94 this.appState_, this.destinationStore_);
97 * Page range ticket item.
98 * @type {!print_preview.ticket_items.PageRange}
102 new print_preview.ticket_items.PageRange(this.documentInfo_);
105 * Custom margins ticket item.
106 * @type {!print_preview.ticket_items.CustomMargins}
109 this.customMargins_ = new print_preview.ticket_items.CustomMargins(
110 this.appState_, this.documentInfo_);
113 * Margins type ticket item.
114 * @type {!print_preview.ticket_items.MarginsType}
117 this.marginsType_ = new print_preview.ticket_items.MarginsType(
118 this.appState_, this.documentInfo_, this.customMargins_);
121 * Media size ticket item.
122 * @type {!print_preview.ticket_items.MediaSize}
125 this.mediaSize_ = new print_preview.ticket_items.MediaSize(
127 this.destinationStore_,
130 this.customMargins_);
133 * Landscape ticket item.
134 * @type {!print_preview.ticket_items.Landscape}
137 this.landscape_ = new print_preview.ticket_items.Landscape(
139 this.destinationStore_,
142 this.customMargins_);
145 * Header-footer ticket item.
146 * @type {!print_preview.ticket_items.HeaderFooter}
149 this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
153 this.customMargins_);
156 * Fit-to-page ticket item.
157 * @type {!print_preview.ticket_items.FitToPage}
160 this.fitToPage_ = new print_preview.ticket_items.FitToPage(
161 this.documentInfo_, this.destinationStore_);
164 * Print CSS backgrounds ticket item.
165 * @type {!print_preview.ticket_items.CssBackground}
168 this.cssBackground_ = new print_preview.ticket_items.CssBackground(
169 this.appState_, this.documentInfo_);
172 * Print selection only ticket item.
173 * @type {!print_preview.ticket_items.SelectionOnly}
176 this.selectionOnly_ =
177 new print_preview.ticket_items.SelectionOnly(this.documentInfo_);
180 * Vendor ticket items.
181 * @type {!print_preview.ticket_items.VendorItems}
184 this.vendorItems_ = new print_preview.ticket_items.VendorItems(
185 this.appState_, this.destinationStore_);
188 * Keeps track of event listeners for the print ticket store.
189 * @type {!EventTracker}
192 this.tracker_ = new EventTracker();
195 * Whether the print preview has been initialized.
199 this.isInitialized_ = false;
201 this.addEventListeners_();
205 * Event types dispatched by the print ticket store.
208 PrintTicketStore.EventType = {
209 CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
210 DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
211 INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE',
212 TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE'
215 PrintTicketStore.prototype = {
216 __proto__: cr.EventTarget.prototype,
219 * Whether the print preview has been initialized.
222 get isInitialized() {
223 return this.isInitialized_;
227 return this.collate_;
238 get cssBackground() {
239 return this.cssBackground_;
242 get customMargins() {
243 return this.customMargins_;
251 return this.fitToPage_;
255 return this.headerFooter_;
259 return this.mediaSize_;
263 return this.landscape_;
267 return this.marginsType_;
271 return this.pageRange_;
274 get selectionOnly() {
275 return this.selectionOnly_;
279 return this.vendorItems_;
283 * @return {!print_preview.MeasurementSystem} Measurement system of the
286 get measurementSystem() {
287 return this.measurementSystem_;
291 * Initializes the print ticket store. Dispatches an INITIALIZE event.
292 * @param {string} thousandsDelimeter Delimeter of the thousands place.
293 * @param {string} decimalDelimeter Delimeter of the decimal point.
294 * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit
295 * of the local measurement system.
296 * @param {boolean} selectionOnly Whether only selected content should be
300 thousandsDelimeter, decimalDelimeter, unitType, selectionOnly) {
301 this.measurementSystem_.setSystem(thousandsDelimeter, decimalDelimeter,
303 this.selectionOnly_.updateValue(selectionOnly);
305 // Initialize ticket with user's previous values.
306 if (this.appState_.hasField(
307 print_preview.AppState.Field.IS_COLOR_ENABLED)) {
308 this.color_.updateValue(this.appState_.getField(
309 print_preview.AppState.Field.IS_COLOR_ENABLED));
311 if (this.appState_.hasField(
312 print_preview.AppState.Field.IS_DUPLEX_ENABLED)) {
313 this.duplex_.updateValue(this.appState_.getField(
314 print_preview.AppState.Field.IS_DUPLEX_ENABLED));
316 if (this.appState_.hasField(print_preview.AppState.Field.MEDIA_SIZE)) {
317 this.mediaSize_.updateValue(this.appState_.getField(
318 print_preview.AppState.Field.MEDIA_SIZE));
320 if (this.appState_.hasField(
321 print_preview.AppState.Field.IS_LANDSCAPE_ENABLED)) {
322 this.landscape_.updateValue(this.appState_.getField(
323 print_preview.AppState.Field.IS_LANDSCAPE_ENABLED));
325 // Initialize margins after landscape because landscape may reset margins.
326 if (this.appState_.hasField(print_preview.AppState.Field.MARGINS_TYPE)) {
327 this.marginsType_.updateValue(
328 this.appState_.getField(print_preview.AppState.Field.MARGINS_TYPE));
330 if (this.appState_.hasField(
331 print_preview.AppState.Field.CUSTOM_MARGINS)) {
332 this.customMargins_.updateValue(this.appState_.getField(
333 print_preview.AppState.Field.CUSTOM_MARGINS));
335 if (this.appState_.hasField(
336 print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED)) {
337 this.headerFooter_.updateValue(this.appState_.getField(
338 print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED));
340 if (this.appState_.hasField(
341 print_preview.AppState.Field.IS_COLLATE_ENABLED)) {
342 this.collate_.updateValue(this.appState_.getField(
343 print_preview.AppState.Field.IS_COLLATE_ENABLED));
345 if (this.appState_.hasField(
346 print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)) {
347 this.cssBackground_.updateValue(this.appState_.getField(
348 print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED));
350 if (this.appState_.hasField(
351 print_preview.AppState.Field.VENDOR_OPTIONS)) {
352 this.vendorItems_.updateValue(this.appState_.getField(
353 print_preview.AppState.Field.VENDOR_OPTIONS));
358 * @return {boolean} {@code true} if the stored print ticket is valid,
359 * {@code false} otherwise.
361 isTicketValid: function() {
362 return this.isTicketValidForPreview() &&
363 (!this.copies_.isCapabilityAvailable() || this.copies_.isValid()) &&
364 (!this.pageRange_.isCapabilityAvailable() ||
365 this.pageRange_.isValid());
368 /** @return {boolean} Whether the ticket is valid for preview generation. */
369 isTicketValidForPreview: function() {
370 return (!this.marginsType_.isCapabilityAvailable() ||
371 !this.marginsType_.isValueEqual(
372 print_preview.ticket_items.MarginsType.Value.CUSTOM) ||
373 this.customMargins_.isValid());
377 * Creates an object that represents a Google Cloud Print print ticket.
378 * @param {!print_preview.Destination} destination Destination to print to.
379 * @return {!Object} Google Cloud Print print ticket.
381 createPrintTicket: function(destination) {
382 assert(!destination.isLocal || destination.isPrivet,
383 'Trying to create a Google Cloud Print print ticket for a local ' +
384 ' non-privet destination');
386 assert(destination.capabilities,
387 'Trying to create a Google Cloud Print print ticket for a ' +
388 'destination with no print capabilities');
393 if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
394 cjt.print.collate = {collate: this.collate.getValue()};
396 if (this.color.isCapabilityAvailable() && this.color.isUserEdited()) {
397 var selectedOption = this.color.getSelectedOption();
398 if (!selectedOption) {
399 console.error('Could not find correct color option');
401 cjt.print.color = {type: selectedOption.type};
402 if (selectedOption.hasOwnProperty('vendor_id')) {
403 cjt.print.color.vendor_id = selectedOption.vendor_id;
407 if (this.copies.isCapabilityAvailable() && this.copies.isUserEdited()) {
408 cjt.print.copies = {copies: this.copies.getValueAsNumber()};
410 if (this.duplex.isCapabilityAvailable() && this.duplex.isUserEdited()) {
412 {type: this.duplex.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
414 if (this.mediaSize.isCapabilityAvailable()) {
415 var value = this.mediaSize.getValue();
416 cjt.print.media_size = {
417 width_microns: value.width_microns,
418 height_microns: value.height_microns,
419 is_continuous_feed: value.is_continuous_feed,
420 vendor_id: value.vendor_id
423 if (!this.landscape.isCapabilityAvailable()) {
424 // In this case "orientation" option is hidden from user, so user can't
425 // adjust it for page content, see Landscape.isCapabilityAvailable().
426 // We can improve results if we set AUTO here.
427 if (this.landscape.hasOption('AUTO'))
428 cjt.print.page_orientation = { type: 'AUTO' };
429 } else if (this.landscape.isUserEdited()) {
430 cjt.print.page_orientation =
431 {type: this.landscape.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
433 if (this.vendorItems.isCapabilityAvailable() &&
434 this.vendorItems.isUserEdited()) {
435 var items = this.vendorItems.ticketItems;
436 cjt.print.vendor_ticket_item = [];
437 for (var itemId in items) {
438 if (items.hasOwnProperty(itemId)) {
439 cjt.print.vendor_ticket_item.push(
440 {id: itemId, value: items[itemId]});
444 return JSON.stringify(cjt);
448 * Adds event listeners for the print ticket store.
451 addEventListeners_: function() {
453 this.destinationStore_,
454 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
455 this.onDestinationSelect_.bind(this));
458 this.destinationStore_,
459 print_preview.DestinationStore.EventType.
460 SELECTED_DESTINATION_CAPABILITIES_READY,
461 this.onSelectedDestinationCapabilitiesReady_.bind(this));
464 this.destinationStore_,
465 print_preview.DestinationStore.EventType.
466 CACHED_SELECTED_DESTINATION_INFO_READY,
467 this.onSelectedDestinationCapabilitiesReady_.bind(this));
469 // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
470 // events, the consumers of the print ticket store events should listen
471 // for the events from document info instead. Will move this when
472 // consumers are all migrated.
475 print_preview.DocumentInfo.EventType.CHANGE,
476 this.onDocumentInfoChange_.bind(this));
480 * Called when the destination selected.
483 onDestinationSelect_: function() {
484 // Reset user selection for certain ticket items.
485 if (this.capabilitiesHolder_.get() != null) {
486 this.customMargins_.updateValue(null);
487 if (this.marginsType_.getValue() ==
488 print_preview.ticket_items.MarginsType.Value.CUSTOM) {
489 this.marginsType_.updateValue(
490 print_preview.ticket_items.MarginsType.Value.DEFAULT);
492 this.vendorItems_.updateValue({});
497 * Called when the capabilities of the selected destination are ready.
500 onSelectedDestinationCapabilitiesReady_: function() {
501 var caps = this.destinationStore_.selectedDestination.capabilities;
502 var isFirstUpdate = this.capabilitiesHolder_.get() == null;
503 this.capabilitiesHolder_.set(caps);
505 this.isInitialized_ = true;
506 cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
508 cr.dispatchSimpleEvent(
509 this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
514 * Called when document data model has changed. Dispatches a print ticket
518 onDocumentInfoChange_: function() {
519 cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
525 PrintTicketStore: PrintTicketStore