J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2000-2005 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package javax.print; |
| 27 | |
| 28 | import java.awt.GraphicsConfiguration; |
| 29 | import java.awt.GraphicsDevice; |
| 30 | import java.awt.GraphicsEnvironment; |
| 31 | import java.awt.HeadlessException; |
| 32 | import java.awt.Dialog; |
| 33 | import java.awt.Frame; |
| 34 | import java.awt.Point; |
| 35 | import java.awt.Rectangle; |
| 36 | import java.awt.Window; |
| 37 | import java.awt.KeyboardFocusManager; |
| 38 | import javax.print.attribute.Attribute; |
| 39 | import javax.print.attribute.AttributeSet; |
| 40 | import javax.print.attribute.PrintRequestAttributeSet; |
| 41 | import javax.print.attribute.standard.Destination; |
| 42 | import javax.print.attribute.standard.Fidelity; |
| 43 | |
| 44 | import sun.print.ServiceDialog; |
| 45 | import sun.print.SunAlternateMedia; |
| 46 | |
| 47 | /** This class is a collection of UI convenience methods which provide a |
| 48 | * graphical user dialog for browsing print services looked up through the Java |
| 49 | * Print Service API. |
| 50 | * <p> |
| 51 | * The dialogs follow a standard pattern of acting as a continue/cancel option |
| 52 | *for a user as well as allowing the user to select the print service to use |
| 53 | *and specify choices such as paper size and number of copies. |
| 54 | * <p> |
| 55 | * <p> |
| 56 | * The dialogs are designed to work with pluggable print services though the |
| 57 | * public APIs of those print services. |
| 58 | * <p> |
| 59 | * If a print service provides any vendor extensions these may be made |
| 60 | * accessible to the user through a vendor supplied tab panel Component. |
| 61 | * Such a vendor extension is encouraged to use Swing! and to support its |
| 62 | * accessibility APIs. |
| 63 | * The vendor extensions should return the settings as part of the |
| 64 | * AttributeSet. |
| 65 | * Applications which want to preserve the user settings should use those |
| 66 | * settings to specify the print job. |
| 67 | * Note that this class is not referenced by any other part of the Java |
| 68 | * Print Service and may not be included in profiles which cannot depend |
| 69 | * on the presence of the AWT packages. |
| 70 | */ |
| 71 | |
| 72 | public class ServiceUI { |
| 73 | |
| 74 | |
| 75 | /** |
| 76 | * Presents a dialog to the user for selecting a print service (printer). |
| 77 | * It is displayed at the location specified by the application and |
| 78 | * is modal. |
| 79 | * If the specification is invalid or would make the dialog not visible it |
| 80 | * will be displayed at a location determined by the implementation. |
| 81 | * The dialog blocks its calling thread and is application modal. |
| 82 | * <p> |
| 83 | * The dialog may include a tab panel with custom UI lazily obtained from |
| 84 | * the PrintService's ServiceUIFactory when the PrintService is browsed. |
| 85 | * The dialog will attempt to locate a MAIN_UIROLE first as a JComponent, |
| 86 | * then as a Panel. If there is no ServiceUIFactory or no matching role |
| 87 | * the custom tab will be empty or not visible. |
| 88 | * <p> |
| 89 | * The dialog returns the print service selected by the user if the user |
| 90 | * OK's the dialog and null if the user cancels the dialog. |
| 91 | * <p> |
| 92 | * An application must pass in an array of print services to browse. |
| 93 | * The array must be non-null and non-empty. |
| 94 | * Typically an application will pass in only PrintServices capable |
| 95 | * of printing a particular document flavor. |
| 96 | * <p> |
| 97 | * An application may pass in a PrintService to be initially displayed. |
| 98 | * A non-null parameter must be included in the array of browsable |
| 99 | * services. |
| 100 | * If this parameter is null a service is chosen by the implementation. |
| 101 | * <p> |
| 102 | * An application may optionally pass in the flavor to be printed. |
| 103 | * If this is non-null choices presented to the user can be better |
| 104 | * validated against those supported by the services. |
| 105 | * An application must pass in a PrintRequestAttributeSet for returning |
| 106 | * user choices. |
| 107 | * On calling the PrintRequestAttributeSet may be empty, or may contain |
| 108 | * application-specified values. |
| 109 | * <p> |
| 110 | * These are used to set the initial settings for the initially |
| 111 | * displayed print service. Values which are not supported by the print |
| 112 | * service are ignored. As the user browses print services, attributes |
| 113 | * and values are copied to the new display. If a user browses a |
| 114 | * print service which does not support a particular attribute-value, the |
| 115 | * default for that service is used as the new value to be copied. |
| 116 | * <p> |
| 117 | * If the user cancels the dialog, the returned attributes will not reflect |
| 118 | * any changes made by the user. |
| 119 | * |
| 120 | * A typical basic usage of this method may be : |
| 121 | * <pre> |
| 122 | * PrintService[] services = PrintServiceLookup.lookupPrintServices( |
| 123 | * DocFlavor.INPUT_STREAM.JPEG, null); |
| 124 | * PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet(); |
| 125 | * if (services.length > 0) { |
| 126 | * PrintService service = ServiceUI.printDialog(null, 50, 50, |
| 127 | * services, services[0], |
| 128 | * null, |
| 129 | * attributes); |
| 130 | * if (service != null) { |
| 131 | * ... print ... |
| 132 | * } |
| 133 | * } |
| 134 | * </pre> |
| 135 | * <p> |
| 136 | |
| 137 | * @param gc used to select screen. null means primary or default screen. |
| 138 | * @param x location of dialog including border in screen coordinates |
| 139 | * @param y location of dialog including border in screen coordinates |
| 140 | * @param services to be browsable, must be non-null. |
| 141 | * @param defaultService - initial PrintService to display. |
| 142 | * @param flavor - the flavor to be printed, or null. |
| 143 | * @param attributes on input is the initial application supplied |
| 144 | * preferences. This cannot be null but may be empty. |
| 145 | * On output the attributes reflect changes made by the user. |
| 146 | * @return print service selected by the user, or null if the user |
| 147 | * cancelled the dialog. |
| 148 | * @throws HeadlessException if GraphicsEnvironment.isHeadless() |
| 149 | * returns true. |
| 150 | * @throws IllegalArgumentException if services is null or empty, |
| 151 | * or attributes is null, or the initial PrintService is not in the |
| 152 | * list of browsable services. |
| 153 | */ |
| 154 | public static PrintService printDialog(GraphicsConfiguration gc, |
| 155 | int x, int y, |
| 156 | PrintService[] services, |
| 157 | PrintService defaultService, |
| 158 | DocFlavor flavor, |
| 159 | PrintRequestAttributeSet attributes) |
| 160 | throws HeadlessException |
| 161 | { |
| 162 | int defaultIndex = -1; |
| 163 | |
| 164 | if (GraphicsEnvironment.isHeadless()) { |
| 165 | throw new HeadlessException(); |
| 166 | } else if ((services == null) || (services.length == 0)) { |
| 167 | throw new IllegalArgumentException("services must be non-null " + |
| 168 | "and non-empty"); |
| 169 | } else if (attributes == null) { |
| 170 | throw new IllegalArgumentException("attributes must be non-null"); |
| 171 | } |
| 172 | |
| 173 | if (defaultService != null) { |
| 174 | for (int i = 0; i < services.length; i++) { |
| 175 | if (services[i].equals(defaultService)) { |
| 176 | defaultIndex = i; |
| 177 | break; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | if (defaultIndex < 0) { |
| 182 | throw new IllegalArgumentException("services must contain " + |
| 183 | "defaultService"); |
| 184 | } |
| 185 | } else { |
| 186 | defaultIndex = 0; |
| 187 | } |
| 188 | |
| 189 | // For now we set owner to null. In the future, it may be passed |
| 190 | // as an argument. |
| 191 | Window owner = null; |
| 192 | |
| 193 | Rectangle gcBounds = (gc == null) ? GraphicsEnvironment. |
| 194 | getLocalGraphicsEnvironment().getDefaultScreenDevice(). |
| 195 | getDefaultConfiguration().getBounds() : gc.getBounds(); |
| 196 | |
| 197 | ServiceDialog dialog; |
| 198 | if (owner instanceof Frame) { |
| 199 | dialog = new ServiceDialog(gc, |
| 200 | x + gcBounds.x, |
| 201 | y + gcBounds.y, |
| 202 | services, defaultIndex, |
| 203 | flavor, attributes, |
| 204 | (Frame)owner); |
| 205 | } else { |
| 206 | dialog = new ServiceDialog(gc, |
| 207 | x + gcBounds.x, |
| 208 | y + gcBounds.y, |
| 209 | services, defaultIndex, |
| 210 | flavor, attributes, |
| 211 | (Dialog)owner); |
| 212 | } |
| 213 | Rectangle dlgBounds = dialog.getBounds(); |
| 214 | |
| 215 | // get union of all GC bounds |
| 216 | GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); |
| 217 | GraphicsDevice[] gs = ge.getScreenDevices(); |
| 218 | for (int j=0; j<gs.length; j++) { |
| 219 | gcBounds = |
| 220 | gcBounds.union(gs[j].getDefaultConfiguration().getBounds()); |
| 221 | } |
| 222 | |
| 223 | // if portion of dialog is not within the gc boundary |
| 224 | if (!gcBounds.contains(dlgBounds)) { |
| 225 | // put in the center relative to parent frame/dialog |
| 226 | dialog.setLocationRelativeTo(owner); |
| 227 | } |
| 228 | dialog.show(); |
| 229 | |
| 230 | if (dialog.getStatus() == ServiceDialog.APPROVE) { |
| 231 | PrintRequestAttributeSet newas = dialog.getAttributes(); |
| 232 | Class dstCategory = Destination.class; |
| 233 | Class amCategory = SunAlternateMedia.class; |
| 234 | Class fdCategory = Fidelity.class; |
| 235 | |
| 236 | if (attributes.containsKey(dstCategory) && |
| 237 | !newas.containsKey(dstCategory)) |
| 238 | { |
| 239 | attributes.remove(dstCategory); |
| 240 | } |
| 241 | |
| 242 | if (attributes.containsKey(amCategory) && |
| 243 | !newas.containsKey(amCategory)) |
| 244 | { |
| 245 | attributes.remove(amCategory); |
| 246 | } |
| 247 | |
| 248 | attributes.addAll(newas); |
| 249 | |
| 250 | Fidelity fd = (Fidelity)attributes.get(fdCategory); |
| 251 | if (fd != null) { |
| 252 | if (fd == Fidelity.FIDELITY_TRUE) { |
| 253 | removeUnsupportedAttributes(dialog.getPrintService(), |
| 254 | flavor, attributes); |
| 255 | } |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | return dialog.getPrintService(); |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * POSSIBLE FUTURE API: This method may be used down the road if we |
| 264 | * decide to allow developers to explicitly display a "page setup" dialog. |
| 265 | * Currently we use that functionality internally for the AWT print model. |
| 266 | */ |
| 267 | /* |
| 268 | public static void pageDialog(GraphicsConfiguration gc, |
| 269 | int x, int y, |
| 270 | PrintService service, |
| 271 | DocFlavor flavor, |
| 272 | PrintRequestAttributeSet attributes) |
| 273 | throws HeadlessException |
| 274 | { |
| 275 | if (GraphicsEnvironment.isHeadless()) { |
| 276 | throw new HeadlessException(); |
| 277 | } else if (service == null) { |
| 278 | throw new IllegalArgumentException("service must be non-null"); |
| 279 | } else if (attributes == null) { |
| 280 | throw new IllegalArgumentException("attributes must be non-null"); |
| 281 | } |
| 282 | |
| 283 | ServiceDialog dialog = new ServiceDialog(gc, x, y, service, |
| 284 | flavor, attributes); |
| 285 | dialog.show(); |
| 286 | |
| 287 | if (dialog.getStatus() == ServiceDialog.APPROVE) { |
| 288 | PrintRequestAttributeSet newas = dialog.getAttributes(); |
| 289 | Class amCategory = SunAlternateMedia.class; |
| 290 | |
| 291 | if (attributes.containsKey(amCategory) && |
| 292 | !newas.containsKey(amCategory)) |
| 293 | { |
| 294 | attributes.remove(amCategory); |
| 295 | } |
| 296 | |
| 297 | attributes.addAll(newas.values()); |
| 298 | } |
| 299 | |
| 300 | dialog.getOwner().dispose(); |
| 301 | } |
| 302 | */ |
| 303 | |
| 304 | /** |
| 305 | * Removes any attributes from the given AttributeSet that are |
| 306 | * unsupported by the given PrintService/DocFlavor combination. |
| 307 | */ |
| 308 | private static void removeUnsupportedAttributes(PrintService ps, |
| 309 | DocFlavor flavor, |
| 310 | AttributeSet aset) |
| 311 | { |
| 312 | AttributeSet asUnsupported = ps.getUnsupportedAttributes(flavor, |
| 313 | aset); |
| 314 | |
| 315 | if (asUnsupported != null) { |
| 316 | Attribute[] usAttrs = asUnsupported.toArray(); |
| 317 | |
| 318 | for (int i=0; i<usAttrs.length; i++) { |
| 319 | Class category = usAttrs[i].getCategory(); |
| 320 | |
| 321 | if (ps.isAttributeCategorySupported(category)) { |
| 322 | Attribute attr = |
| 323 | (Attribute)ps.getDefaultAttributeValue(category); |
| 324 | |
| 325 | if (attr != null) { |
| 326 | aset.add(attr); |
| 327 | } else { |
| 328 | aset.remove(category); |
| 329 | } |
| 330 | } else { |
| 331 | aset.remove(category); |
| 332 | } |
| 333 | } |
| 334 | } |
| 335 | } |
| 336 | } |