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 * @param {print_preview.DestinationStore!} destinationStore Destination store |
| 18 * used to get the selected destination. |
| 19 * @constructor |
| 20 * @extends {cr.EventTarget} |
| 21 */ |
| 22 function PrintTicketStore(destinationStore) { |
| 23 cr.EventTarget.call(this); |
| 24 |
| 25 /** |
| 26 * Destination store used to get the selected destination. |
| 27 * @type {print_preview.DestinationStore!} |
| 28 * @private |
| 29 */ |
| 30 this.destinationStore_ = destinationStore; |
| 31 |
| 32 /** |
| 33 * Information about the document to print. |
| 34 * @type {DocumentInfo} |
| 35 * @private |
| 36 */ |
| 37 this.documentInfo_ = new DocumentInfo(); |
| 38 |
| 39 /** |
| 40 * Cached page number set. Used to not have to parse page range string |
| 41 * everytime its requested. |
| 42 * @type {print_preview.PageNumberSet} |
| 43 * @private |
| 44 */ |
| 45 this.pageNumberSet_ = null; |
| 46 |
| 47 /** |
| 48 * Printing capabilities of Chromium and the currently selected destination. |
| 49 * @type {print_preview.ChromiumCapabilities} |
| 50 * @private |
| 51 */ |
| 52 this.capabilities_ = null; |
| 53 |
| 54 /** |
| 55 * Print ticket information. Used to print and generate previews. |
| 56 * @type {print_preview.ChromiumPrintTicket} |
| 57 * @private |
| 58 */ |
| 59 this.ticket_ = null; |
| 60 |
| 61 /** |
| 62 * Current measurement system. Used to work with margin measurements. |
| 63 * @type {print_preview.MeasurementSystem} |
| 64 * @private |
| 65 */ |
| 66 this.measurementSystem_ = null; |
| 67 }; |
| 68 |
| 69 /** |
| 70 * Events dispatched by the print ticket store. |
| 71 * @enum {string} |
| 72 */ |
| 73 PrintTicketStore.Event = { |
| 74 CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE', |
| 75 DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE', |
| 76 INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE', |
| 77 TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE', |
| 78 }; |
| 79 |
| 80 PrintTicketStore.prototype = { |
| 81 __proto__: cr.EventTarget.prototype, |
| 82 |
| 83 get isDocumentModifiable() { |
| 84 return this.documentInfo_.isModifiable; |
| 85 }, |
| 86 |
| 87 get pageCount() { |
| 88 return this.documentInfo_.pageCount; |
| 89 }, |
| 90 |
| 91 /** @override */ |
| 92 dispatchEvent: function(evt) { |
| 93 // TODO REMOVE ME |
| 94 log(evt.type); |
| 95 cr.EventTarget.prototype.dispatchEvent.call(this, evt); |
| 96 }, |
| 97 |
| 98 /** |
| 99 * Initializes the print ticket store. |
| 100 * @param {boolean} isDocumentModifiable Whether the document to print is |
| 101 * modifiable (i.e. can be re-flowed by Chromium). |
| 102 * @param {boolean} isDuplexEnabled Previous duplex setting. |
| 103 * @param {boolean} isHeaderFooterEnabled Previous header-footer setting. |
| 104 * @param {print_preview.MarginType} marginType Previous margin type. |
| 105 */ |
| 106 initialize: function( |
| 107 isDocumentModifiable, |
| 108 isDuplexEnabled, |
| 109 isHeaderFooterEnabled, |
| 110 marginType, |
| 111 customMarginsInfo, |
| 112 numberFormat, |
| 113 measurementSystem) { |
| 114 |
| 115 this.documentInfo_.isModifiable = isDocumentModifiable; |
| 116 |
| 117 // Create capabilities that can be handled by Chromium. |
| 118 this.capabilities_ = new print_preview.ChromiumCapabilities(); |
| 119 this.capabilities_.hasPageRangeCapability = true; |
| 120 this.capabilities_.hasColorCapability = true; |
| 121 this.capabilities_.hasCopiesCapability = true; |
| 122 this.capabilities_.hasCollateCapability = true; |
| 123 this.capabilities_.hasDuplexCapability = true; |
| 124 if (isDocumentModifiable) { |
| 125 this.capabilities_.hasOrientationCapability = true; |
| 126 this.capabilities_.hasMarginsCapability = true; |
| 127 this.capabilities_.hasHeaderFooterCapability = true; |
| 128 } |
| 129 |
| 130 var numberFormatSymbols = |
| 131 print_preview.MeasurementSystem.parseNumberFormat(numberFormat); |
| 132 this.measurementSystem_ = new print_preview.MeasurementSystem( |
| 133 numberFormatSymbols[0], numberFormatSymbols[1], measurementSystem); |
| 134 |
| 135 marginType = marginType != null ? |
| 136 marginType : print_preview.Margins.Type.DEFAULT; |
| 137 var customMargins = null; |
| 138 if (marginType == print_preview.Margins.Type.CUSTOM) { |
| 139 if (customMarginsInfo != null) { |
| 140 customMargins = new print_preview.Margins( |
| 141 customMarginsInfo[0], customMarginsInfo[1], |
| 142 customMarginsInfo[2], customMarginsInfo[3], |
| 143 this.measurementSystem_); |
| 144 } else { |
| 145 marginType = print_preview.Margins.Type.DEFAULT; |
| 146 } |
| 147 } |
| 148 |
| 149 this.ticket_ = new print_preview.ChromiumPrintTicket(this.capabilities_); |
| 150 this.ticket_.isDuplexEnabled = isDuplexEnabled; |
| 151 this.ticket_.marginType = marginType; |
| 152 this.ticket_.pageRangeStr = ''; |
| 153 if (marginType == print_preview.Margins.Type.CUSTOM) { |
| 154 // TODO this.ticket_.customMargins = customMargins; |
| 155 } |
| 156 this.ticket_.isHeaderFooterEnabled = isHeaderFooterEnabled; |
| 157 |
| 158 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.INITIALIZE); |
| 159 }, |
| 160 |
| 161 createTicketForPreviewGenerator: function() { |
| 162 if (!this.isTicketValid()) { |
| 163 throw Error( |
| 164 'Requesting ticket for preview generator when ticket is not valid'); |
| 165 } |
| 166 |
| 167 var settings = { |
| 168 'pageRange': [], // TODO this.ticket_.pageRangeSequence, |
| 169 'landscape': this.ticket_.isLandscapeEnabled, |
| 170 'color': this.ticket_.colorMode, |
| 171 'headerFooterEnabled': this.ticket_.isHeaderFooterEnabled, |
| 172 'marginsType': this.ticket_.marginType, |
| 173 |
| 174 // This field seems to issue a reloadPreviewPages call when true. |
| 175 'generateDraftData': true, // TODO What should this value be? |
| 176 |
| 177 // NOTE: Even though the following fields don't directly relate to the |
| 178 // preview, they still need to be included. |
| 179 'duplex': this.ticket_.duplexMode, |
| 180 'copies': this.getCopies(), |
| 181 'collate': this.ticket_.isCollateEnabled, |
| 182 'previewModifiable': this.documentInfo_.isModifiable, |
| 183 'printToPDF': false, |
| 184 'printWithCloudPrint': false, |
| 185 'deviceName': 'foo', |
| 186 'cloudPrintID': 'foo' |
| 187 }; |
| 188 |
| 189 if (this.ticket_.marginType == print_preview.Margins.Type.CUSTOM) { |
| 190 // TODO settings['marginsCustom'] = |
| 191 } |
| 192 |
| 193 return settings; |
| 194 }, |
| 195 |
| 196 updateDestinationCapabilities: function(caps) { |
| 197 if (this.capabilities_.hasPageRangeCapability = |
| 198 caps.hasPageRangeCapability) { |
| 199 this.capabilities_.defaultPageRangeStr = caps.defaultPageRangeStr; |
| 200 } |
| 201 if (this.capabilities_.hasColorCapability = caps.hasColorCapability) { |
| 202 this.capabilities_.defaultIsColorEnabled = caps.defaultIsColorEnabled; |
| 203 } |
| 204 if (this.capabilities_.hasCopiesCapability = caps.hasCopiesCapability) { |
| 205 this.capabilities_.defaultCopiesStr = caps.defaultCopiesStr; |
| 206 } |
| 207 if (this.capabilities_.hasCollateCapability = caps.hasCollateCapability) { |
| 208 this.capabilities_.defaultIsCollateEnabled = |
| 209 caps.defaultIsCollateEnabled; |
| 210 } |
| 211 if (this.capabilities_.hasDuplexCapability = caps.hasDuplexCapability) { |
| 212 this.capabilities_.defaultIsDuplexEnabled = caps.defaultIsDuplexEnabled; |
| 213 } |
| 214 if (this.documentInfo_.isModifiable) { |
| 215 if (this.capabilities_.hasOrientationCapability = |
| 216 caps.hasOrientationCapability) { |
| 217 this.capabilities_.defaultIsLandscapeEnabled = |
| 218 caps.defaultIsLandscapeEnabled; |
| 219 } |
| 220 if (this.capabilities_.hasMarginsCapability = |
| 221 caps.hasMarginsCapability) { |
| 222 this.capabilities_.defaultMarginType = caps.defaultMarginType; |
| 223 } |
| 224 if (this.capabilities_.hasHeaderFooterCapability = |
| 225 caps.hasHeaderFooterCapability) { |
| 226 this.capabilities_.defaultIsHeaderFooterEnabled = |
| 227 caps.defaultIsHeaderFooterEnabled; |
| 228 } |
| 229 } |
| 230 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.CAPABILITIES_CHANGE); |
| 231 }, |
| 232 |
| 233 updatePageCount: function(pageCount) { |
| 234 if (this.documentInfo_.pageCount != pageCount) { |
| 235 log('print_preview.PrintTicketStore.updatePageCount -- updating count to
' + pageCount); |
| 236 this.documentInfo_.pageCount = pageCount; |
| 237 this.pageNumberSet_ = null; |
| 238 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.DOCUMENT_CHANGE); |
| 239 } |
| 240 }, |
| 241 |
| 242 hasCopiesCapability: function() { |
| 243 return this.capabilities_.hasCopiesCapability; |
| 244 }, |
| 245 |
| 246 isCopiesValid: function() { |
| 247 return this.isCopiesValidForValue(this.getCopiesStr()); |
| 248 }, |
| 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 getCopies: function() { |
| 262 return parseInt(this.getCopiesStr()); |
| 263 }, |
| 264 |
| 265 getCopiesStr: function() { |
| 266 return this.ticket_.copiesStr; |
| 267 }, |
| 268 |
| 269 updateCopies: function(copies) { |
| 270 if (!this.capabilities_.hasCopiesCapability) { |
| 271 throw Error( |
| 272 'Updating copies capability but destination does not have a ' + |
| 273 'copies capability'); |
| 274 } |
| 275 if (this.ticket_.copiesStr != copies) { |
| 276 this.ticket_.copiesStr = copies; |
| 277 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 278 } |
| 279 }, |
| 280 |
| 281 hasCollateCapability: function() { |
| 282 return this.capabilities_.hasCollateCapability; |
| 283 }, |
| 284 |
| 285 isCollateEnabled: function() { |
| 286 return this.ticket_.isCollateEnabled; |
| 287 }, |
| 288 |
| 289 updateCollate: function(isCollate) { |
| 290 if (!this.capabilities_.hasCollateCapability) { |
| 291 throw Error( |
| 292 'Updating collate capability but destination does not have a ' + |
| 293 'collate capability'); |
| 294 } |
| 295 if (this.ticket_.isCollateEnabled != isCollate) { |
| 296 this.ticket_.isCollateEnabled = isCollate; |
| 297 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 298 } |
| 299 }, |
| 300 |
| 301 hasColorCapability: function() { |
| 302 return this.capabilities_.hasColorCapability; |
| 303 }, |
| 304 |
| 305 isColorEnabled: function() { |
| 306 return this.ticket_.isColorEnabled; |
| 307 }, |
| 308 |
| 309 /** |
| 310 * @param {boolean} isColor Whether the color option is enabled. |
| 311 */ |
| 312 updateColor: function(isColor) { |
| 313 if (!this.capabilities_.hasColorCapability) { |
| 314 throw Error( |
| 315 'Updating color capability but destination does not have a color ' + |
| 316 'capability'); |
| 317 } |
| 318 if (this.ticket_.isColorEnabled != isColor) { |
| 319 this.ticket_.isColorEnabled = isColor; |
| 320 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 321 } |
| 322 }, |
| 323 |
| 324 /** @return {boolean} Whether the header-footer capability is available. */ |
| 325 hasHeaderFooterCapability: function() { |
| 326 if (!this.capabilities_.hasHeaderFooterCapability) { |
| 327 return false; |
| 328 } |
| 329 // Checks the printable area and updates the visibility of header footer |
| 330 // option based on the selected margins. |
| 331 return true; |
| 332 // TODO |
| 333 // var headerFooterApplies = true; |
| 334 // if (marginsType == |
| 335 // print_preview.MarginSettings.MARGINS_VALUE_NO_MARGINS || |
| 336 // !previewModifiable) { |
| 337 // headerFooterApplies = false; |
| 338 // } else if (marginsType != |
| 339 // print_preview.MarginSettings.MARGINS_VALUE_MINIMUM) { |
| 340 // if (cr.isLinux || cr.isChromeOS) { |
| 341 // headerFooterApplies = pageLayout.marginTop > 0 || |
| 342 // pageLayout.marginBottom > 0; |
| 343 // } else { |
| 344 // var pageHeight = pageLayout.marginTop + pageLayout.marginBottom + |
| 345 // pageLayout.contentHeight; |
| 346 // headerFooterApplies = |
| 347 // (pageLayout.marginTop > pageLayout.printableAreaY) || |
| 348 // (pageLayout.marginBottom > |
| 349 // (pageHeight - pageLayout.printableAreaY - |
| 350 // pageLayout.printableAreaHeight)); |
| 351 // } |
| 352 // } |
| 353 // this.setVisible_(headerFooterApplies); |
| 354 }, |
| 355 |
| 356 /** @return {boolean} Whether the header-footer setting is enabled. */ |
| 357 isHeaderFooterEnabled: function() { |
| 358 return this.ticket_.isHeaderFooterEnabled; |
| 359 }, |
| 360 |
| 361 updateHeaderFooter: function(isHeaderFooterEnabled) { |
| 362 if (!this.capabilities_.hasHeaderFooterCapability) { |
| 363 throw Error( |
| 364 'Updating header-footer capability but destination does not have ' + |
| 365 'a header-footer capability'); |
| 366 } |
| 367 if (this.ticket_.isHeaderFooterEnabled != isHeaderFooterEnabled) { |
| 368 this.ticket_.isHeaderFooterEnabled = isHeaderFooterEnabled; |
| 369 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 370 } |
| 371 }, |
| 372 |
| 373 hasOrientationCapability: function() { |
| 374 // TODO Is this true? Maybe we can still rotate if the document is not |
| 375 // modifiable. This is the old behavior. |
| 376 return this.capabilities_.hasOrientationCapability; |
| 377 }, |
| 378 |
| 379 isLandscapeEnabled: function() { |
| 380 return this.ticket_.isLandscapeEnabled; |
| 381 }, |
| 382 |
| 383 updateOrientation: function(isLandscape) { |
| 384 if (!this.capabilities_.hasOrientationCapability) { |
| 385 throw Error( |
| 386 'Updating orientation capability but destination does not have ' + |
| 387 'an orientation capability'); |
| 388 } |
| 389 if (this.ticket_.isLandscapeEnabled != isLandscape) { |
| 390 this.ticket_.isLandscapeEnabled = isLandscape; |
| 391 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 392 } |
| 393 }, |
| 394 |
| 395 hasDuplexCapability: function() { |
| 396 return this.capabilities_.hasDuplexCapability; |
| 397 }, |
| 398 |
| 399 isDuplexEnabled: function() { |
| 400 return this.ticket_.isDuplexEnabled; |
| 401 }, |
| 402 |
| 403 updateDuplex: function(isDuplex) { |
| 404 if (!this.capabilities_.hasDuplexCapability) { |
| 405 throw Error( |
| 406 'Updating duplex capability but destination does not have a ' + |
| 407 'duplex capability'); |
| 408 } |
| 409 if (this.ticket_.isDuplexEnabled != isDuplex) { |
| 410 this.ticket_.isDuplexEnabled = isDuplex; |
| 411 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 412 } |
| 413 }, |
| 414 |
| 415 hasMarginCapability: function() { |
| 416 return this.capabilities_.hasMarginCapability; |
| 417 }, |
| 418 |
| 419 getMarginType: function() { |
| 420 return this.ticket_.marginType; |
| 421 }, |
| 422 |
| 423 updateMarginType: function() { |
| 424 if (!this.capabilities_.hasMarginsCapability) { |
| 425 throw Error( |
| 426 'Updating margins capability but destination does not have a ' + |
| 427 'margin capability'); |
| 428 } |
| 429 // TODO |
| 430 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 431 }, |
| 432 |
| 433 hasPageRangeCapability: function() { |
| 434 return this.capabilities_.hasPageRangeCapability; |
| 435 }, |
| 436 |
| 437 isPageRangeValid: function() { |
| 438 var pageRangeStr = this.ticket_.pageRangeStr; |
| 439 return pageRangeStr == '' || |
| 440 isPageRangeTextValid(pageRangeStr, this.documentInfo_.pageCount); |
| 441 }, |
| 442 |
| 443 getPageRangeStr: function() { |
| 444 return this.ticket_.pageRangeStr; |
| 445 }, |
| 446 |
| 447 getPageNumberSet: function() { |
| 448 if (this.pageNumberSet_ == null) { |
| 449 this.pageNumberSet_ = print_preview.PageNumberSet.parse( |
| 450 this.ticket_.pageRangeStr, this.documentInfo_.pageCount); |
| 451 } |
| 452 return this.pageNumberSet_; |
| 453 }, |
| 454 |
| 455 updatePageRange: function(pageRangeStr) { |
| 456 if (!this.capabilities_.hasPageRangeCapability) { |
| 457 throw Error( |
| 458 'Updating page-range capability but destination does not have a ' + |
| 459 'page-range capability'); |
| 460 } |
| 461 log('print_preview.PrintTicketStore.updatePageRange -- trying update page
range str to ' + pageRangeStr); |
| 462 if (this.ticket_.pageRangeStr != pageRangeStr) { |
| 463 this.ticket_.pageRangeStr = pageRangeStr; |
| 464 this.pageNumberSet_ = null; |
| 465 cr.dispatchSimpleEvent(this, PrintTicketStore.Event.TICKET_CHANGE); |
| 466 } else { |
| 467 log('print_preview.PrintTicketStore.updatePageRange -- ignoring because
no change'); |
| 468 } |
| 469 }, |
| 470 |
| 471 /** |
| 472 * Checking if the stored print ticket is valid. |
| 473 * @return {boolean} {@code true} if the stored print ticket is valid, |
| 474 * {@code false} otherwise. |
| 475 */ |
| 476 isTicketValid: function() { |
| 477 // TODO Validate margins |
| 478 return this.isCopiesValid() && this.isPageRangeValid(); |
| 479 }, |
| 480 |
| 481 serializeTicket: function() { |
| 482 return 'persisted ticket'; |
| 483 }, |
| 484 |
| 485 /** |
| 486 * Generates a print ticket suitable for sending to Google Cloud Print. |
| 487 * @return {string} Serialized form of a Google Cloud Print print ticket. |
| 488 */ |
| 489 createTicketForCloudPrint: function() { |
| 490 // TODO |
| 491 }, |
| 492 |
| 493 /** |
| 494 * Generates a print ticket suitable for sending to Chromium. |
| 495 * @return {Object} Object to send to Chromium. |
| 496 */ |
| 497 createTicketForChromium: function() { |
| 498 // TODO |
| 499 } |
| 500 }; |
| 501 |
| 502 /** |
| 503 * Object which contains information related to the document to print. |
| 504 * @constructor |
| 505 */ |
| 506 function DocumentInfo() { |
| 507 this.isModifiable = true; |
| 508 this.pageCount = 1; |
| 509 this.hasPageSizeStyle = false; |
| 510 this.pageLayout = null; |
| 511 }; |
| 512 |
| 513 // Export |
| 514 return { |
| 515 PrintTicketStore: PrintTicketStore |
| 516 }; |
| 517 }); |
OLD | NEW |