001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.x.print;
018:
019: import java.io.File;
020: import java.security.AccessController;
021: import java.security.PrivilegedAction;
022: import java.util.Collections;
023: import java.util.Map;
024: import java.util.WeakHashMap;
025:
026: import javax.print.DocFlavor;
027: import javax.print.DocPrintJob;
028: import javax.print.PrintException;
029: import javax.print.PrintService;
030: import javax.print.ServiceUIFactory;
031: import javax.print.attribute.Attribute;
032: import javax.print.attribute.AttributeSet;
033: import javax.print.attribute.AttributeSetUtilities;
034: import javax.print.attribute.HashAttributeSet;
035: import javax.print.attribute.HashPrintServiceAttributeSet;
036: import javax.print.attribute.PrintServiceAttribute;
037: import javax.print.attribute.PrintServiceAttributeSet;
038: import javax.print.attribute.standard.Chromaticity;
039: import javax.print.attribute.standard.Copies;
040: import javax.print.attribute.standard.CopiesSupported;
041: import javax.print.attribute.standard.Destination;
042: import javax.print.attribute.standard.JobName;
043: import javax.print.attribute.standard.Media;
044: import javax.print.attribute.standard.MediaPrintableArea;
045: import javax.print.attribute.standard.MediaSize;
046: import javax.print.attribute.standard.MediaSizeName;
047: import javax.print.attribute.standard.OrientationRequested;
048: import javax.print.attribute.standard.PrintQuality;
049: import javax.print.attribute.standard.PrinterName;
050: import javax.print.attribute.standard.PrinterResolution;
051: import javax.print.attribute.standard.PrinterState;
052: import javax.print.attribute.standard.QueuedJobCount;
053: import javax.print.attribute.standard.RequestingUserName;
054: import javax.print.attribute.standard.SheetCollate;
055: import javax.print.attribute.standard.Sides;
056: import javax.print.event.PrintServiceAttributeEvent;
057: import javax.print.event.PrintServiceAttributeListener;
058:
059: import org.apache.harmony.x.print.DevmodeStructWrapper.Paper;
060: import org.apache.harmony.x.print.DevmodeStructWrapper.StdPaper;
061:
062: class WinPrintService implements PrintService {
063:
064: static final JobName DEFAULT_JOB_NAME = new JobName(
065: "Java printing", null); //$NON-NLS-1$
066:
067: private static final DocFlavor[] SUPPORTED_FLAVORS = {
068: DocFlavor.SERVICE_FORMATTED.PRINTABLE,
069: DocFlavor.SERVICE_FORMATTED.PAGEABLE, DocFlavor.URL.JPEG,
070: DocFlavor.INPUT_STREAM.JPEG, DocFlavor.BYTE_ARRAY.JPEG,
071: DocFlavor.URL.GIF, DocFlavor.INPUT_STREAM.GIF,
072: DocFlavor.BYTE_ARRAY.GIF, DocFlavor.URL.PNG,
073: DocFlavor.INPUT_STREAM.PNG, DocFlavor.BYTE_ARRAY.PNG };
074:
075: private static final Class<?>[] SUPPORTED_ATTR_CATS = new Class<?>[] {
076: JobName.class, RequestingUserName.class, Destination.class,
077: OrientationRequested.class, Media.class, MediaSize.class,
078: Copies.class, PrintQuality.class, PrinterResolution.class,
079: Sides.class, SheetCollate.class, Chromaticity.class,
080: MediaPrintableArea.class, PrinterResolution.class };
081:
082: final String printerName;
083: private final Map<PrintServiceAttributeListener, Object> attrListeners;
084: private long pHandle;
085: private DevmodeStructWrapper dmStruct;
086: private DevmodeStructWrapper defaultDmStruct;
087:
088: WinPrintService(final String printerName) {
089: this .printerName = printerName;
090: attrListeners = Collections
091: .synchronizedMap(new WeakHashMap<PrintServiceAttributeListener, Object>());
092: }
093:
094: public void addPrintServiceAttributeListener(
095: final PrintServiceAttributeListener listener) {
096: attrListeners.put(listener, null);
097: }
098:
099: public DocPrintJob createPrintJob() {
100: WinPrinterFactory.checkPrintJobAccess();
101: try {
102: notifyListeners(WinPrinterFactory
103: .getPrinterState(getPrinterHandle()),
104: WinPrinterFactory
105: .getQueuedJobCount(getPrinterHandle()));
106: } catch (final PrintException ex) {
107: throw new RuntimeException(ex);
108: }
109: return new WinPrintJob(this );
110: }
111:
112: public <T extends PrintServiceAttribute> T getAttribute(
113: final Class<T> category) {
114: if (category == null) {
115: throw new NullPointerException(
116: "category should not be null"); //$NON-NLS-1$
117: }
118:
119: if (!PrintServiceAttribute.class.isAssignableFrom(category)) {
120: throw new IllegalArgumentException(category
121: + " is not assignable from PrintServiceAttribute"); //$NON-NLS-1$
122: }
123:
124: try {
125: if (PrinterName.class.equals(category)) {
126: return category
127: .cast(new PrinterName(printerName, null));
128: } else if (PrinterState.class.equals(category)) {
129: return category.cast(WinPrinterFactory
130: .getPrinterState(getPrinterHandle()));
131: } else if (QueuedJobCount.class.equals(category)) {
132: return category.cast(WinPrinterFactory
133: .getQueuedJobCount(getPrinterHandle()));
134: }
135:
136: return null;
137: } catch (final PrintException ex) {
138: throw new RuntimeException(ex);
139: }
140: }
141:
142: public PrintServiceAttributeSet getAttributes() {
143: final PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
144:
145: attrs.add(new PrinterName(printerName, null));
146: try {
147: attrs.add(WinPrinterFactory
148: .getPrinterState(getPrinterHandle()));
149: attrs.add(WinPrinterFactory
150: .getQueuedJobCount(getPrinterHandle()));
151: } catch (final PrintException ex) {
152: throw new RuntimeException(ex);
153: }
154:
155: return AttributeSetUtilities.unmodifiableView(attrs);
156: }
157:
158: public Object getDefaultAttributeValue(
159: final Class<? extends Attribute> category) {
160: checkArgs(category, null);
161:
162: final DevmodeStructWrapper dm = getDefaultPrinterProps();
163:
164: if (JobName.class.equals(category)) {
165: return DEFAULT_JOB_NAME;
166: } else if (RequestingUserName.class.equals(category)) {
167: return new RequestingUserName(
168: getSystemProperty("user.name"), //$NON-NLS-1$
169: null);
170: } else if (Destination.class.equals(category)) {
171: File file = new File(getSystemProperty("user.dir") //$NON-NLS-1$
172: + File.separator + "output.prn"); //$NON-NLS-1$
173: return new Destination(file.toURI());
174: } else if (OrientationRequested.class.equals(category)) {
175: return dm.getOrientation();
176: } else if (Paper.class.equals(category)) {
177: return getDefaultPaper();
178: } else if (Media.class.equals(category)) {
179: return getDefaultPaper().getSize().getMediaSizeName();
180: } else if (MediaSize.class.equals(category)) {
181: return getDefaultPaper().getSize();
182: } else if (PrintQuality.class.equals(category)) {
183: return dm.getPrintQuality();
184: } else if (Sides.class.equals(category)) {
185: return dm.getSides();
186: } else if (Copies.class.equals(category)) {
187: return dm.getCopies();
188: } else if (SheetCollate.class.equals(category)) {
189: return dm.getCollate();
190: } else if (PrinterResolution.class.equals(category)) {
191: return dm.getPrinterResolution();
192: } else if (Chromaticity.class.equals(category)) {
193: return dm.getChromaticity();
194: }
195:
196: return null;
197: }
198:
199: public String getName() {
200: return printerName;
201: }
202:
203: public ServiceUIFactory getServiceUIFactory() {
204: return null;
205: }
206:
207: public Class<?>[] getSupportedAttributeCategories() {
208: return SUPPORTED_ATTR_CATS;
209: }
210:
211: public Object getSupportedAttributeValues(
212: final Class<? extends Attribute> category,
213: final DocFlavor flavor, final AttributeSet attributes) {
214: checkArgs(category, flavor);
215:
216: try {
217: if (OrientationRequested.class.equals(category)) {
218: return WinPrinterFactory
219: .getSupportedOrientations(getPrinterHandle());
220: } else if (Media.class.equals(category)
221: || MediaSizeName.class.equals(category)) {
222: return WinPrinterFactory
223: .getSupportedMediaSizeNames(getPrinterHandle());
224: } else if (MediaSize.class.equals(category)) {
225: return WinPrinterFactory
226: .getSupportedMediaSizes(getPrinterHandle());
227: } else if (CopiesSupported.class.equals(category)) {
228: final int max = WinPrinterFactory
229: .getMaxNumberOfCopies(getPrinterHandle());
230: return max > 1 ? new CopiesSupported(1, max)
231: : new CopiesSupported(1);
232: } else if (PrintQuality.class.equals(category)) {
233: return new PrintQuality[] { PrintQuality.HIGH,
234: PrintQuality.NORMAL, PrintQuality.DRAFT };
235: } else if (Sides.class.equals(category)) {
236: return WinPrinterFactory
237: .isDuplexSupported(getPrinterHandle()) ? new Sides[] {
238: Sides.ONE_SIDED, Sides.TWO_SIDED_SHORT_EDGE,
239: Sides.TWO_SIDED_LONG_EDGE }
240: : new Sides[] { Sides.ONE_SIDED };
241: } else if (SheetCollate.class.equals(category)) {
242: return WinPrinterFactory
243: .isDuplexSupported(getPrinterHandle()) ? new SheetCollate[] {
244: SheetCollate.COLLATED, SheetCollate.UNCOLLATED }
245: : new SheetCollate[] { SheetCollate.UNCOLLATED };
246: } else if (Chromaticity.class.equals(category)) {
247: return WinPrinterFactory
248: .isColorPrintingSupported(getPrinterHandle()) ? new Chromaticity[] {
249: Chromaticity.MONOCHROME, Chromaticity.COLOR }
250: : new Chromaticity[] { Chromaticity.MONOCHROME };
251: } else if (PrinterResolution.class.equals(category)) {
252: return WinPrinterFactory
253: .getSupportedPrinterResolutions(getPrinterHandle());
254: } else if (PrintQuality.class.equals(category)) {
255: return new PrintQuality[] { PrintQuality.HIGH,
256: PrintQuality.NORMAL, PrintQuality.DRAFT };
257: }
258: } catch (final PrintException ex) {
259: throw new RuntimeException(ex);
260: }
261:
262: return null;
263: }
264:
265: public DocFlavor[] getSupportedDocFlavors() {
266: return SUPPORTED_FLAVORS;
267: }
268:
269: public AttributeSet getUnsupportedAttributes(
270: final DocFlavor flavor, final AttributeSet attributes) {
271: checkFlavor(flavor);
272:
273: if (attributes == null) {
274: return null;
275: }
276:
277: final AttributeSet result = new HashAttributeSet();
278:
279: for (Attribute attr : attributes.toArray()) {
280: if (!isAttributeValueSupported(attr, flavor, attributes)) {
281: result.add(attr);
282: }
283: }
284:
285: return result.size() > 0 ? result : null;
286: }
287:
288: public boolean isAttributeCategorySupported(
289: final Class<? extends Attribute> category) {
290: checkArgs(category, null);
291: return arrayContains(SUPPORTED_ATTR_CATS, category);
292: }
293:
294: public boolean isAttributeValueSupported(final Attribute attrval,
295: final DocFlavor flavor, final AttributeSet attributes) {
296: checkFlavor(flavor);
297:
298: final Class<? extends Attribute> category = attrval
299: .getCategory();
300:
301: try {
302: if (Copies.class.equals(category)) {
303: int max = WinPrinterFactory
304: .getMaxNumberOfCopies(getPrinterHandle());
305: return max <= 0 ? ((Copies) attrval).getValue() == 1
306: : ((Copies) attrval).getValue() <= max;
307: }
308: } catch (final PrintException ex) {
309: throw new RuntimeException(ex);
310: }
311:
312: final Object obj = getSupportedAttributeValues(category,
313: flavor, attributes);
314:
315: if (obj != null) {
316: if (obj.getClass().isArray()) {
317: return arrayContains((Object[]) obj, attrval);
318: } else {
319: return obj.equals(attrval);
320: }
321: }
322:
323: return false;
324: }
325:
326: public boolean isDocFlavorSupported(final DocFlavor flavor) {
327: return arrayContains(SUPPORTED_FLAVORS, flavor);
328: }
329:
330: public void removePrintServiceAttributeListener(
331: final PrintServiceAttributeListener listener) {
332: attrListeners.remove(listener);
333: }
334:
335: @Override
336: public boolean equals(final Object object) {
337: return (object instanceof WinPrintService)
338: && ((WinPrintService) object).printerName
339: .equals(printerName);
340: }
341:
342: @Override
343: public String toString() {
344: return getName();
345: }
346:
347: synchronized long getPrinterHandle() {
348: if (pHandle == 0) {
349: try {
350: pHandle = WinPrinterFactory
351: .getPrinterHandle(printerName);
352: } catch (final PrintException ex) {
353: throw new RuntimeException(ex);
354: }
355: }
356:
357: return pHandle;
358: }
359:
360: synchronized DevmodeStructWrapper getPrinterProps() {
361: if (dmStruct == null) {
362: try {
363: dmStruct = new DevmodeStructWrapper(WinPrinterFactory
364: .getPrinterProps(printerName,
365: getPrinterHandle()));
366: } catch (final PrintException ex) {
367: throw new RuntimeException(ex);
368: }
369: }
370:
371: return dmStruct;
372: }
373:
374: synchronized DevmodeStructWrapper getDefaultPrinterProps() {
375: if (defaultDmStruct == null) {
376: try {
377: defaultDmStruct = new DevmodeStructWrapper(
378: WinPrinterFactory.getPrinterProps(printerName,
379: getPrinterHandle()));
380: } catch (final PrintException ex) {
381: throw new RuntimeException(ex);
382: }
383: }
384:
385: return defaultDmStruct;
386: }
387:
388: @Override
389: protected synchronized void finalize() {
390: if (pHandle > 0) {
391: try {
392: WinPrinterFactory.releasePrinterHandle(pHandle);
393: pHandle = 0;
394: dmStruct = null;
395: defaultDmStruct = null;
396: } catch (final PrintException ex) {
397: throw new RuntimeException(ex);
398: }
399: }
400: }
401:
402: private static <T> boolean arrayContains(final T[] array,
403: final T val) {
404: for (T a : array) {
405: if (a.equals(val)) {
406: return true;
407: }
408: }
409: return false;
410: }
411:
412: private static String getSystemProperty(final String name) {
413: return AccessController
414: .doPrivileged(new PrivilegedAction<String>() {
415: public String run() {
416: return System.getProperty(name);
417: }
418: });
419: }
420:
421: private void notifyListeners(final PrintServiceAttribute... attrs) {
422: final PrintServiceAttributeEvent event = new PrintServiceAttributeEvent(
423: this , new HashPrintServiceAttributeSet(attrs));
424: for (PrintServiceAttributeListener listener : attrListeners
425: .keySet()) {
426: listener.attributeUpdate(event);
427: }
428: }
429:
430: private Paper getDefaultPaper() {
431: final Paper p = getDefaultPrinterProps().getPaper();
432: return p != null ? p : StdPaper.ISO_A4;
433: }
434:
435: private void checkFlavor(final DocFlavor flavor) {
436: if ((flavor != null) && !isDocFlavorSupported(flavor)) {
437: throw new IllegalArgumentException("unsupported flavor"); //$NON-NLS-1$
438: }
439: }
440:
441: private void checkArgs(final Class<? extends Attribute> category,
442: final DocFlavor flavor) {
443: if (category == null) {
444: throw new NullPointerException(
445: "category should not be null"); //$NON-NLS-1$
446: }
447:
448: if (!Attribute.class.isAssignableFrom(category)) {
449: throw new IllegalArgumentException(category
450: + " is not assignable from Attribute"); //$NON-NLS-1$
451: }
452:
453: checkFlavor(flavor);
454: }
455: }
|