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 * Landscape ticket item.
122 * @type {!print_preview.ticket_items.Landscape}
125 this.landscape_ = new print_preview.ticket_items.Landscape(
126 this.appState_, this.destinationStore_, this.documentInfo_,
127 this.marginsType_, this.customMargins_);
130 * Header-footer ticket item.
131 * @type {!print_preview.ticket_items.HeaderFooter}
134 this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
135 this.appState_, this.documentInfo_, this.marginsType_,
136 this.customMargins_);
139 * Fit-to-page ticket item.
140 * @type {!print_preview.ticket_items.FitToPage}
143 this.fitToPage_ = new print_preview.ticket_items.FitToPage(
144 this.documentInfo_, this.destinationStore_);
147 * Print CSS backgrounds ticket item.
148 * @type {!print_preview.ticket_items.CssBackground}
151 this.cssBackground_ = new print_preview.ticket_items.CssBackground(
152 this.appState_, this.documentInfo_);
155 * Print selection only ticket item.
156 * @type {!print_preview.ticket_items.SelectionOnly}
159 this.selectionOnly_ =
160 new print_preview.ticket_items.SelectionOnly(this.documentInfo_);
163 * Keeps track of event listeners for the print ticket store.
164 * @type {!EventTracker}
167 this.tracker_ = new EventTracker();
170 * Whether the print preview has been initialized.
174 this.isInitialized_ = false;
176 this.addEventListeners_();
180 * Event types dispatched by the print ticket store.
183 PrintTicketStore.EventType = {
184 CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
185 DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
186 INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE',
187 TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE'
190 PrintTicketStore.prototype = {
191 __proto__: cr.EventTarget.prototype,
194 * Whether the print preview has been initialized.
197 get isInitialized() {
198 return this.isInitialized_;
202 return this.collate_;
213 get cssBackground() {
214 return this.cssBackground_;
217 get customMargins() {
218 return this.customMargins_;
226 return this.fitToPage_;
230 return this.headerFooter_;
234 return this.landscape_;
238 return this.marginsType_;
242 return this.pageRange_;
245 get selectionOnly() {
246 return this.selectionOnly_;
250 * @return {!print_preview.MeasurementSystem} Measurement system of the
253 get measurementSystem() {
254 return this.measurementSystem_;
258 * Initializes the print ticket store. Dispatches an INITIALIZE event.
259 * @param {string} thousandsDelimeter Delimeter of the thousands place.
260 * @param {string} decimalDelimeter Delimeter of the decimal point.
261 * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit
262 * of the local measurement system.
263 * @param {boolean} selectionOnly Whether only selected content should be
267 thousandsDelimeter, decimalDelimeter, unitType, selectionOnly) {
268 this.measurementSystem_.setSystem(thousandsDelimeter, decimalDelimeter,
270 this.selectionOnly_.updateValue(selectionOnly);
272 // Initialize ticket with user's previous values.
273 if (this.appState_.hasField(
274 print_preview.AppState.Field.IS_COLOR_ENABLED)) {
275 this.color_.updateValue(this.appState_.getField(
276 print_preview.AppState.Field.IS_COLOR_ENABLED));
278 if (this.appState_.hasField(
279 print_preview.AppState.Field.IS_DUPLEX_ENABLED)) {
280 this.duplex_.updateValue(this.appState_.getField(
281 print_preview.AppState.Field.IS_DUPLEX_ENABLED));
283 if (this.appState_.hasField(
284 print_preview.AppState.Field.IS_LANDSCAPE_ENABLED)) {
285 this.landscape_.updateValue(this.appState_.getField(
286 print_preview.AppState.Field.IS_LANDSCAPE_ENABLED));
288 // Initialize margins after landscape because landscape may reset margins.
289 if (this.appState_.hasField(print_preview.AppState.Field.MARGINS_TYPE)) {
290 this.marginsType_.updateValue(
291 this.appState_.getField(print_preview.AppState.Field.MARGINS_TYPE));
293 if (this.appState_.hasField(
294 print_preview.AppState.Field.CUSTOM_MARGINS)) {
295 this.customMargins_.updateValue(this.appState_.getField(
296 print_preview.AppState.Field.CUSTOM_MARGINS));
298 if (this.appState_.hasField(
299 print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED)) {
300 this.headerFooter_.updateValue(this.appState_.getField(
301 print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED));
303 if (this.appState_.hasField(
304 print_preview.AppState.Field.IS_COLLATE_ENABLED)) {
305 this.collate_.updateValue(this.appState_.getField(
306 print_preview.AppState.Field.IS_COLLATE_ENABLED));
308 if (this.appState_.hasField(
309 print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)) {
310 this.cssBackground_.updateValue(this.appState_.getField(
311 print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED));
316 * @return {boolean} {@code true} if the stored print ticket is valid,
317 * {@code false} otherwise.
319 isTicketValid: function() {
320 return this.isTicketValidForPreview() &&
321 (!this.pageRange_.isCapabilityAvailable() ||
322 this.pageRange_.isValid());
325 /** @return {boolean} Whether the ticket is valid for preview generation. */
326 isTicketValidForPreview: function() {
327 return (!this.copies.isCapabilityAvailable() || this.copies.isValid()) &&
328 (!this.marginsType_.isCapabilityAvailable() ||
329 !this.marginsType_.isValueEqual(
330 print_preview.ticket_items.MarginsType.Value.CUSTOM) ||
331 this.customMargins_.isValid());
335 * Creates an object that represents a Google Cloud Print print ticket.
336 * @param {!print_preview.Destination} destination Destination to print to.
337 * @return {!Object} Google Cloud Print print ticket.
339 createPrintTicket: function(destination) {
340 assert(!destination.isLocal || destination.isPrivet,
341 'Trying to create a Google Cloud Print print ticket for a local ' +
342 ' non-privet destination');
344 assert(destination.capabilities,
345 'Trying to create a Google Cloud Print print ticket for a ' +
346 'destination with no print capabilities');
351 if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
352 cjt.print.collate = {collate: this.collate.getValue() == 'true'};
354 if (this.color.isCapabilityAvailable() && this.color.isUserEdited()) {
355 var colorType = this.color.getValue() ?
356 'STANDARD_COLOR' : 'STANDARD_MONOCHROME';
357 // Find option with this colorType to read its vendor_id.
358 var selectedOptions = destination.capabilities.printer.color.option.
359 filter(function(option) {
360 return option.type == colorType;
362 if (selectedOptions.length == 0) {
363 console.error('Could not find correct color option');
365 cjt.print.color = {type: colorType};
366 if (selectedOptions[0].hasOwnProperty('vendor_id')) {
367 cjt.print.color.vendor_id = selectedOptions[0].vendor_id;
371 if (this.copies.isCapabilityAvailable() && this.copies.isUserEdited()) {
372 cjt.print.copies = {copies: this.copies.getValueAsNumber()};
374 if (this.duplex.isCapabilityAvailable() && this.duplex.isUserEdited()) {
376 {type: this.duplex.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
378 if (this.landscape.isCapabilityAvailable() &&
379 this.landscape.isUserEdited()) {
380 cjt.print.page_orientation =
381 {type: this.landscape.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
383 return JSON.stringify(cjt);
387 * Adds event listeners for the print ticket store.
390 addEventListeners_: function() {
392 this.destinationStore_,
393 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
394 this.onDestinationSelect_.bind(this));
397 this.destinationStore_,
398 print_preview.DestinationStore.EventType.
399 SELECTED_DESTINATION_CAPABILITIES_READY,
400 this.onSelectedDestinationCapabilitiesReady_.bind(this));
403 this.destinationStore_,
404 print_preview.DestinationStore.EventType.
405 CACHED_SELECTED_DESTINATION_INFO_READY,
406 this.onSelectedDestinationCapabilitiesReady_.bind(this));
408 // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
409 // events, the consumers of the print ticket store events should listen
410 // for the events from document info instead. Will move this when
411 // consumers are all migrated.
414 print_preview.DocumentInfo.EventType.CHANGE,
415 this.onDocumentInfoChange_.bind(this));
419 * Called when the destination selected.
422 onDestinationSelect_: function() {
423 // Reset user selection for certain ticket items.
424 if (this.capabilitiesHolder_.get() != null) {
425 this.customMargins_.updateValue(null);
426 if (this.marginsType_.getValue() ==
427 print_preview.ticket_items.MarginsType.Value.CUSTOM) {
428 this.marginsType_.updateValue(
429 print_preview.ticket_items.MarginsType.Value.DEFAULT);
435 * Called when the capabilities of the selected destination are ready.
438 onSelectedDestinationCapabilitiesReady_: function() {
439 var caps = this.destinationStore_.selectedDestination.capabilities;
440 var isFirstUpdate = this.capabilitiesHolder_.get() == null;
441 this.capabilitiesHolder_.set(caps);
443 this.isInitialized_ = true;
444 cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
446 cr.dispatchSimpleEvent(
447 this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
452 * Called when document data model has changed. Dispatches a print ticket
456 onDocumentInfoChange_: function() {
457 cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
463 PrintTicketStore: PrintTicketStore