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 @SuppressWarnings("unchecked") 141 T tmp = (T)ColorSupported.SUPPORTED; 142 return tmp; 143 } else { 144 return null; 145 } 146 } 147 public PrintServiceAttributeSet getAttributes() { 148 PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); 149 attrs.add(ColorSupported.SUPPORTED); 150 151 return AttributeSetUtilities.unmodifiableView(attrs); 152 } 153 154 public boolean isDocFlavorSupported(DocFlavor flavor) { 155 DocFlavor [] flavors = getSupportedDocFlavors(); 156 for (int f=0; f<flavors.length; f++) { 157 if (flavor.equals(flavors[f])) { 158 return true; 159 } 160 } 161 return false; 162 } 163 164 165 public Class<?>[] getSupportedAttributeCategories() { 166 Class<?>[] cats = new Class<?>[suppAttrCats.length]; 167 System.arraycopy(suppAttrCats, 0, cats, 0, cats.length); 168 return cats; 169 } 170 171 public boolean 172 isAttributeCategorySupported(Class<? extends Attribute> category) 173 { 174 if (category == null) { 175 throw new NullPointerException("null category"); 176 } 177 if (!(Attribute.class.isAssignableFrom(category))) { 178 throw new IllegalArgumentException(category + 179 " is not an Attribute"); 180 } 181 182 for (int i=0;i<suppAttrCats.length;i++) { 183 if (category == suppAttrCats[i]) { 184 return true; 185 } 186 } 187 return false; 188 } 189 190 191 public Object 192 getDefaultAttributeValue(Class<? extends Attribute> category) 193 { 194 if (category == null) { 195 throw new NullPointerException("null category"); 196 } 197 if (!Attribute.class.isAssignableFrom(category)) { 198 throw new IllegalArgumentException(category + 199 " is not an Attribute"); 200 } 201 202 if (!isAttributeCategorySupported(category)) { 203 return null; 204 } 205 206 if (category == Copies.class) { 207 return new Copies(1); 208 } else if (category == Chromaticity.class) { 209 return Chromaticity.COLOR; 210 } else if (category == Fidelity.class) { 211 return Fidelity.FIDELITY_FALSE; 212 } else if (category == Media.class) { 213 String defaultCountry = Locale.getDefault().getCountry(); 214 if (defaultCountry != null && 215 (defaultCountry.equals("") || 216 defaultCountry.equals(Locale.US.getCountry()) || 217 defaultCountry.equals(Locale.CANADA.getCountry()))) { 218 return MediaSizeName.NA_LETTER; 219 } else { 220 return MediaSizeName.ISO_A4; 221 } 222 } else if (category == MediaPrintableArea.class) { 223 String defaultCountry = Locale.getDefault().getCountry(); 224 float iw, ih; 225 float margin = 0.5f; // both these papers > 5" in all dimensions 226 if (defaultCountry != null && 227 (defaultCountry.equals("") || 228 defaultCountry.equals(Locale.US.getCountry()) || 229 defaultCountry.equals(Locale.CANADA.getCountry()))) { 230 iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 2*margin; 231 ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 2*margin; 232 } else { 233 iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 2*margin; 234 ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 2*margin; 235 } 236 return new MediaPrintableArea(margin, margin, iw, ih, 237 MediaPrintableArea.INCH); 238 } else if (category == OrientationRequested.class) { 239 return OrientationRequested.PORTRAIT; 240 } else if (category == PageRanges.class) { 241 return new PageRanges(1, Integer.MAX_VALUE); 242 } else if (category == SheetCollate.class) { 243 return SheetCollate.UNCOLLATED; 244 } else if (category == Sides.class) { 245 return Sides.ONE_SIDED; 246 247 } else 248 return null; 249 } 250 251 252 public Object 253 getSupportedAttributeValues(Class<? extends Attribute> category, 254 DocFlavor flavor, 255 AttributeSet attributes) 256 { 257 258 if (category == null) { 259 throw new NullPointerException("null category"); 260 } 261 if (!Attribute.class.isAssignableFrom(category)) { 262 throw new IllegalArgumentException(category + 263 " does not implement Attribute"); 264 } 265 if (flavor != null && !isDocFlavorSupported(flavor)) { 266 throw new IllegalArgumentException(flavor + 267 " is an unsupported flavor"); 268 } 269 270 if (!isAttributeCategorySupported(category)) { 271 return null; 272 } 273 274 if (category == Chromaticity.class) { 275 Chromaticity[]arr = new Chromaticity[1]; 276 arr[0] = Chromaticity.COLOR; 277 //arr[1] = Chromaticity.MONOCHROME; 278 return (arr); 279 } else if (category == JobName.class) { 280 return new JobName("", null); 281 } else if (category == RequestingUserName.class) { 282 return new RequestingUserName("", null); 283 } else if (category == OrientationRequested.class) { 284 if (flavor == null || 285 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 286 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || 287 flavor.equals(DocFlavor.INPUT_STREAM.GIF) || 288 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || 289 flavor.equals(DocFlavor.INPUT_STREAM.PNG) || 290 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || 291 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || 292 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) || 293 flavor.equals(DocFlavor.URL.GIF) || 294 flavor.equals(DocFlavor.URL.JPEG) || 295 flavor.equals(DocFlavor.URL.PNG)) { 296 OrientationRequested []arr = new OrientationRequested[3]; 297 arr[0] = OrientationRequested.PORTRAIT; 298 arr[1] = OrientationRequested.LANDSCAPE; 299 arr[2] = OrientationRequested.REVERSE_LANDSCAPE; 300 return arr; 301 } else { 302 return null; 303 } 304 } else if ((category == Copies.class) || 305 (category == CopiesSupported.class)) { 306 return new CopiesSupported(1, MAXCOPIES); 307 } else if (category == Media.class) { 308 Media []arr = new Media[mediaSizes.length]; 309 System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length); 310 return arr; 311 } else if (category == Fidelity.class) { 312 Fidelity []arr = new Fidelity[2]; 313 arr[0] = Fidelity.FIDELITY_FALSE; 314 arr[1] = Fidelity.FIDELITY_TRUE; 315 return arr; 316 } else if (category == MediaPrintableArea.class) { 317 if (attributes == null) { 318 return null; 319 } 320 MediaSize mediaSize = (MediaSize)attributes.get(MediaSize.class); 321 if (mediaSize == null) { 322 Media media = (Media)attributes.get(Media.class); 323 if (media != null && media instanceof MediaSizeName) { 324 MediaSizeName msn = (MediaSizeName)media; 325 mediaSize = MediaSize.getMediaSizeForName(msn); 326 } 327 } 328 if (mediaSize == null) { 329 return null; 330 } else { 331 MediaPrintableArea []arr = new MediaPrintableArea[1]; 332 float w = mediaSize.getX(MediaSize.INCH); 333 float h = mediaSize.getY(MediaSize.INCH); 334 /* For dimensions >= 5 inches use 0.5 inch margins. 335 * For smaller dimensions, use 10% margins. 336 */ 337 float xmargin = 0.5f; 338 float ymargin = 0.5f; 339 if (w < 5f) { 340 xmargin = w/10; 341 } 342 if (h < 5f) { 343 ymargin = h/10; 344 } 345 arr[0] = new MediaPrintableArea(xmargin, ymargin, 346 w - 2*xmargin, 347 h - 2*ymargin, 348 MediaSize.INCH); 349 return arr; 350 } 351 } else if (category == PageRanges.class) { 352 if (flavor == null || 353 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 354 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 355 PageRanges []arr = new PageRanges[1]; 356 arr[0] = new PageRanges(1, Integer.MAX_VALUE); 357 return arr; 358 } else { 359 return null; 360 } 361 } else if (category == SheetCollate.class) { 362 if (flavor == null || 363 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 364 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 365 SheetCollate []arr = new SheetCollate[2]; 366 arr[0] = SheetCollate.UNCOLLATED; 367 arr[1] = SheetCollate.COLLATED; 368 return arr; 369 } else { 370 SheetCollate []arr = new SheetCollate[1]; 371 arr[0] = SheetCollate.UNCOLLATED; 372 return arr; 373 } 374 } else if (category == Sides.class) { 375 if (flavor == null || 376 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 377 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) { 378 Sides []arr = new Sides[3]; 379 arr[0] = Sides.ONE_SIDED; 380 arr[1] = Sides.TWO_SIDED_LONG_EDGE; 381 arr[2] = Sides.TWO_SIDED_SHORT_EDGE; 382 return arr; 383 } else { 384 return null; 385 } 386 } else { 387 return null; 388 } 389 } 390 391 private boolean isSupportedCopies(Copies copies) { 392 int numCopies = copies.getValue(); 393 return (numCopies > 0 && numCopies < MAXCOPIES); 394 } 395 396 private boolean isSupportedMedia(MediaSizeName msn) { 397 for (int i=0; i<mediaSizes.length; i++) { 398 if (msn.equals(mediaSizes[i])) { 399 return true; 400 } 401 } 402 return false; 403 } 404 405 public boolean isAttributeValueSupported(Attribute attr, 406 DocFlavor flavor, 407 AttributeSet attributes) { 408 if (attr == null) { 409 throw new NullPointerException("null attribute"); 410 } 411 if (flavor != null && !isDocFlavorSupported(flavor)) { 412 throw new IllegalArgumentException(flavor + 413 " is an unsupported flavor"); 414 } 415 Class<? extends Attribute> category = attr.getCategory(); 416 if (!isAttributeCategorySupported(category)) { 417 return false; 418 } 419 else if (attr.getCategory() == Chromaticity.class) { 420 return attr == Chromaticity.COLOR; 421 } 422 else if (attr.getCategory() == Copies.class) { 423 return isSupportedCopies((Copies)attr); 424 } else if (attr.getCategory() == Media.class && 425 attr instanceof MediaSizeName) { 426 return isSupportedMedia((MediaSizeName)attr); 427 } else if (attr.getCategory() == OrientationRequested.class) { 428 if (attr == OrientationRequested.REVERSE_PORTRAIT || 429 (flavor != null) && 430 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 431 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 432 return false; 433 } 434 } else if (attr.getCategory() == PageRanges.class) { 435 if (flavor != null && 436 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 437 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 438 return false; 439 } 440 } else if (attr.getCategory() == SheetCollate.class) { 441 if (flavor != null && 442 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 443 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 444 return false; 445 } 446 } else if (attr.getCategory() == Sides.class) { 447 if (flavor != null && 448 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || 449 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) { 450 return false; 451 } 452 } 453 return true; 454 } 455 456 public AttributeSet getUnsupportedAttributes(DocFlavor flavor, 457 AttributeSet attributes) { 458 459 if (flavor != null && !isDocFlavorSupported(flavor)) { 460 throw new IllegalArgumentException("flavor " + flavor + 461 "is not supported"); 462 } 463 464 if (attributes == null) { 465 return null; 466 } 467 468 Attribute attr; 469 AttributeSet unsupp = new HashAttributeSet(); 470 Attribute[] attrs = attributes.toArray(); 471 for (int i=0; i<attrs.length; i++) { 472 try { 473 attr = attrs[i]; 474 if (!isAttributeCategorySupported(attr.getCategory())) { 475 unsupp.add(attr); 476 } else if (!isAttributeValueSupported(attr, flavor, 477 attributes)) { 478 unsupp.add(attr); 479 } 480 } catch (ClassCastException e) { 481 } 482 } 483 if (unsupp.isEmpty()) { 484 return null; 485 } else { 486 return unsupp; 487 } 488 } 489 490 public ServiceUIFactory getServiceUIFactory() { 491 return null; 492 } 493 494 public String toString() { 495 return "PSStreamPrintService: " + getName(); 496 } 497 498 /* Stream services have an output stream which cannot be shared, 499 * so two services are equal only if they are the same object. 500 */ 501 public boolean equals(Object obj) { 502 return (obj == this || 503 (obj instanceof PSStreamPrintService && 504 ((PSStreamPrintService)obj).getName().equals(getName()))); 505 } 506 507 public int hashCode() { 508 return this.getClass().hashCode()+getName().hashCode(); 509 } 510 511 }