OLD | NEW |
---|---|
(Empty) | |
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 // TODO Optimize this to not dispatch CHANGE events when nothing really changed. | |
6 | |
7 cr.define('print_preview', function() { | |
8 'use strict'; | |
9 | |
10 /** | |
11 * Storage of the print ticket and document statistics. | |
12 * | |
13 * Dispatches events when the contents of the print ticket or document | |
14 * statistics change. Also handles validation of the print ticket against | |
15 * destination capabilities and against the document. | |
16 * | |
17 * @constructor | |
18 * @extends {cr.EventTarget} | |
19 */ | |
20 function PrintTicketStore() { | |
21 cr.EventTarget.call(this); | |
22 | |
23 /** | |
24 * Information about the document to print. | |
25 * @type {DocumentInfo} | |
26 * @private | |
27 */ | |
28 this.documentInfo_ = new DocumentInfo(); | |
29 | |
30 /** | |
31 * Printing capabilities of Chromium and the currently selected destination. | |
32 * @type {print_preview.ChromiumCapabilities} | |
33 * @private | |
34 */ | |
35 this.capabilities_ = null; | |
36 | |
37 /** | |
38 * Print ticket information. Used to print and generate previews. | |
39 * @type {print_preview.ChromiumPrintTicket} | |
40 * @private | |
41 */ | |
42 this.ticket_ = null; | |
43 | |
44 /** | |
45 * Current measurement system. Used to work with margin measurements. | |
46 * @type {print_preview.MeasurementSystem} | |
47 * @private | |
48 */ | |
49 this.measurementSystem_ = null; | |
50 | |
51 /** | |
52 * Cached page number set. Used to not have to parse page range string | |
53 * everytime its requested. | |
54 * @type {print_preview.PageNumberSet} | |
55 * @private | |
56 */ | |
57 this.pageNumberSet_ = null; | |
58 }; | |
59 | |
60 /** | |
61 * Events dispatched by the print ticket store. | |
62 * @enum {string} | |
63 */ | |
64 PrintTicketStore.Event = { | |
65 CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE', | |
66 DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE', | |
67 INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE', | |
68 TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE' | |
69 }; | |
70 | |
71 /** | |
72 * Minimum size in points the margins need to be to fit a header or footer. | |
73 * TODO: Figure out someway to actually calculate this value. | |
74 * @type {number} | |
75 * @const | |
76 * @private | |
77 */ | |
78 PrintTicketStore.MINIMUM_HEADER_FOOTER_HEIGHT_ = 0; | |
79 | |
80 PrintTicketStore.prototype = { | |
81 __proto__: cr.EventTarget.prototype, | |
82 | |
83 /** @override */ | |
84 dispatchEvent: function(evt) { | |
85 // TODO REMOVE ME | |
86 log(evt.type); | |
87 cr.EventTarget.prototype.dispatchEvent.call(this, evt); | |
88 }, | |
89 | |
90 /** | |
91 * @return {boolean} Whether the print ticket store has been initialized. | |
92 */ | |
93 get isInitialized() { | |
94 return !!this.ticket_; | |
95 }, | |
96 | |
97 /** @return {boolean} Whether the document is modifiable. */ | |
98 get isDocumentModifiable() { | |
99 return this.documentInfo_.isModifiable; | |
100 }, | |
101 | |
102 /** @return {number} Number of pages in the document. */ | |
103 get pageCount() { | |
104 return this.documentInfo_.pageCount; | |
105 }, | |
106 | |
107 /** | |
108 * @param {number} pageCount New number of pages in the document. | |
109 * Dispatches a DOCUMENT_CHANGE event if the value changes. | |
110 */ | |
111 updatePageCount: function(pageCount) { | |
112 if (this.documentInfo_.pageCount != pageCount) { | |
113 this.documentInfo_.pageCount = pageCount; | |
114 this.pageNumberSet_ = null; | |
115 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.DOCUMENT_CHANGE); | |
116 } | |
117 }, | |
118 | |
119 /** | |
120 * @return {!print_preview.PrintableArea} Printable area of the document in | |
121 * points. | |
122 */ | |
123 get printableArea() { | |
124 return this.documentInfo_.printableArea; | |
125 }, | |
126 | |
127 /** | |
128 * @param {!print_preview.PrintableArea} printableArea New printable area of | |
129 * the document in points. Dispatches a DOCUMENT_CHANGE event if the | |
130 * value changes. | |
131 */ | |
132 updatePrintableArea: function(printableArea) { | |
133 if (!this.documentInfo_.printableArea.equals(printableArea)) { | |
134 log('PrintableArea: ' + printableArea.origin.x + ' ' + | |
135 printableArea.origin.y + ' ' + printableArea.size.width + ' ' + | |
136 printableArea.size.height); | |
137 this.documentInfo_.printableArea = printableArea; | |
138 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.DOCUMENT_CHANGE); | |
139 } | |
140 }, | |
141 | |
142 /** @return {!print_preview.Size} Size of the document in points. */ | |
143 get pageSize() { | |
144 return this.documentInfo_.pageSize; | |
145 }, | |
146 | |
147 /** | |
148 * @param {!print_preview.Size} pageSize New size of the document. | |
149 * Dispatches a DOCUMENT_CHANGE event if the value changes. | |
150 */ | |
151 updatePageSize: function(pageSize) { | |
152 if (!this.documentInfo_.pageSize.equals(pageSize)) { | |
153 log('Updating page size to: ' + pageSize.width + ' ' + pageSize.height); | |
154 this.documentInfo_.pageSize = pageSize; | |
155 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.DOCUMENT_CHANGE); | |
156 } | |
157 }, | |
158 | |
159 /** | |
160 * @return {!print_preview.MeasurementSystem} Measurement system of the | |
161 * local system. | |
162 */ | |
163 get measurementSystem() { | |
164 if (!this.isInitialized) { | |
165 throw Error( | |
166 'Trying to get measurement system before ticket is initialized'); | |
167 } | |
168 return /** @type {!print_preview.MeasurementSystem} */ (this. | |
169 measurementSystem_); | |
170 }, | |
171 | |
172 /** | |
173 * Initializes the print ticket store. Dispatches an INITIALIZE event. | |
174 * @param {boolean} isDocumentModifiable Whether the document to print is | |
175 * modifiable (i.e. can be re-flowed by Chromium). | |
176 * @param {boolean} isDuplexEnabled Previous duplex setting. | |
177 * @param {boolean} isHeaderFooterEnabled Previous header-footer setting. | |
178 * @param {print_preview.Margins.Type} marginsType Previous margins type. | |
179 * @param {print_preview.Margins} customMargins Initial custom margins. | |
180 * @param {!print_preview.MeasurementSystem} measurementSystem Measurement | |
181 * system of the local system. | |
182 */ | |
183 initialize: function( | |
184 isDocumentModifiable, | |
185 isDuplexEnabled, | |
186 isHeaderFooterEnabled, | |
187 marginsType, | |
188 customMargins, | |
189 measurementSystem) { | |
190 | |
191 this.documentInfo_.isModifiable = isDocumentModifiable; | |
192 | |
193 // Create capabilities that can be handled by Chromium before any | |
194 // particular print destination is selected. | |
195 this.capabilities_ = new print_preview.ChromiumCapabilities( | |
196 true /*hasCopiesCapability*/, | |
197 '1' /*defaultCopiesStr*/, | |
198 true /*hasCollateCapability*/, | |
199 true /*defaultIsCollateEnabled*/, | |
200 true /*hasDuplexCapability*/, | |
201 true /*defaultIsDuplexEnabled*/, | |
202 true /*hasOrientationCapability*/, | |
203 false /*defaultIsLandscapeEnabled*/, | |
204 true /*hasColorCapability*/, | |
205 true /*defaultIsColorEnabled*/); | |
206 | |
207 // Initialize ticket with user's previous values. | |
208 this.ticket_ = new print_preview.ChromiumPrintTicket(this.capabilities_); | |
209 this.ticket_.isDuplexEnabled = isDuplexEnabled; | |
210 this.ticket_.marginsType = marginsType; | |
211 this.ticket_.customMargins = customMargins; | |
212 this.ticket_.isHeaderFooterEnabled = isHeaderFooterEnabled; | |
213 | |
214 // Initialize measurement system. | |
215 this.measurementSystem_ = measurementSystem; | |
216 | |
217 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.INITIALIZE); | |
218 }, | |
219 | |
220 /** | |
221 * Updates the capabilities of the destination the print ticket is for. | |
222 * Dispatches a CAPABILITIES_CHANGE event. | |
223 * @param {!print_preview.ChromiumCapabilities} caps New capabilities. | |
224 */ | |
225 updateDestinationCapabilities: function(caps) { | |
226 this.capabilities_ = caps; | |
227 this.ticket_.capabilities = caps; | |
228 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.CAPABILITIES_CHANGE); | |
229 }, | |
230 | |
231 /** @return {boolean} Whether the ticket store has the copies capability. */ | |
232 hasCopiesCapability: function() { | |
233 return this.capabilities_.hasCopiesCapability; | |
234 }, | |
235 | |
236 /** | |
237 * @return {boolean} Whether the string representation of the copies value | |
238 * currently in the ticket store is valid. | |
239 */ | |
240 isCopiesValid: function() { | |
241 return this.isCopiesValidForValue(this.ticket_.copiesStr); | |
242 }, | |
243 | |
244 /** | |
245 * @param {string} value String representation of the number of print | |
246 * copies. | |
247 * @return {boolean} Whether the given value is valid--an integer in the | |
248 * range [1, 999]. | |
249 */ | |
250 isCopiesValidForValue: function(value) { | |
251 if (/[^\d]+/.test(value)) { | |
252 return false; | |
253 } | |
254 var copies = parseInt(value); | |
255 if (copies > 999 || copies < 1) { | |
256 return false; | |
257 } | |
258 return true; | |
259 }, | |
260 | |
261 /** @return {number} Number of copies to print. */ | |
262 getCopies: function() { | |
263 return parseInt(this.ticket_.copiesStr); | |
264 }, | |
265 | |
266 /** | |
267 * @return {string} String representation of the number of copies to print. | |
268 */ | |
269 getCopiesStr: function() { | |
270 return this.ticket_.copiesStr; | |
271 }, | |
272 | |
273 /** | |
274 * Updates the string representation of the number of copies to print. | |
275 * Dispatches a TICKET_CHANGE event if the string value has changed. | |
276 * @param {string} New string representation of the number of copies to | |
277 * print. | |
278 */ | |
279 updateCopies: function(copies) { | |
280 if (!this.hasCopiesCapability()) { | |
281 throw Error( | |
282 'Updating copies capability but destination does not have a ' + | |
283 'copies capability'); | |
284 } | |
285 if (this.ticket_.copiesStr != copies) { | |
286 this.ticket_.copiesStr = copies; | |
287 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
288 } | |
289 }, | |
290 | |
291 /** @return {boolean} Whether the ticket store has a collate capability. */ | |
292 hasCollateCapability: function() { | |
293 return this.capabilities_.hasCollateCapability; | |
294 }, | |
295 | |
296 /** @return {boolean} Whether collate is enabled. */ | |
297 isCollateEnabled: function() { | |
298 return this.ticket_.isCollateEnabled; | |
299 }, | |
300 | |
301 /** | |
302 * Updates whether collate is enabled. Dispatches a TICKET_CHANGE event if | |
303 * collate has changed. | |
304 * @param {boolean} isCollate Whether collate is enabled. | |
305 */ | |
306 updateCollate: function(isCollate) { | |
307 if (!this.hasCollateCapability()) { | |
308 throw Error( | |
309 'Updating collate capability but destination does not have a ' + | |
310 'collate capability'); | |
311 } | |
312 if (this.ticket_.isCollateEnabled != isCollate) { | |
313 this.ticket_.isCollateEnabled = isCollate; | |
314 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
315 } | |
316 }, | |
317 | |
318 /** | |
319 * @return {boolean} Whether the ticket store has color printing capability. | |
320 */ | |
321 hasColorCapability: function() { | |
322 return this.capabilities_.hasColorCapability; | |
323 }, | |
324 | |
325 /** | |
326 * @return {boolean} Whether color printing is enabled. | |
327 */ | |
328 isColorEnabled: function() { | |
329 return this.ticket_.isColorEnabled; | |
330 }, | |
331 | |
332 /** | |
333 * Updates whether color printing is enabled. Dispatches a TICKET_CHANGE if | |
334 * color has changed. | |
335 * @param {boolean} isColor Whether the color printing is enabled. | |
336 */ | |
337 updateColor: function(isColor) { | |
338 if (!this.hasColorCapability()) { | |
339 throw Error( | |
340 'Updating color capability but destination does not have a color ' + | |
341 'capability'); | |
342 } | |
343 if (this.ticket_.isColorEnabled != isColor) { | |
344 this.ticket_.isColorEnabled = isColor; | |
345 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
346 } | |
347 }, | |
348 | |
349 /** @return {boolean} Whether the header-footer capability is available. */ | |
350 hasHeaderFooterCapability: function() { | |
351 // Checks the printable area and updates the visibility of header footer | |
352 // option based on the selected margins. | |
353 if (!this.documentInfo_.isModifiable || | |
354 this.ticket_.marginsType == print_preview.Margins.Type.NO_MARGINS) { | |
355 return false; | |
356 } | |
357 if (this.ticket_.marginsType == print_preview.Margins.Type.CUSTOM) { | |
358 var margins = this.ticket_.customMargins; | |
359 // TODO This condition only checks if the margin is non-zero. It should | |
360 // check whether the margin is large enough to render the header-footer. | |
361 var availableTopMargin = this.documentInfo_.printableArea.origin.y - | |
362 PrintTicketStore.MINIMUM_HEADER_FOOTER_HEIGHT_; | |
363 var availbleBottomMargin = this.documentInfo_.pageSize.height - | |
364 this.documentInfo_.printableArea.origin.y - | |
365 this.documentInfo_.printableArea.size.height - | |
366 PrintTicketStore.MINIMUM_HEADER_FOOTER_HEIGHT_; | |
367 if (margins.top < availableTopMargin || | |
368 margins.bottom < availbleBottomMargin) { | |
369 return false; | |
370 } | |
371 } | |
372 return true; | |
373 }, | |
374 | |
375 /** @return {boolean} Whether the header-footer setting is enabled. */ | |
376 isHeaderFooterEnabled: function() { | |
377 return this.ticket_.isHeaderFooterEnabled; | |
378 }, | |
379 | |
380 /** | |
381 * Updates the whether the header-footer setting is enabled. Dispatches a | |
382 * TICKET_CHANGE event if the setting changed. | |
383 * @param {boolean} isHeaderFooterEnabled Whether the header-footer setting | |
384 * is enabled. | |
385 */ | |
386 updateHeaderFooter: function(isHeaderFooterEnabled) { | |
387 if (!this.hasHeaderFooterCapability()) { | |
388 throw Error( | |
389 'Updating header-footer capability but destination does not have ' + | |
390 'a header-footer capability'); | |
391 } | |
392 if (this.ticket_.isHeaderFooterEnabled != isHeaderFooterEnabled) { | |
393 this.ticket_.isHeaderFooterEnabled = isHeaderFooterEnabled; | |
394 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
395 } | |
396 }, | |
397 | |
398 /** | |
399 * @return {boolean} Whether the page orientation capability is available. | |
400 */ | |
401 hasOrientationCapability: function() { | |
402 // TODO Technically, the print destination can still change the | |
403 // orientation of the print out (at least for cloud printers). But the | |
404 // preview wouldn't update in the case where the document is not | |
405 // modifiable so this is a bad user experience. | |
406 return this.documentInfo_.isModifiable; | |
407 }, | |
408 | |
409 /** | |
410 * @return {boolean} Whether the document should be printed in landscape. | |
411 */ | |
412 isLandscapeEnabled: function() { | |
413 return this.ticket_.isLandscapeEnabled; | |
414 }, | |
415 | |
416 /** | |
417 * Updates whether the document should be printed in landscape. Dispatches | |
418 * a TICKET_CHANGE event if the setting changes. | |
419 * @param {boolean} isLandscape Whether the document should be printed in | |
420 * landscape. | |
421 */ | |
422 updateOrientation: function(isLandscape) { | |
423 if (!this.hasOrientationCapability()) { | |
424 throw Error( | |
425 'Updating orientation capability but destination does not have ' + | |
426 'an orientation capability'); | |
427 } | |
428 if (this.ticket_.isLandscapeEnabled != isLandscape) { | |
429 this.ticket_.isLandscapeEnabled = isLandscape; | |
430 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
431 } | |
432 }, | |
433 | |
434 /** @return {boolean} Whether the duplexing capability is available. */ | |
435 hasDuplexCapability: function() { | |
436 return this.capabilities_.hasDuplexCapability; | |
437 }, | |
438 | |
439 /** @return {boolean} Whether the document should be printed in duplex. */ | |
440 isDuplexEnabled: function() { | |
441 return this.ticket_.isDuplexEnabled; | |
442 }, | |
443 | |
444 /** | |
445 * Updates the duplexing setting. Dispatches a TICKET_CHANGE event if the | |
446 * value changes. | |
447 * @param {boolean} isDuplex Whether the document should be printed in | |
448 * duplex. | |
449 */ | |
450 updateDuplex: function(isDuplex) { | |
451 if (!this.hasDuplexCapability()) { | |
452 throw Error( | |
453 'Updating duplex capability but destination does not have a ' + | |
454 'duplex capability'); | |
455 } | |
456 if (this.ticket_.isDuplexEnabled != isDuplex) { | |
457 this.ticket_.isDuplexEnabled = isDuplex; | |
458 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
459 } | |
460 }, | |
461 | |
462 /** @return {boolean} Whether the margins capability is available. */ | |
463 hasMarginsCapability: function() { | |
464 return this.documentInfo_.isModifiable; | |
465 }, | |
466 | |
467 /** @return {print_preview.Margins.Type} Type of predefined margins. */ | |
468 getMarginsType: function() { | |
469 return this.ticket_.marginsType; | |
470 }, | |
471 | |
472 /** | |
473 * Updates the type of predefined margins. Dispatches a TICKET_CHANGE event | |
474 * if the margins type changes. | |
475 * @param {print_preview.Margins.Type} marginsType Type of predefined | |
476 * margins. | |
477 */ | |
478 updateMarginsType: function(marginsType) { | |
479 if (!this.hasMarginsCapability()) { | |
480 throw Error( | |
481 'Updating margins capability but destination does not have a ' + | |
482 'margin capability'); | |
483 } | |
484 if (this.ticket_.marginsType != marginsType) { | |
485 this.ticket_.marginsType = marginsType; | |
486 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
487 } | |
488 }, | |
489 | |
490 /** @return {print_preview.Margins} Custom margins of the document. */ | |
491 getCustomMargins: function() { | |
492 return this.ticket_.customMargins; | |
493 }, | |
494 | |
495 // TODO Store the custom margins as a string so that validation can be done | |
496 // in the PrintTicketStore. | |
497 | |
498 /** | |
499 * Updates the custom margins of the document. Dispatches a TICKET_CHANGE | |
500 * event if the margins have changed. | |
501 * @param {print_preview.Margins} margins New document page margins. | |
502 */ | |
503 updateCustomMargins: function(margins) { | |
504 if (!this.hasMarginsCapability()) { | |
505 throw Error( | |
506 'Updating margins capability but destination does not have a ' + | |
507 'margin capability'); | |
508 } | |
509 if (!margins.equals(this.ticket_.customMargins)) { | |
510 this.ticket_.customMargins = margins; | |
511 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
512 } | |
513 }, | |
514 | |
515 /** @return {boolean} Whether the page range capability is available. */ | |
516 hasPageRangeCapability: function() { | |
517 // Page range can always be manipulated by Chromium. | |
518 return true; | |
519 }, | |
520 | |
521 /** | |
522 * @return {boolean} Whether the current page range string is defines a | |
523 * valid page number set. | |
524 */ | |
525 isPageRangeValid: function() { | |
526 var pageRangeStr = this.ticket_.pageRangeStr; | |
527 return pageRangeStr == '' || | |
528 isPageRangeTextValid(pageRangeStr, this.documentInfo_.pageCount); | |
529 }, | |
530 | |
531 /** @return {string} String representation of the page range. */ | |
532 getPageRangeStr: function() { | |
533 return this.ticket_.pageRangeStr; | |
534 }, | |
535 | |
536 /** | |
537 * @return {!print_preview.PageNumberSet} Page number set specified by the | |
538 * string representation of the page range string. | |
539 */ | |
540 getPageNumberSet: function() { | |
541 if (this.pageNumberSet_ == null) { | |
542 this.pageNumberSet_ = print_preview.PageNumberSet.parse( | |
543 this.ticket_.pageRangeStr, this.documentInfo_.pageCount); | |
544 } | |
545 return this.pageNumberSet_; | |
546 }, | |
547 | |
548 /** | |
549 * Updates the page range string. Dispatches a TICKET_CHANGE if the string | |
550 * changed. | |
551 * @param {string} pageRangeStr New page range string. | |
552 */ | |
553 updatePageRange: function(pageRangeStr) { | |
554 if (this.ticket_.pageRangeStr != pageRangeStr) { | |
555 this.ticket_.pageRangeStr = pageRangeStr; | |
556 this.pageNumberSet_ = null; | |
557 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); | |
558 } | |
559 }, | |
560 | |
561 /** | |
562 * @return {boolean} {@code true} if the stored print ticket is valid, | |
563 * {@code false} otherwise. | |
564 */ | |
565 isTicketValid: function() { | |
566 // TODO Validate custom margins | |
567 return this.isCopiesValid() && this.isPageRangeValid(); | |
568 } | |
569 }; | |
570 | |
571 /** | |
572 * Object which contains information related to the document to print. | |
573 * | |
574 * @constructor | |
575 */ | |
576 function DocumentInfo() { | |
577 /** | |
578 * Whether the document to print is modifiable (i.e. can be reflowed). | |
579 * @type {boolean} | |
580 */ | |
581 this.isModifiable = true; | |
582 | |
583 /** | |
584 * Number of pages in the document to print. | |
585 * @type {number} | |
586 */ | |
587 this.pageCount = 1; | |
588 | |
589 /** | |
590 * Size of the pages of the document. | |
591 * @type {!print_preview.Size} | |
592 */ | |
593 this.pageSize = new print_preview.Size(612, 792); | |
dpapad
2012/04/24 01:24:56
Where do these values come from?
Robert Toscano
2012/04/24 22:29:56
8.5"x11" paper size. I've move the initialization
| |
594 | |
595 /** | |
596 * Printable area of the document. | |
597 * @type {!print_preview.PrintableArea} | |
598 */ | |
599 this.printableArea = new print_preview.PrintableArea( | |
600 new print_preview.Coordinate2d(0, 0), | |
601 this.pageSize); | |
602 }; | |
603 | |
604 // Export | |
605 return { | |
606 PrintTicketStore: PrintTicketStore | |
607 }; | |
608 }); | |
OLD | NEW |