1 /* 2 * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.print; 27 28 import java.io.OutputStream; 29 import java.util.Iterator; 30 import java.util.Locale; 31 32 import javax.print.DocFlavor; 33 import javax.print.DocPrintJob; 34 import javax.print.StreamPrintService; 35 import javax.print.StreamPrintServiceFactory; 36 import javax.print.ServiceUIFactory; 37 import javax.print.attribute.Attribute; 38 import javax.print.attribute.AttributeSet; 39 import javax.print.attribute.AttributeSetUtilities; 40 import javax.print.attribute.HashAttributeSet; 41 import javax.print.attribute.HashPrintServiceAttributeSet; 42 import javax.print.attribute.PrintServiceAttribute; 43 import javax.print.attribute.PrintServiceAttributeSet; 44 import javax.print.attribute.Size2DSyntax; 45 import javax.print.event.PrintServiceAttributeListener; 46 import javax.print.attribute.standard.JobName; 47 import javax.print.attribute.standard.RequestingUserName; 48 import javax.print.attribute.standard.Chromaticity; 49 import javax.print.attribute.standard.ColorSupported; 50 import javax.print.attribute.standard.Copies; 51 import javax.print.attribute.standard.CopiesSupported; 52 import javax.print.attribute.standard.Fidelity; 53 import javax.print.attribute.standard.Media; 54 import javax.print.attribute.standard.MediaPrintableArea; 55 import javax.print.attribute.standard.MediaSize; 56 import javax.print.attribute.standard.MediaSizeName; 57 import javax.print.attribute.standard.OrientationRequested; 58 import javax.print.attribute.standard.PageRanges; 59 import javax.print.attribute.standard.SheetCollate; 60 import javax.print.attribute.standard.Sides; 61 62 public class PSStreamPrintService extends StreamPrintService 63 implements SunPrinterJobService { 64 65 private static final Class[] suppAttrCats = { 66 Chromaticity.class, 67 Copies.class, 68 Fidelity.class, 69 JobName.class, 70 Media.class, 71 MediaPrintableArea.class, 72 OrientationRequested.class, 73 PageRanges.class, 74 RequestingUserName.class, 75 SheetCollate.class, 76 Sides.class, 77 }; 78 79 private static int MAXCOPIES = 1000; 80 81 private static final MediaSizeName mediaSizes[] = { 82 MediaSizeName.NA_LETTER, 83 MediaSizeName.TABLOID, 84 MediaSizeName.LEDGER, 85 MediaSizeName.NA_LEGAL, 86 MediaSizeName.EXECUTIVE, 87 MediaSizeName.ISO_A3, 88 MediaSizeName.ISO_A4, 89 MediaSizeName.ISO_A5, 90 MediaSizeName.ISO_B4, 91 MediaSizeName.ISO_B5, 92 }; 93 94 public PSStreamPrintService(OutputStream out) { 95 super(out); 96 } 97 98 public String getOutputFormat() { 99 return PSStreamPrinterFactory.psMimeType; 100 } 101 102 103 public DocFlavor[] getSupportedDocFlavors() { 104 return PSStreamPrinterFactory.getFlavors(); 105 } 106 107 public DocPrintJob createPrintJob() { 108 return new PSStreamPrintJob(this); 109 } 110 111 public boolean usesClass(Class c) { 112 return (c == sun.print.PSPrinterJob.class); 113 } 114 115 public String getName() { 116 return "Postscript output"; 117 } 118 119 public void addPrintServiceAttributeListener( 120 PrintServiceAttributeListener listener) { 121 return; 122 } 123 124 public void removePrintServiceAttributeListener( 125 PrintServiceAttributeListener listener) { 126 return; 127 } 128 129 130 public <T extends PrintServiceAttribute> 131 T getAttribute(Class<T> category) 132 { 133 if (category == null) { 134 throw new NullPointerException("category"); 135 } 136 if (!(PrintServiceAttribute.class.isAssignableFrom(category))) { 137 throw new IllegalArgumentException("Not a PrintServiceAttribute"); 138 } 139 if (category == ColorSupported.class) { 140 return (T)ColorSupported.SUPPORTED; 141 } else { 142 return null; 143 } 144 } 145 public PrintServiceAttributeSet getAttributes() { 146 PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); 147 attrs.add(ColorSupported.SUPPORTED); 148 149 return AttributeSetUtilities.unmodifiableView(attrs); 150 } 151 152 public boolean isDocFlavorSupported(DocFlavor flavor) { 153 DocFlavor [] flavors = getSupportedDocFlavors(); 154 for (int f=0; f<flavors.length; f++) { 155 if (flavor.equals(flavors[f])) { 156 return true; 157 } 158 } 159 return false; 160 } 161 162 163 public Class<?>[] getSupportedAttributeCategories() { 164 Class []cats = new Class[suppAttrCats.length]; 165 System.arraycopy(suppAttrCats, 0, cats, 0, cats.length); 166 return cats; 167 } 168 169 public boolean 170 isAttributeCategorySupported(Class<? extends Attribute> category) 171 { 172 if (category == null) { 173 throw new NullPointerException("null category"); 174 } 175 if (!(Attribute.class.isAssignableFrom(category))) { 176 throw new IllegalArgumentException(category + 177 " is not an Attribute"); 178 } 179 180 for (int i=0;i<suppAttrCats.length;i++) { 181 if (category == suppAttrCats[i]) { 182 return true; 183 } 184 } 185 return false; 186 } 187 188 189 public Object 190 getDefaultAttributeValue(Class<? extends Attribute> category) 191 { 192 if (category == null) { 193 throw new NullPointerException("null category"); 194 } 195 if (!Attribute.class.isAssignableFrom(category)) { 196 throw new IllegalArgumentException(category + 197 " is not an Attribute"); 198 } 199 200 if (!isAttributeCategorySupported(category)) { 201 return null; 202 } 203 204 if (category == Copies.class) { 205 return new Copies(1); 206 } else if (category == Chromaticity.class) { 207 return Chromaticity.COLOR; 208 } else if (category == Fidelity.class) { 209 return Fidelity.FIDELITY_FALSE; 210 } else if (category == Media.class) { 211 String defaultCountry = Locale.getDefault().getCountry(); 212 if (defaultCountry != null && 213 (defaultCountry.equals("") || 214 defaultCountry.equals(Locale.US.getCountry()) || 215 defaultCountry.equals(Locale.CANADA.getCountry()))) { 216 return MediaSizeName.NA_LETTER; 217 } else { 218 return MediaSizeName.ISO_A4; 219 } 220 } else if (category == MediaPrintableArea.class) { 221 String defaultCountry = Locale.getDefault().getCountry(); 222 float iw, ih; 223 float margin = 0.5f; // both these papers > 5" in all dimensions 224 if (defaultCountry != null && 225 (defaultCountry.equals("") || 226 defaultCountry.equals(Locale.US.getCountry()) || 227 defaultCountry.equals(Locale.CANADA.getCountry()))) { 228 iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 2*margin; 229 ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 2*margin; 230 } else { 231 iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 2*margin; 232 ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 2*margin; 233 } 234 return new MediaPrintableArea(margin, margin, iw, ih, 235 MediaPrintableArea.INCH); 236 } else if (category == OrientationRequested.class) { 237 return OrientationRequested.PORTRAIT; 238 } else if (category == PageRanges.class) { 239 return new PageRanges(1, Integer.MAX_VALUE); 240 } else if (category == SheetCollate.class) { 241 return SheetCollate.UNCOLLATED; 242 } else if (category == Sides.class) { 243 return Sides.ONE_SIDED; 244 245 } else 246 return null; 247 } 248 249 250 public Object 251 getSupportedAttributeValues(Class<? extends Attribute> category, 252 DocFlavor flavor, 253 AttributeSet attributes) 254 { 255 256 if (category == null) { 257 throw new NullPointerException("null category"); 258 } 259 if (!Attribute.class.isAssignableFrom(category)) { 260 throw new IllegalArgumentException(category + 261 " does not implement Attribute"); 262 } 263 if (flavor != null && !isDocFlavorSupported(flavor)) { 264 throw new IllegalArgumentException(flavor + 265 " is an unsupported flavor"); 266 } 267 268 if (!isAttributeCategorySupported(category)) { 269 return null; 270 } 271 272 if (category == Chromaticity.class) { 273 Chromaticity[]arr = new Chromaticity[1]; 274 arr[0] = Chromaticity.COLOR; 275 //arr[1] = Chromaticity.MONOCHROME; 276 return (arr); 277 } else if (category == JobName.class) { 278 return new JobName("", null); 279 } else if (category == RequestingUserName.class) { 280 return new RequestingUserName("", null); 281 } else if (category == OrientationRequested.class) { 282 if (flavor == null || 283 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 284 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 285 OrientationRequested []arr = new OrientationRequested[3]; 286 arr[0] = OrientationRequested.PORTRAIT; 287 arr[1] = OrientationRequested.LANDSCAPE; 288 arr[2] = OrientationRequested.REVERSE_LANDSCAPE; 289 return arr; 290 } else { 291 return null; 292 } 293 } else if ((category == Copies.class) || 294 (category == CopiesSupported.class)) { 295 return new CopiesSupported(1, MAXCOPIES); 296 } else if (category == Media.class) { 297 Media []arr = new Media[mediaSizes.length]; 298 System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length); 299 return arr; 300 } else if (category == Fidelity.class) { 301 Fidelity []arr = new Fidelity[2]; 302 arr[0] = Fidelity.FIDELITY_FALSE; 303 arr[1] = Fidelity.FIDELITY_TRUE; 304 return arr; 305 } else if (category == MediaPrintableArea.class) { 306 if (attributes == null) { 307 return null; 308 } 309 MediaSize mediaSize = (MediaSize)attributes.get(MediaSize.class); 310 if (mediaSize == null) { 311 Media media = (Media)attributes.get(Media.class); 312 if (media != null && media instanceof MediaSizeName) { 313 MediaSizeName msn = (MediaSizeName)media; 314 mediaSize = MediaSize.getMediaSizeForName(msn); 315 } 316 } 317 if (mediaSize == null) { 318 return null; 319 } else { 320 MediaPrintableArea []arr = new MediaPrintableArea[1]; 321 float w = mediaSize.getX(MediaSize.INCH); 322 float h = mediaSize.getY(MediaSize.INCH); 323 /* For dimensions >= 5 inches use 0.5 inch margins. 324 * For smaller dimensions, use 10% margins. 325 */ 326 float xmargin = 0.5f; 327 float ymargin = 0.5f; 328 if (w < 5f) { 329 xmargin = w/10; 330 } 331 if (h < 5f) { 332 ymargin = h/10; 333 } 334 arr[0] = new MediaPrintableArea(xmargin, ymargin, 335 w - 2*xmargin, 336 h - 2*ymargin, 337 MediaSize.INCH); 338 return arr; 339 } 340 } else if (category == PageRanges.class) { 341 if (flavor == null || 342 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 343 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 344 PageRanges []arr = new PageRanges[1]; 345 arr[0] = new PageRanges(1, Integer.MAX_VALUE); 346 return arr; 347 } else { 348 return null; 349 } 350 } else if (category == SheetCollate.class) { 351 if (flavor == null || 352 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 353 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 354 SheetCollate []arr = new SheetCollate[2]; 355 arr[0] = SheetCollate.UNCOLLATED; 356 arr[1] = SheetCollate.COLLATED; 357 return arr; 358 } else { 359 SheetCollate []arr = new SheetCollate[1]; 360 arr[0] = SheetCollate.UNCOLLATED; 361 return arr; 362 } 363 } else if (category == Sides.class) { 364 if (flavor == null || 365 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 366 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 367 Sides []arr = new Sides[3]; 368 arr[0] = Sides.ONE_SIDED; 369 arr[1] = Sides.TWO_SIDED_LONG_EDGE; 370 arr[2] = Sides.TWO_SIDED_SHORT_EDGE; 371 return arr; 372 } else { 373 return null; 374 } 375 } else { 376 return null; 377 } 378 } 379 380 private boolean isSupportedCopies(Copies copies) { 381 int numCopies = copies.getValue(); 382 return (numCopies > 0 && numCopies < MAXCOPIES); 383 } 384 385 private boolean isSupportedMedia(MediaSizeName msn) { 386 for (int i=0; i<mediaSizes.length; i++) { 387 if (msn.equals(mediaSizes[i])) { 388 return true; 389 } 390 } 391 return false; 392 } 393 394 public boolean isAttributeValueSupported(Attribute attr, 395 DocFlavor flavor, 396 AttributeSet attributes) { 397 if (attr == null) { 398 throw new NullPointerException("null attribute"); 399 } 400 if (flavor != null && !isDocFlavorSupported(flavor)) { 401 throw new IllegalArgumentException(flavor + 402 " is an unsupported flavor"); 403 } 404 Class category = attr.getCategory(); 405 if (!isAttributeCategorySupported(category)) { 406 return false; 407 } 408 else if (attr.getCategory() == Chromaticity.class) { 409 return attr == Chromaticity.COLOR; 410 } 411 else if (attr.getCategory() == Copies.class) { 412 return isSupportedCopies((Copies)attr); 413 } else if (attr.getCategory() == Media.class && 414 attr instanceof MediaSizeName) { 415 return isSupportedMedia((MediaSizeName)attr); 416 } else if (attr.getCategory() == OrientationRequested.class) { 417 if (attr == OrientationRequested.REVERSE_PORTRAIT || 418 (flavor != null) && 419 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 420 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 421 return false; 422 } 423 } else if (attr.getCategory() == PageRanges.class) { 424 if (flavor != null && 425 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 426 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 427 return false; 428 } 429 } else if (attr.getCategory() == SheetCollate.class) { 430 if (flavor != null && 431 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 432 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 433 return false; 434 } 435 } else if (attr.getCategory() == Sides.class) { 436 if (flavor != null && 437 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 438 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 439 return false; 440 } 441 } 442 return true; 443 } 444 445 public AttributeSet getUnsupportedAttributes(DocFlavor flavor, 446 AttributeSet attributes) { 447 448 if (flavor != null && !isDocFlavorSupported(flavor)) { 449 throw new IllegalArgumentException("flavor " + flavor + 450 "is not supported"); 451 } 452 453 if (attributes == null) { 454 return null; 455 } 456 457 Attribute attr; 458 AttributeSet unsupp = new HashAttributeSet(); 459 Attribute[] attrs = attributes.toArray(); 460 for (int i=0; i<attrs.length; i++) { 461 try { 462 attr = attrs[i]; 463 if (!isAttributeCategorySupported(attr.getCategory())) { 464 unsupp.add(attr); 465 } else if (!isAttributeValueSupported(attr, flavor, 466 attributes)) { 467 unsupp.add(attr); 468 } 469 } catch (ClassCastException e) { 470 } 471 } 472 if (unsupp.isEmpty()) { 473 return null; 474 } else { 475 return unsupp; 476 } 477 } 478 479 public ServiceUIFactory getServiceUIFactory() { 480 return null; 481 } 482 483 public String toString() { 484 return "PSStreamPrintService: " + getName(); 485 } 486 487 /* Stream services have an output stream which cannot be shared, 488 * so two services are equal only if they are the same object. 489 */ 490 public boolean equals(Object obj) { 491 return (obj == this || 492 (obj instanceof PSStreamPrintService && 493 ((PSStreamPrintService)obj).getName().equals(getName()))); 494 } 495 496 public int hashCode() { 497 return this.getClass().hashCode()+getName().hashCode(); 498 } 499 500 }