Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / print_preview / data / print_ticket_store.js
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
5 cr.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      * Media size ticket item.
122      * @type {!print_preview.ticket_items.MediaSize}
123      * @private
124      */
125     this.mediaSize_ = new print_preview.ticket_items.MediaSize(
126         this.appState_,
127         this.destinationStore_,
128         this.documentInfo_,
129         this.marginsType_,
130         this.customMargins_);
131
132     /**
133      * Landscape ticket item.
134      * @type {!print_preview.ticket_items.Landscape}
135      * @private
136      */
137     this.landscape_ = new print_preview.ticket_items.Landscape(
138         this.appState_,
139         this.destinationStore_,
140         this.documentInfo_,
141         this.marginsType_,
142         this.customMargins_);
143
144     /**
145      * Header-footer ticket item.
146      * @type {!print_preview.ticket_items.HeaderFooter}
147      * @private
148      */
149     this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
150         this.appState_,
151         this.documentInfo_,
152         this.marginsType_,
153         this.customMargins_);
154
155     /**
156      * Fit-to-page ticket item.
157      * @type {!print_preview.ticket_items.FitToPage}
158      * @private
159      */
160     this.fitToPage_ = new print_preview.ticket_items.FitToPage(
161         this.documentInfo_, this.destinationStore_);
162
163     /**
164      * Print CSS backgrounds ticket item.
165      * @type {!print_preview.ticket_items.CssBackground}
166      * @private
167      */
168     this.cssBackground_ = new print_preview.ticket_items.CssBackground(
169         this.appState_, this.documentInfo_);
170
171     /**
172      * Print selection only ticket item.
173      * @type {!print_preview.ticket_items.SelectionOnly}
174      * @private
175      */
176     this.selectionOnly_ =
177         new print_preview.ticket_items.SelectionOnly(this.documentInfo_);
178
179     /**
180      * Vendor ticket items.
181      * @type {!print_preview.ticket_items.VendorItems}
182      * @private
183      */
184     this.vendorItems_ = new print_preview.ticket_items.VendorItems(
185         this.appState_, this.destinationStore_);
186
187     /**
188      * Keeps track of event listeners for the print ticket store.
189      * @type {!EventTracker}
190      * @private
191      */
192     this.tracker_ = new EventTracker();
193
194     /**
195      * Whether the print preview has been initialized.
196      * @type {boolean}
197      * @private
198      */
199     this.isInitialized_ = false;
200
201     this.addEventListeners_();
202   };
203
204   /**
205    * Event types dispatched by the print ticket store.
206    * @enum {string}
207    */
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'
213   };
214
215   PrintTicketStore.prototype = {
216     __proto__: cr.EventTarget.prototype,
217
218     /**
219      * Whether the print preview has been initialized.
220      * @type {boolean}
221      */
222     get isInitialized() {
223       return this.isInitialized_;
224     },
225
226     get collate() {
227       return this.collate_;
228     },
229
230     get color() {
231       return this.color_;
232     },
233
234     get copies() {
235       return this.copies_;
236     },
237
238     get cssBackground() {
239       return this.cssBackground_;
240     },
241
242     get customMargins() {
243       return this.customMargins_;
244     },
245
246     get duplex() {
247       return this.duplex_;
248     },
249
250     get fitToPage() {
251       return this.fitToPage_;
252     },
253
254     get headerFooter() {
255       return this.headerFooter_;
256     },
257
258     get mediaSize() {
259       return this.mediaSize_;
260     },
261
262     get landscape() {
263       return this.landscape_;
264     },
265
266     get marginsType() {
267       return this.marginsType_;
268     },
269
270     get pageRange() {
271       return this.pageRange_;
272     },
273
274     get selectionOnly() {
275       return this.selectionOnly_;
276     },
277
278     get vendorItems() {
279       return this.vendorItems_;
280     },
281
282     /**
283      * @return {!print_preview.MeasurementSystem} Measurement system of the
284      *     local system.
285      */
286     get measurementSystem() {
287       return this.measurementSystem_;
288     },
289
290     /**
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
297      *     printed.
298      */
299     init: function(
300         thousandsDelimeter, decimalDelimeter, unitType, selectionOnly) {
301       this.measurementSystem_.setSystem(thousandsDelimeter, decimalDelimeter,
302                                         unitType);
303       this.selectionOnly_.updateValue(selectionOnly);
304
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));
310       }
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));
315       }
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));
319       }
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));
324       }
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));
329       }
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));
334       }
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));
339       }
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));
344       }
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));
349       }
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));
354     }
355     },
356
357     /**
358      * @return {boolean} {@code true} if the stored print ticket is valid,
359      *     {@code false} otherwise.
360      */
361     isTicketValid: function() {
362       return this.isTicketValidForPreview() &&
363           (!this.copies_.isCapabilityAvailable() || this.copies_.isValid()) &&
364           (!this.pageRange_.isCapabilityAvailable() ||
365               this.pageRange_.isValid());
366     },
367
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());
374     },
375
376     /**
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.
380      */
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');
385
386       assert(destination.capabilities,
387              'Trying to create a Google Cloud Print print ticket for a ' +
388                  'destination with no print capabilities');
389       var cjt = {
390         version: '1.0',
391         print: {}
392       };
393       if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
394         cjt.print.collate = {collate: this.collate.getValue()};
395       }
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');
400         } else {
401           cjt.print.color = {type: selectedOption.type};
402           if (selectedOption.hasOwnProperty('vendor_id')) {
403             cjt.print.color.vendor_id = selectedOption.vendor_id;
404           }
405         }
406       }
407       if (this.copies.isCapabilityAvailable() && this.copies.isUserEdited()) {
408         cjt.print.copies = {copies: this.copies.getValueAsNumber()};
409       }
410       if (this.duplex.isCapabilityAvailable() && this.duplex.isUserEdited()) {
411         cjt.print.duplex =
412             {type: this.duplex.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
413       }
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
421         };
422       }
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'};
432       }
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]});
441           }
442         }
443       }
444       return JSON.stringify(cjt);
445     },
446
447     /**
448      * Adds event listeners for the print ticket store.
449      * @private
450      */
451     addEventListeners_: function() {
452       this.tracker_.add(
453           this.destinationStore_,
454           print_preview.DestinationStore.EventType.DESTINATION_SELECT,
455           this.onDestinationSelect_.bind(this));
456
457       this.tracker_.add(
458           this.destinationStore_,
459           print_preview.DestinationStore.EventType.
460               SELECTED_DESTINATION_CAPABILITIES_READY,
461           this.onSelectedDestinationCapabilitiesReady_.bind(this));
462
463       this.tracker_.add(
464           this.destinationStore_,
465           print_preview.DestinationStore.EventType.
466               CACHED_SELECTED_DESTINATION_INFO_READY,
467           this.onSelectedDestinationCapabilitiesReady_.bind(this));
468
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.
473       this.tracker_.add(
474           this.documentInfo_,
475           print_preview.DocumentInfo.EventType.CHANGE,
476           this.onDocumentInfoChange_.bind(this));
477     },
478
479     /**
480      * Called when the destination selected.
481      * @private
482      */
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);
491         }
492         this.vendorItems_.updateValue({});
493       }
494     },
495
496     /**
497      * Called when the capabilities of the selected destination are ready.
498      * @private
499      */
500     onSelectedDestinationCapabilitiesReady_: function() {
501       var caps = this.destinationStore_.selectedDestination.capabilities;
502       var isFirstUpdate = this.capabilitiesHolder_.get() == null;
503       this.capabilitiesHolder_.set(caps);
504       if (isFirstUpdate) {
505         this.isInitialized_ = true;
506         cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
507       } else {
508         cr.dispatchSimpleEvent(
509             this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
510       }
511     },
512
513     /**
514      * Called when document data model has changed. Dispatches a print ticket
515      * store event.
516      * @private
517      */
518     onDocumentInfoChange_: function() {
519       cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
520     },
521   };
522
523   // Export
524   return {
525     PrintTicketStore: PrintTicketStore
526   };
527 });