Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / data / print_ticket_store.js
blob267b539ee3919aab054042632005fdf66d2f65db
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() {
6   'use strict';
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.
13   /**
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.
22    * @constructor
23    * @extends {cr.EventTarget}
24    */
25   function PrintTicketStore(destinationStore, appState, documentInfo) {
26     cr.EventTarget.call(this);
28     /**
29      * Destination store used to understand which printer is selected.
30      * @type {!print_preview.DestinationStore}
31      * @private
32      */
33     this.destinationStore_ = destinationStore;
35     /**
36      * App state used to persist and load ticket values.
37      * @type {!print_preview.AppState}
38      * @private
39      */
40     this.appState_ = appState;
42     /**
43      * Information about the document to print.
44      * @type {!print_preview.DocumentInfo}
45      * @private
46      */
47     this.documentInfo_ = documentInfo;
49     /**
50      * Printing capabilities of Chromium and the currently selected destination.
51      * @type {!print_preview.CapabilitiesHolder}
52      * @private
53      */
54     this.capabilitiesHolder_ = new print_preview.CapabilitiesHolder();
56     /**
57      * Current measurement system. Used to work with margin measurements.
58      * @type {!print_preview.MeasurementSystem}
59      * @private
60      */
61     this.measurementSystem_ = new print_preview.MeasurementSystem(
62         ',', '.', print_preview.MeasurementSystem.UnitType.IMPERIAL);
64     /**
65      * Collate ticket item.
66      * @type {!print_preview.ticket_items.Collate}
67      * @private
68      */
69     this.collate_ = new print_preview.ticket_items.Collate(
70         this.appState_, this.destinationStore_);
72     /**
73      * Color ticket item.
74      * @type {!print_preview.ticket_items.Color}
75      * @private
76      */
77     this.color_ = new print_preview.ticket_items.Color(
78         this.appState_, this.destinationStore_);
80     /**
81      * Copies ticket item.
82      * @type {!print_preview.ticket_items.Copies}
83      * @private
84      */
85     this.copies_ =
86         new print_preview.ticket_items.Copies(this.destinationStore_);
88     /**
89      * Duplex ticket item.
90      * @type {!print_preview.ticket_items.Duplex}
91      * @private
92      */
93     this.duplex_ = new print_preview.ticket_items.Duplex(
94         this.appState_, this.destinationStore_);
96     /**
97      * Page range ticket item.
98      * @type {!print_preview.ticket_items.PageRange}
99      * @private
100      */
101     this.pageRange_ =
102         new print_preview.ticket_items.PageRange(this.documentInfo_);
104     /**
105      * Custom margins ticket item.
106      * @type {!print_preview.ticket_items.CustomMargins}
107      * @private
108      */
109     this.customMargins_ = new print_preview.ticket_items.CustomMargins(
110         this.appState_, this.documentInfo_);
112     /**
113      * Margins type ticket item.
114      * @type {!print_preview.ticket_items.MarginsType}
115      * @private
116      */
117     this.marginsType_ = new print_preview.ticket_items.MarginsType(
118         this.appState_, this.documentInfo_, this.customMargins_);
120     /**
121      * Landscape ticket item.
122      * @type {!print_preview.ticket_items.Landscape}
123      * @private
124      */
125     this.landscape_ = new print_preview.ticket_items.Landscape(
126         this.appState_, this.destinationStore_, this.documentInfo_,
127         this.marginsType_, this.customMargins_);
129     /**
130      * Header-footer ticket item.
131      * @type {!print_preview.ticket_items.HeaderFooter}
132      * @private
133      */
134     this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
135         this.appState_, this.documentInfo_, this.marginsType_,
136         this.customMargins_);
138     /**
139      * Fit-to-page ticket item.
140      * @type {!print_preview.ticket_items.FitToPage}
141      * @private
142      */
143     this.fitToPage_ = new print_preview.ticket_items.FitToPage(
144         this.documentInfo_, this.destinationStore_);
146     /**
147      * Print CSS backgrounds ticket item.
148      * @type {!print_preview.ticket_items.CssBackground}
149      * @private
150      */
151     this.cssBackground_ = new print_preview.ticket_items.CssBackground(
152         this.appState_, this.documentInfo_);
154     /**
155      * Print selection only ticket item.
156      * @type {!print_preview.ticket_items.SelectionOnly}
157      * @private
158      */
159     this.selectionOnly_ =
160         new print_preview.ticket_items.SelectionOnly(this.documentInfo_);
162     /**
163      * Keeps track of event listeners for the print ticket store.
164      * @type {!EventTracker}
165      * @private
166      */
167     this.tracker_ = new EventTracker();
169     /**
170      * Whether the print preview has been initialized.
171      * @type {boolean}
172      * @private
173      */
174     this.isInitialized_ = false;
176     this.addEventListeners_();
177   };
179   /**
180    * Event types dispatched by the print ticket store.
181    * @enum {string}
182    */
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'
188   };
190   PrintTicketStore.prototype = {
191     __proto__: cr.EventTarget.prototype,
193     /**
194      * Whether the print preview has been initialized.
195      * @type {boolean}
196      */
197     get isInitialized() {
198       return this.isInitialized_;
199     },
201     get collate() {
202       return this.collate_;
203     },
205     get color() {
206       return this.color_;
207     },
209     get copies() {
210       return this.copies_;
211     },
213     get cssBackground() {
214       return this.cssBackground_;
215     },
217     get customMargins() {
218       return this.customMargins_;
219     },
221     get duplex() {
222       return this.duplex_;
223     },
225     get fitToPage() {
226       return this.fitToPage_;
227     },
229     get headerFooter() {
230       return this.headerFooter_;
231     },
233     get landscape() {
234       return this.landscape_;
235     },
237     get marginsType() {
238       return this.marginsType_;
239     },
241     get pageRange() {
242       return this.pageRange_;
243     },
245     get selectionOnly() {
246       return this.selectionOnly_;
247     },
249     /**
250      * @return {!print_preview.MeasurementSystem} Measurement system of the
251      *     local system.
252      */
253     get measurementSystem() {
254       return this.measurementSystem_;
255     },
257     /**
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
264      *     printed.
265      */
266     init: function(
267         thousandsDelimeter, decimalDelimeter, unitType, selectionOnly) {
268       this.measurementSystem_.setSystem(thousandsDelimeter, decimalDelimeter,
269                                         unitType);
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));
277       }
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));
282       }
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));
287       }
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));
292       }
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));
297       }
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));
302       }
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));
307       }
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));
312       }
313     },
315     /**
316      * @return {boolean} {@code true} if the stored print ticket is valid,
317      *     {@code false} otherwise.
318      */
319     isTicketValid: function() {
320       return this.isTicketValidForPreview() &&
321           (!this.pageRange_.isCapabilityAvailable() ||
322               this.pageRange_.isValid());
323     },
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());
332     },
334     /**
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.
338      */
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');
347       var cjt = {
348         version: '1.0',
349         print: {}
350       };
351       if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
352         cjt.print.collate = {collate: this.collate.getValue() == 'true'};
353       }
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;
361             });
362         if (selectedOptions.length == 0) {
363           console.error('Could not find correct color option');
364         } else {
365           cjt.print.color = {type: colorType};
366           if (selectedOptions[0].hasOwnProperty('vendor_id')) {
367             cjt.print.color.vendor_id = selectedOptions[0].vendor_id;
368           }
369         }
370       }
371       if (this.copies.isCapabilityAvailable() && this.copies.isUserEdited()) {
372         cjt.print.copies = {copies: this.copies.getValueAsNumber()};
373       }
374       if (this.duplex.isCapabilityAvailable() && this.duplex.isUserEdited()) {
375         cjt.print.duplex =
376             {type: this.duplex.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
377       }
378       if (this.landscape.isCapabilityAvailable() &&
379           this.landscape.isUserEdited()) {
380         cjt.print.page_orientation =
381             {type: this.landscape.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
382       }
383       return JSON.stringify(cjt);
384     },
386     /**
387      * Adds event listeners for the print ticket store.
388      * @private
389      */
390     addEventListeners_: function() {
391       this.tracker_.add(
392           this.destinationStore_,
393           print_preview.DestinationStore.EventType.DESTINATION_SELECT,
394           this.onDestinationSelect_.bind(this));
396       this.tracker_.add(
397           this.destinationStore_,
398           print_preview.DestinationStore.EventType.
399               SELECTED_DESTINATION_CAPABILITIES_READY,
400           this.onSelectedDestinationCapabilitiesReady_.bind(this));
402       this.tracker_.add(
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.
412       this.tracker_.add(
413           this.documentInfo_,
414           print_preview.DocumentInfo.EventType.CHANGE,
415           this.onDocumentInfoChange_.bind(this));
416     },
418     /**
419      * Called when the destination selected.
420      * @private
421      */
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);
430         }
431       }
432     },
434     /**
435      * Called when the capabilities of the selected destination are ready.
436      * @private
437      */
438     onSelectedDestinationCapabilitiesReady_: function() {
439       var caps = this.destinationStore_.selectedDestination.capabilities;
440       var isFirstUpdate = this.capabilitiesHolder_.get() == null;
441       this.capabilitiesHolder_.set(caps);
442       if (isFirstUpdate) {
443         this.isInitialized_ = true;
444         cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
445       } else {
446         cr.dispatchSimpleEvent(
447             this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
448       }
449     },
451     /**
452      * Called when document data model has changed. Dispatches a print ticket
453      * store event.
454      * @private
455      */
456     onDocumentInfoChange_: function() {
457       cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
458     },
459   };
461   // Export
462   return {
463     PrintTicketStore: PrintTicketStore
464   };