Update To 11.40.268.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      * DPI ticket item.
90      * @type {!print_preview.ticket_items.Dpi}
91      * @private
92      */
93     this.dpi_ = new print_preview.ticket_items.Dpi(
94         this.appState_, this.destinationStore_);
95
96     /**
97      * Duplex ticket item.
98      * @type {!print_preview.ticket_items.Duplex}
99      * @private
100      */
101     this.duplex_ = new print_preview.ticket_items.Duplex(
102         this.appState_, this.destinationStore_);
103
104     /**
105      * Page range ticket item.
106      * @type {!print_preview.ticket_items.PageRange}
107      * @private
108      */
109     this.pageRange_ =
110         new print_preview.ticket_items.PageRange(this.documentInfo_);
111
112     /**
113      * Custom margins ticket item.
114      * @type {!print_preview.ticket_items.CustomMargins}
115      * @private
116      */
117     this.customMargins_ = new print_preview.ticket_items.CustomMargins(
118         this.appState_, this.documentInfo_);
119
120     /**
121      * Margins type ticket item.
122      * @type {!print_preview.ticket_items.MarginsType}
123      * @private
124      */
125     this.marginsType_ = new print_preview.ticket_items.MarginsType(
126         this.appState_, this.documentInfo_, this.customMargins_);
127
128     /**
129      * Media size ticket item.
130      * @type {!print_preview.ticket_items.MediaSize}
131      * @private
132      */
133     this.mediaSize_ = new print_preview.ticket_items.MediaSize(
134         this.appState_,
135         this.destinationStore_,
136         this.documentInfo_,
137         this.marginsType_,
138         this.customMargins_);
139
140     /**
141      * Landscape ticket item.
142      * @type {!print_preview.ticket_items.Landscape}
143      * @private
144      */
145     this.landscape_ = new print_preview.ticket_items.Landscape(
146         this.appState_,
147         this.destinationStore_,
148         this.documentInfo_,
149         this.marginsType_,
150         this.customMargins_);
151
152     /**
153      * Header-footer ticket item.
154      * @type {!print_preview.ticket_items.HeaderFooter}
155      * @private
156      */
157     this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
158         this.appState_,
159         this.documentInfo_,
160         this.marginsType_,
161         this.customMargins_);
162
163     /**
164      * Fit-to-page ticket item.
165      * @type {!print_preview.ticket_items.FitToPage}
166      * @private
167      */
168     this.fitToPage_ = new print_preview.ticket_items.FitToPage(
169         this.documentInfo_, this.destinationStore_);
170
171     /**
172      * Print CSS backgrounds ticket item.
173      * @type {!print_preview.ticket_items.CssBackground}
174      * @private
175      */
176     this.cssBackground_ = new print_preview.ticket_items.CssBackground(
177         this.appState_, this.documentInfo_);
178
179     /**
180      * Print selection only ticket item.
181      * @type {!print_preview.ticket_items.SelectionOnly}
182      * @private
183      */
184     this.selectionOnly_ =
185         new print_preview.ticket_items.SelectionOnly(this.documentInfo_);
186
187     /**
188      * Vendor ticket items.
189      * @type {!print_preview.ticket_items.VendorItems}
190      * @private
191      */
192     this.vendorItems_ = new print_preview.ticket_items.VendorItems(
193         this.appState_, this.destinationStore_);
194
195     /**
196      * Keeps track of event listeners for the print ticket store.
197      * @type {!EventTracker}
198      * @private
199      */
200     this.tracker_ = new EventTracker();
201
202     /**
203      * Whether the print preview has been initialized.
204      * @type {boolean}
205      * @private
206      */
207     this.isInitialized_ = false;
208
209     this.addEventListeners_();
210   };
211
212   /**
213    * Event types dispatched by the print ticket store.
214    * @enum {string}
215    */
216   PrintTicketStore.EventType = {
217     CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
218     DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
219     INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE',
220     TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE'
221   };
222
223   PrintTicketStore.prototype = {
224     __proto__: cr.EventTarget.prototype,
225
226     /**
227      * Whether the print preview has been initialized.
228      * @type {boolean}
229      */
230     get isInitialized() {
231       return this.isInitialized_;
232     },
233
234     get collate() {
235       return this.collate_;
236     },
237
238     get color() {
239       return this.color_;
240     },
241
242     get copies() {
243       return this.copies_;
244     },
245
246     get cssBackground() {
247       return this.cssBackground_;
248     },
249
250     get customMargins() {
251       return this.customMargins_;
252     },
253
254     get dpi() {
255       return this.dpi_;
256     },
257
258     get duplex() {
259       return this.duplex_;
260     },
261
262     get fitToPage() {
263       return this.fitToPage_;
264     },
265
266     get headerFooter() {
267       return this.headerFooter_;
268     },
269
270     get mediaSize() {
271       return this.mediaSize_;
272     },
273
274     get landscape() {
275       return this.landscape_;
276     },
277
278     get marginsType() {
279       return this.marginsType_;
280     },
281
282     get pageRange() {
283       return this.pageRange_;
284     },
285
286     get selectionOnly() {
287       return this.selectionOnly_;
288     },
289
290     get vendorItems() {
291       return this.vendorItems_;
292     },
293
294     /**
295      * @return {!print_preview.MeasurementSystem} Measurement system of the
296      *     local system.
297      */
298     get measurementSystem() {
299       return this.measurementSystem_;
300     },
301
302     /**
303      * Initializes the print ticket store. Dispatches an INITIALIZE event.
304      * @param {string} thousandsDelimeter Delimeter of the thousands place.
305      * @param {string} decimalDelimeter Delimeter of the decimal point.
306      * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit
307      *     of the local measurement system.
308      * @param {boolean} selectionOnly Whether only selected content should be
309      *     printed.
310      */
311     init: function(
312         thousandsDelimeter, decimalDelimeter, unitType, selectionOnly) {
313       this.measurementSystem_.setSystem(thousandsDelimeter, decimalDelimeter,
314                                         unitType);
315       this.selectionOnly_.updateValue(selectionOnly);
316
317       // Initialize ticket with user's previous values.
318       if (this.appState_.hasField(
319           print_preview.AppState.Field.IS_COLOR_ENABLED)) {
320         this.color_.updateValue(
321             /** @type {!Object} */(this.appState_.getField(
322             print_preview.AppState.Field.IS_COLOR_ENABLED)));
323       }
324       if (this.appState_.hasField(print_preview.AppState.Field.DPI)) {
325         this.dpi_.updateValue(
326             /** @type {!Object} */(this.appState_.getField(
327             print_preview.AppState.Field.DPI)));
328       }
329       if (this.appState_.hasField(
330           print_preview.AppState.Field.IS_DUPLEX_ENABLED)) {
331         this.duplex_.updateValue(
332             /** @type {!Object} */(this.appState_.getField(
333             print_preview.AppState.Field.IS_DUPLEX_ENABLED)));
334       }
335       if (this.appState_.hasField(print_preview.AppState.Field.MEDIA_SIZE)) {
336         this.mediaSize_.updateValue(
337             /** @type {!Object} */(this.appState_.getField(
338             print_preview.AppState.Field.MEDIA_SIZE)));
339       }
340       if (this.appState_.hasField(
341           print_preview.AppState.Field.IS_LANDSCAPE_ENABLED)) {
342         this.landscape_.updateValue(
343             /** @type {!Object} */(this.appState_.getField(
344             print_preview.AppState.Field.IS_LANDSCAPE_ENABLED)));
345       }
346       // Initialize margins after landscape because landscape may reset margins.
347       if (this.appState_.hasField(print_preview.AppState.Field.MARGINS_TYPE)) {
348         this.marginsType_.updateValue(
349             /** @type {!Object} */(this.appState_.getField(
350             print_preview.AppState.Field.MARGINS_TYPE)));
351       }
352       if (this.appState_.hasField(
353           print_preview.AppState.Field.CUSTOM_MARGINS)) {
354         this.customMargins_.updateValue(
355             /** @type {!Object} */(this.appState_.getField(
356             print_preview.AppState.Field.CUSTOM_MARGINS)));
357       }
358       if (this.appState_.hasField(
359           print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED)) {
360         this.headerFooter_.updateValue(
361             /** @type {!Object} */(this.appState_.getField(
362             print_preview.AppState.Field.IS_HEADER_FOOTER_ENABLED)));
363       }
364       if (this.appState_.hasField(
365           print_preview.AppState.Field.IS_COLLATE_ENABLED)) {
366         this.collate_.updateValue(
367             /** @type {!Object} */(this.appState_.getField(
368             print_preview.AppState.Field.IS_COLLATE_ENABLED)));
369       }
370       if (this.appState_.hasField(
371           print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)) {
372         this.cssBackground_.updateValue(
373             /** @type {!Object} */(this.appState_.getField(
374             print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)));
375       }
376       if (this.appState_.hasField(
377           print_preview.AppState.Field.VENDOR_OPTIONS)) {
378         this.vendorItems_.updateValue(
379             /** @type {!Object.<string, string>} */(this.appState_.getField(
380             print_preview.AppState.Field.VENDOR_OPTIONS)));
381     }
382     },
383
384     /**
385      * @return {boolean} {@code true} if the stored print ticket is valid,
386      *     {@code false} otherwise.
387      */
388     isTicketValid: function() {
389       return this.isTicketValidForPreview() &&
390           (!this.copies_.isCapabilityAvailable() || this.copies_.isValid()) &&
391           (!this.pageRange_.isCapabilityAvailable() ||
392               this.pageRange_.isValid());
393     },
394
395     /** @return {boolean} Whether the ticket is valid for preview generation. */
396     isTicketValidForPreview: function() {
397       return (!this.marginsType_.isCapabilityAvailable() ||
398               !this.marginsType_.isValueEqual(
399                   print_preview.ticket_items.MarginsType.Value.CUSTOM) ||
400               this.customMargins_.isValid());
401     },
402
403     /**
404      * Creates an object that represents a Google Cloud Print print ticket.
405      * @param {!print_preview.Destination} destination Destination to print to.
406      * @return {!Object} Google Cloud Print print ticket.
407      */
408     createPrintTicket: function(destination) {
409       assert(!destination.isLocal || destination.isPrivet,
410              'Trying to create a Google Cloud Print print ticket for a local ' +
411                  ' non-privet destination');
412
413       assert(destination.capabilities,
414              'Trying to create a Google Cloud Print print ticket for a ' +
415                  'destination with no print capabilities');
416       var cjt = {
417         version: '1.0',
418         print: {}
419       };
420       if (this.collate.isCapabilityAvailable() && this.collate.isUserEdited()) {
421         cjt.print.collate = {collate: this.collate.getValue()};
422       }
423       if (this.color.isCapabilityAvailable() && this.color.isUserEdited()) {
424         var selectedOption = this.color.getSelectedOption();
425         if (!selectedOption) {
426           console.error('Could not find correct color option');
427         } else {
428           cjt.print.color = {type: selectedOption.type};
429           if (selectedOption.hasOwnProperty('vendor_id')) {
430             cjt.print.color.vendor_id = selectedOption.vendor_id;
431           }
432         }
433       }
434       if (this.copies.isCapabilityAvailable() && this.copies.isUserEdited()) {
435         cjt.print.copies = {copies: this.copies.getValueAsNumber()};
436       }
437       if (this.duplex.isCapabilityAvailable() && this.duplex.isUserEdited()) {
438         cjt.print.duplex =
439             {type: this.duplex.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
440       }
441       if (this.mediaSize.isCapabilityAvailable()) {
442         var value = this.mediaSize.getValue();
443         cjt.print.media_size = {
444           width_microns: value.width_microns,
445           height_microns: value.height_microns,
446           is_continuous_feed: value.is_continuous_feed,
447           vendor_id: value.vendor_id
448         };
449       }
450       if (!this.landscape.isCapabilityAvailable()) {
451         // In this case "orientation" option is hidden from user, so user can't
452         // adjust it for page content, see Landscape.isCapabilityAvailable().
453         // We can improve results if we set AUTO here.
454         if (this.landscape.hasOption('AUTO'))
455           cjt.print.page_orientation = { type: 'AUTO' };
456       } else if (this.landscape.isUserEdited()) {
457         cjt.print.page_orientation =
458             {type: this.landscape.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
459       }
460       if (this.dpi.isCapabilityAvailable()) {
461         var value = this.dpi.getValue();
462         cjt.print.dpi = {
463           horizontal_dpi: value.horizontal_dpi,
464           vertical_dpi: value.vertical_dpi,
465           vendor_id: value.vendor_id
466         };
467       }
468       if (this.vendorItems.isCapabilityAvailable() &&
469           this.vendorItems.isUserEdited()) {
470         var items = this.vendorItems.ticketItems;
471         cjt.print.vendor_ticket_item = [];
472         for (var itemId in items) {
473           if (items.hasOwnProperty(itemId)) {
474             cjt.print.vendor_ticket_item.push(
475                 {id: itemId, value: items[itemId]});
476           }
477         }
478       }
479       return JSON.stringify(cjt);
480     },
481
482     /**
483      * Adds event listeners for the print ticket store.
484      * @private
485      */
486     addEventListeners_: function() {
487       this.tracker_.add(
488           this.destinationStore_,
489           print_preview.DestinationStore.EventType.DESTINATION_SELECT,
490           this.onDestinationSelect_.bind(this));
491
492       this.tracker_.add(
493           this.destinationStore_,
494           print_preview.DestinationStore.EventType.
495               SELECTED_DESTINATION_CAPABILITIES_READY,
496           this.onSelectedDestinationCapabilitiesReady_.bind(this));
497
498       this.tracker_.add(
499           this.destinationStore_,
500           print_preview.DestinationStore.EventType.
501               CACHED_SELECTED_DESTINATION_INFO_READY,
502           this.onSelectedDestinationCapabilitiesReady_.bind(this));
503
504       // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
505       // events, the consumers of the print ticket store events should listen
506       // for the events from document info instead. Will move this when
507       // consumers are all migrated.
508       this.tracker_.add(
509           this.documentInfo_,
510           print_preview.DocumentInfo.EventType.CHANGE,
511           this.onDocumentInfoChange_.bind(this));
512     },
513
514     /**
515      * Called when the destination selected.
516      * @private
517      */
518     onDestinationSelect_: function() {
519       // Reset user selection for certain ticket items.
520       if (this.capabilitiesHolder_.get() != null) {
521         this.customMargins_.updateValue(null);
522         if (this.marginsType_.getValue() ==
523             print_preview.ticket_items.MarginsType.Value.CUSTOM) {
524           this.marginsType_.updateValue(
525               print_preview.ticket_items.MarginsType.Value.DEFAULT);
526         }
527         this.vendorItems_.updateValue({});
528       }
529     },
530
531     /**
532      * Called when the capabilities of the selected destination are ready.
533      * @private
534      */
535     onSelectedDestinationCapabilitiesReady_: function() {
536       var caps = assert(
537           this.destinationStore_.selectedDestination.capabilities);
538       var isFirstUpdate = this.capabilitiesHolder_.get() == null;
539       this.capabilitiesHolder_.set(caps);
540       if (isFirstUpdate) {
541         this.isInitialized_ = true;
542         cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
543       } else {
544         cr.dispatchSimpleEvent(
545             this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
546       }
547     },
548
549     /**
550      * Called when document data model has changed. Dispatches a print ticket
551      * store event.
552      * @private
553      */
554     onDocumentInfoChange_: function() {
555       cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
556     },
557   };
558
559   // Export
560   return {
561     PrintTicketStore: PrintTicketStore
562   };
563 });