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.
4
5cr.define('print_preview', function() {
6  'use strict';
7
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.
12
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);
27
28    /**
29     * Destination store used to understand which printer is selected.
30     * @type {!print_preview.DestinationStore}
31     * @private
32     */
33    this.destinationStore_ = destinationStore;
34
35    /**
36     * App state used to persist and load ticket values.
37     * @type {!print_preview.AppState}
38     * @private
39     */
40    this.appState_ = appState;
41
42    /**
43     * Information about the document to print.
44     * @type {!print_preview.DocumentInfo}
45     * @private
46     */
47    this.documentInfo_ = documentInfo;
48
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();
55
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);
63
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_);
71
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_);
79
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_);
87
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_);
95
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_);
103
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_);
111
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_);
119
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_);
128
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_);
137
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_);
145
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_);
153
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_);
161
162    /**
163     * Keeps track of event listeners for the print ticket store.
164     * @type {!EventTracker}
165     * @private
166     */
167    this.tracker_ = new EventTracker();
168
169    /**
170     * Whether the print preview has been initialized.
171     * @type {boolean}
172     * @private
173     */
174    this.isInitialized_ = false;
175
176    this.addEventListeners_();
177  };
178
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  };
189
190  PrintTicketStore.prototype = {
191    __proto__: cr.EventTarget.prototype,
192
193    /**
194     * Whether the print preview has been initialized.
195     * @type {boolean}
196     */
197    get isInitialized() {
198      return this.isInitialized_;
199    },
200
201    get collate() {
202      return this.collate_;
203    },
204
205    get color() {
206      return this.color_;
207    },
208
209    get copies() {
210      return this.copies_;
211    },
212
213    get cssBackground() {
214      return this.cssBackground_;
215    },
216
217    get customMargins() {
218      return this.customMargins_;
219    },
220
221    get duplex() {
222      return this.duplex_;
223    },
224
225    get fitToPage() {
226      return this.fitToPage_;
227    },
228
229    get headerFooter() {
230      return this.headerFooter_;
231    },
232
233    get landscape() {
234      return this.landscape_;
235    },
236
237    get marginsType() {
238      return this.marginsType_;
239    },
240
241    get pageRange() {
242      return this.pageRange_;
243    },
244
245    get selectionOnly() {
246      return this.selectionOnly_;
247    },
248
249    /**
250     * @return {!print_preview.MeasurementSystem} Measurement system of the
251     *     local system.
252     */
253    get measurementSystem() {
254      return this.measurementSystem_;
255    },
256
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);
271
272      // Initialize ticket with user's previous values.
273      if (this.appState_.hasField(print_preview.AppState.Field.MARGINS_TYPE)) {
274        this.marginsType_.updateValue(
275            this.appState_.getField(print_preview.AppState.Field.MARGINS_TYPE));
276      }
277      if (this.appState_.hasField(
278          print_preview.AppState.Field.CUSTOM_MARGINS)) {
279        this.customMargins_.updateValue(this.appState_.getField(
280            print_preview.AppState.Field.CUSTOM_MARGINS));
281      }
282      if (this.appState_.hasField(
283          print_preview.AppState.Field.IS_COLOR_ENABLED)) {
284        this.color_.updateValue(this.appState_.getField(
285            print_preview.AppState.Field.IS_COLOR_ENABLED));
286      }
287      if (this.appState_.hasField(
288          print_preview.AppState.Field.IS_DUPLEX_ENABLED)) {
289        this.duplex_.updateValue(this.appState_.getField(
290            print_preview.AppState.Field.IS_DUPLEX_ENABLED));
291      }
292      if (this.appState_.hasField(
293          print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED)) {
294        this.headerFooter_.updateValue(this.appState_.getField(
295            print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED));
296      }
297      if (this.appState_.hasField(
298          print_preview.AppState.Field.IS_LANDSCAPE_ENABLED)) {
299        this.landscape_.updateValue(this.appState_.getField(
300            print_preview.AppState.Field.IS_LANDSCAPE_ENABLED));
301      }
302      if (this.appState_.hasField(
303          print_preview.AppState.Field.IS_COLLATE_ENABLED)) {
304        this.collate_.updateValue(this.appState_.getField(
305            print_preview.AppState.Field.IS_COLLATE_ENABLED));
306      }
307      if (this.appState_.hasField(
308          print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)) {
309        this.cssBackground_.updateValue(this.appState_.getField(
310            print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED));
311      }
312    },
313
314    /**
315     * @return {boolean} {@code true} if the stored print ticket is valid,
316     *     {@code false} otherwise.
317     */
318    isTicketValid: function() {
319      return this.isTicketValidForPreview() &&
320          (!this.pageRange_.isCapabilityAvailable() ||
321              this.pageRange_.isValid());
322    },
323
324    /** @return {boolean} Whether the ticket is valid for preview generation. */
325    isTicketValidForPreview: function() {
326      return (!this.copies.isCapabilityAvailable() || this.copies.isValid()) &&
327          (!this.marginsType_.isCapabilityAvailable() ||
328              !this.marginsType_.isValueEqual(
329                  print_preview.ticket_items.MarginsType.Value.CUSTOM) ||
330              this.customMargins_.isValid());
331    },
332
333    /**
334     * Adds event listeners for the print ticket store.
335     * @private
336     */
337    addEventListeners_: function() {
338      this.tracker_.add(
339          this.destinationStore_,
340          print_preview.DestinationStore.EventType.
341              SELECTED_DESTINATION_CAPABILITIES_READY,
342          this.onSelectedDestinationCapabilitiesReady_.bind(this));
343      // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
344      // events, the consumers of the print ticket store events should listen
345      // for the events from document info instead. Will move this when
346      // consumers are all migrated.
347      this.tracker_.add(
348          this.documentInfo_,
349          print_preview.DocumentInfo.EventType.CHANGE,
350          this.onDocumentInfoChange_.bind(this));
351    },
352
353    /**
354     * Called when the capabilities of the selected destination are ready.
355     * @private
356     */
357    onSelectedDestinationCapabilitiesReady_: function() {
358      var caps = this.destinationStore_.selectedDestination.capabilities;
359      var isFirstUpdate = this.capabilitiesHolder_.get() == null;
360      this.capabilitiesHolder_.set(caps);
361      if (isFirstUpdate) {
362        this.isInitialized_ = true;
363        cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
364      } else {
365        // Reset user selection for certain ticket items.
366        this.customMargins_.updateValue(null);
367
368        if (this.marginsType_.getValue() ==
369            print_preview.ticket_items.MarginsType.Value.CUSTOM) {
370          this.marginsType_.updateValue(
371              print_preview.ticket_items.MarginsType.Value.DEFAULT);
372        }
373        cr.dispatchSimpleEvent(
374            this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
375      }
376    },
377
378    /**
379     * Called when document data model has changed. Dispatches a print ticket
380     * store event.
381     * @private
382     */
383    onDocumentInfoChange_: function() {
384      cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
385    },
386  };
387
388  // Export
389  return {
390    PrintTicketStore: PrintTicketStore
391  };
392});
393