1 /* 2 * Copyright (c) 2000, 2021, 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.awt.BorderLayout; 29 import java.awt.Color; 30 import java.awt.Component; 31 import java.awt.Container; 32 import java.awt.Dialog; 33 import java.awt.FlowLayout; 34 import java.awt.Frame; 35 import java.awt.GraphicsConfiguration; 36 import java.awt.GridBagLayout; 37 import java.awt.GridBagConstraints; 38 import java.awt.GridLayout; 39 import java.awt.Insets; 40 import java.awt.Toolkit; 41 import java.awt.Window; 42 import java.awt.event.ActionEvent; 43 import java.awt.event.ActionListener; 44 import java.awt.event.FocusEvent; 45 import java.awt.event.FocusListener; 46 import java.awt.event.ItemEvent; 47 import java.awt.event.ItemListener; 48 import java.awt.event.WindowEvent; 49 import java.awt.event.WindowAdapter; 50 import java.awt.print.PrinterJob; 51 import java.io.File; 52 import java.io.FilePermission; 53 import java.io.IOException; 54 import java.net.URI; 55 import java.net.URL; 56 import java.text.DecimalFormat; 57 import java.util.Locale; 58 import java.util.ResourceBundle; 59 import java.util.Vector; 60 import javax.print.*; 61 import javax.print.attribute.*; 62 import javax.print.attribute.standard.*; 63 import javax.swing.*; 64 import javax.swing.border.Border; 65 import javax.swing.border.EmptyBorder; 66 import javax.swing.border.TitledBorder; 67 import javax.swing.event.ChangeEvent; 68 import javax.swing.event.ChangeListener; 69 import javax.swing.event.DocumentEvent; 70 import javax.swing.event.DocumentListener; 71 import javax.swing.event.PopupMenuEvent; 72 import javax.swing.event.PopupMenuListener; 73 import javax.swing.text.NumberFormatter; 74 import sun.print.SunPageSelection; 75 import java.awt.event.KeyEvent; 76 import java.net.URISyntaxException; 77 import java.lang.reflect.Field; 78 import java.net.MalformedURLException; 79 80 /** 81 * A class which implements a cross-platform print dialog. 82 * 83 * @author Chris Campbell 84 */ 85 @SuppressWarnings("serial") // Superclass is not serializable across versions 86 public class ServiceDialog extends JDialog implements ActionListener { 87 88 /** 89 * Waiting print status (user response pending). 90 */ 91 public static final int WAITING = 0; 92 93 /** 94 * Approve print status (user activated "Print" or "OK"). 95 */ 96 public static final int APPROVE = 1; 97 98 /** 99 * Cancel print status (user activated "Cancel"); 100 */ 101 public static final int CANCEL = 2; 102 103 private static final String strBundle = "sun.print.resources.serviceui"; 104 private static final Insets panelInsets = new Insets(6, 6, 6, 6); 105 private static final Insets compInsets = new Insets(3, 6, 3, 6); 106 107 private static ResourceBundle messageRB; 108 private JTabbedPane tpTabs; 109 private JButton btnCancel, btnApprove; 110 private PrintService[] services; 111 private int defaultServiceIndex; 112 private PrintRequestAttributeSet asOriginal; 113 private HashPrintRequestAttributeSet asCurrent; 114 private PrintService psCurrent; 115 private DocFlavor docFlavor; 116 private int status; 117 118 private ValidatingFileChooser jfc; 119 120 private GeneralPanel pnlGeneral; 121 private PageSetupPanel pnlPageSetup; 122 private AppearancePanel pnlAppearance; 123 124 private boolean isAWT = false; 125 static { initResource()126 initResource(); 127 } 128 129 130 /** 131 * Constructor for the "standard" print dialog (containing all relevant 132 * tabs) 133 */ ServiceDialog(GraphicsConfiguration gc, int x, int y, PrintService[] services, int defaultServiceIndex, DocFlavor flavor, PrintRequestAttributeSet attributes, Window window)134 public ServiceDialog(GraphicsConfiguration gc, 135 int x, int y, 136 PrintService[] services, 137 int defaultServiceIndex, 138 DocFlavor flavor, 139 PrintRequestAttributeSet attributes, 140 Window window) 141 { 142 super(window, getMsg("dialog.printtitle"), Dialog.DEFAULT_MODALITY_TYPE, gc); 143 initPrintDialog(x, y, services, defaultServiceIndex, 144 flavor, attributes); 145 } 146 147 /** 148 * Initialize print dialog. 149 */ initPrintDialog(int x, int y, PrintService[] services, int defaultServiceIndex, DocFlavor flavor, PrintRequestAttributeSet attributes)150 void initPrintDialog(int x, int y, 151 PrintService[] services, 152 int defaultServiceIndex, 153 DocFlavor flavor, 154 PrintRequestAttributeSet attributes) 155 { 156 this.services = services; 157 this.defaultServiceIndex = defaultServiceIndex; 158 this.asOriginal = attributes; 159 this.asCurrent = new HashPrintRequestAttributeSet(attributes); 160 this.psCurrent = services[defaultServiceIndex]; 161 this.docFlavor = flavor; 162 SunPageSelection pages = 163 (SunPageSelection)attributes.get(SunPageSelection.class); 164 if (pages != null) { 165 isAWT = true; 166 } 167 168 if (attributes.get(DialogOwner.class) != null) { 169 DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class); 170 /* When the ServiceDialog is constructed the caller of the 171 * constructor checks for this attribute and if it specifies a 172 * window then it will use that in the constructor instead of 173 * inferring one from keyboard focus. 174 * In this case the owner of the dialog is the same as that 175 * specified in the attribute and we do not need to set the 176 * on top property 177 */ 178 if ((getOwner() == null) || (owner.getOwner() != getOwner())) { 179 try { 180 setAlwaysOnTop(true); 181 } catch (SecurityException e) { 182 } 183 } 184 } 185 Container c = getContentPane(); 186 c.setLayout(new BorderLayout()); 187 188 tpTabs = new JTabbedPane(); 189 tpTabs.setBorder(new EmptyBorder(5, 5, 5, 5)); 190 191 String gkey = getMsg("tab.general"); 192 int gmnemonic = getVKMnemonic("tab.general"); 193 pnlGeneral = new GeneralPanel(); 194 tpTabs.add(gkey, pnlGeneral); 195 tpTabs.setMnemonicAt(0, gmnemonic); 196 197 String pkey = getMsg("tab.pagesetup"); 198 int pmnemonic = getVKMnemonic("tab.pagesetup"); 199 pnlPageSetup = new PageSetupPanel(); 200 tpTabs.add(pkey, pnlPageSetup); 201 tpTabs.setMnemonicAt(1, pmnemonic); 202 203 String akey = getMsg("tab.appearance"); 204 int amnemonic = getVKMnemonic("tab.appearance"); 205 pnlAppearance = new AppearancePanel(); 206 tpTabs.add(akey, pnlAppearance); 207 tpTabs.setMnemonicAt(2, amnemonic); 208 209 c.add(tpTabs, BorderLayout.CENTER); 210 211 updatePanels(); 212 213 JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING)); 214 btnApprove = createExitButton("button.print", this); 215 pnlSouth.add(btnApprove); 216 getRootPane().setDefaultButton(btnApprove); 217 btnCancel = createExitButton("button.cancel", this); 218 handleEscKey(btnCancel); 219 pnlSouth.add(btnCancel); 220 c.add(pnlSouth, BorderLayout.SOUTH); 221 222 addWindowListener(new WindowAdapter() { 223 public void windowClosing(WindowEvent event) { 224 dispose(CANCEL); 225 } 226 }); 227 228 getAccessibleContext().setAccessibleDescription(getMsg("dialog.printtitle")); 229 setResizable(false); 230 setLocation(x, y); 231 pack(); 232 } 233 234 /** 235 * Constructor for the solitary "page setup" dialog 236 */ ServiceDialog(GraphicsConfiguration gc, int x, int y, PrintService ps, DocFlavor flavor, PrintRequestAttributeSet attributes, Window window)237 public ServiceDialog(GraphicsConfiguration gc, 238 int x, int y, 239 PrintService ps, 240 DocFlavor flavor, 241 PrintRequestAttributeSet attributes, 242 Window window) 243 { 244 super(window, getMsg("dialog.pstitle"), Dialog.DEFAULT_MODALITY_TYPE, gc); 245 initPageDialog(x, y, ps, flavor, attributes); 246 } 247 248 /** 249 * Initialize "page setup" dialog 250 */ initPageDialog(int x, int y, PrintService ps, DocFlavor flavor, PrintRequestAttributeSet attributes)251 void initPageDialog(int x, int y, 252 PrintService ps, 253 DocFlavor flavor, 254 PrintRequestAttributeSet attributes) 255 { 256 this.psCurrent = ps; 257 this.docFlavor = flavor; 258 this.asOriginal = attributes; 259 this.asCurrent = new HashPrintRequestAttributeSet(attributes); 260 261 if (attributes.get(DialogOwner.class) != null) { 262 /* See comments in same block in initPrintDialog */ 263 DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class); 264 if ((getOwner() == null) || (owner.getOwner() != getOwner())) { 265 try { 266 setAlwaysOnTop(true); 267 } catch (SecurityException e) { 268 } 269 } 270 } 271 272 Container c = getContentPane(); 273 c.setLayout(new BorderLayout()); 274 275 pnlPageSetup = new PageSetupPanel(); 276 c.add(pnlPageSetup, BorderLayout.CENTER); 277 278 pnlPageSetup.updateInfo(); 279 280 JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING)); 281 btnApprove = createExitButton("button.ok", this); 282 pnlSouth.add(btnApprove); 283 getRootPane().setDefaultButton(btnApprove); 284 btnCancel = createExitButton("button.cancel", this); 285 handleEscKey(btnCancel); 286 pnlSouth.add(btnCancel); 287 c.add(pnlSouth, BorderLayout.SOUTH); 288 289 addWindowListener(new WindowAdapter() { 290 public void windowClosing(WindowEvent event) { 291 dispose(CANCEL); 292 } 293 }); 294 295 getAccessibleContext().setAccessibleDescription(getMsg("dialog.pstitle")); 296 setResizable(false); 297 setLocation(x, y); 298 pack(); 299 } 300 301 /** 302 * Performs Cancel when Esc key is pressed. 303 */ handleEscKey(JButton btnCancel)304 private void handleEscKey(JButton btnCancel) { 305 @SuppressWarnings("serial") // anonymous class 306 Action cancelKeyAction = new AbstractAction() { 307 public void actionPerformed(ActionEvent e) { 308 dispose(CANCEL); 309 } 310 }; 311 KeyStroke cancelKeyStroke = 312 KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE, 0); 313 InputMap inputMap = 314 btnCancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 315 ActionMap actionMap = btnCancel.getActionMap(); 316 317 if (inputMap != null && actionMap != null) { 318 inputMap.put(cancelKeyStroke, "cancel"); 319 actionMap.put("cancel", cancelKeyAction); 320 } 321 } 322 323 324 /** 325 * Returns the current status of the dialog (whether the user has selected 326 * the "Print" or "Cancel" button) 327 */ getStatus()328 public int getStatus() { 329 return status; 330 } 331 332 /** 333 * Returns an AttributeSet based on whether or not the user cancelled the 334 * dialog. If the user selected "Print" we return their new selections, 335 * otherwise we return the attributes that were passed in initially. 336 */ getAttributes()337 public PrintRequestAttributeSet getAttributes() { 338 if (status == APPROVE) { 339 return asCurrent; 340 } else { 341 return asOriginal; 342 } 343 } 344 345 /** 346 * Returns a PrintService based on whether or not the user cancelled the 347 * dialog. If the user selected "Print" we return the user's selection 348 * for the PrintService, otherwise we return null. 349 */ getPrintService()350 public PrintService getPrintService() { 351 if (status == APPROVE) { 352 return psCurrent; 353 } else { 354 return null; 355 } 356 } 357 358 /** 359 * Sets the current status flag for the dialog and disposes it (thus 360 * returning control of the parent frame back to the user) 361 */ dispose(int status)362 public void dispose(int status) { 363 this.status = status; 364 365 super.dispose(); 366 } 367 actionPerformed(ActionEvent e)368 public void actionPerformed(ActionEvent e) { 369 Object source = e.getSource(); 370 boolean approved = false; 371 372 if (source == btnApprove) { 373 approved = true; 374 375 if (pnlGeneral != null) { 376 if (pnlGeneral.isPrintToFileRequested()) { 377 approved = showFileChooser(); 378 } else { 379 asCurrent.remove(Destination.class); 380 } 381 } 382 } 383 384 dispose(approved ? APPROVE : CANCEL); 385 } 386 387 /** 388 * Displays a JFileChooser that allows the user to select the destination 389 * for "Print To File" 390 */ showFileChooser()391 private boolean showFileChooser() { 392 Class<Destination> dstCategory = Destination.class; 393 394 Destination dst = (Destination)asCurrent.get(dstCategory); 395 if (dst == null) { 396 dst = (Destination)asOriginal.get(dstCategory); 397 if (dst == null) { 398 dst = (Destination)psCurrent.getDefaultAttributeValue(dstCategory); 399 // "dst" should not be null. The following code 400 // is only added to safeguard against a possible 401 // buggy implementation of a PrintService having a 402 // null default Destination. 403 if (dst == null) { 404 try { 405 dst = new Destination(new URI("file:out.prn")); 406 } catch (URISyntaxException e) { 407 } 408 } 409 } 410 } 411 412 File fileDest; 413 if (dst != null) { 414 try { 415 fileDest = new File(dst.getURI()); 416 } catch (Exception e) { 417 // all manner of runtime exceptions possible 418 fileDest = new File("out.prn"); 419 } 420 } else { 421 fileDest = new File("out.prn"); 422 } 423 424 ValidatingFileChooser jfc = new ValidatingFileChooser(); 425 jfc.setApproveButtonText(getMsg("button.ok")); 426 jfc.setDialogTitle(getMsg("dialog.printtofile")); 427 jfc.setDialogType(JFileChooser.SAVE_DIALOG); 428 jfc.setSelectedFile(fileDest); 429 430 int returnVal = jfc.showDialog(this, null); 431 if (returnVal == JFileChooser.APPROVE_OPTION) { 432 fileDest = jfc.getSelectedFile(); 433 434 try { 435 asCurrent.add(new Destination(fileDest.toURI())); 436 } catch (Exception e) { 437 asCurrent.remove(dstCategory); 438 } 439 } else { 440 asCurrent.remove(dstCategory); 441 } 442 443 return (returnVal == JFileChooser.APPROVE_OPTION); 444 } 445 446 /** 447 * Updates each of the top level panels 448 */ updatePanels()449 private void updatePanels() { 450 pnlGeneral.updateInfo(); 451 pnlPageSetup.updateInfo(); 452 pnlAppearance.updateInfo(); 453 } 454 455 /** 456 * Initialize ResourceBundle 457 */ 458 @SuppressWarnings("removal") initResource()459 public static void initResource() { 460 java.security.AccessController.doPrivileged( 461 new java.security.PrivilegedAction<Object>() { 462 public Object run() { 463 try { 464 messageRB = ResourceBundle.getBundle(strBundle); 465 return null; 466 } catch (java.util.MissingResourceException e) { 467 throw new Error("Fatal: Resource for ServiceUI " + 468 "is missing"); 469 } 470 } 471 } 472 ); 473 } 474 475 /** 476 * Returns message string from resource 477 */ getMsg(String key)478 public static String getMsg(String key) { 479 try { 480 return removeMnemonics(messageRB.getString(key)); 481 } catch (java.util.MissingResourceException e) { 482 throw new Error("Fatal: Resource for ServiceUI is broken; " + 483 "there is no " + key + " key in resource"); 484 } 485 } 486 removeMnemonics(String s)487 private static String removeMnemonics(String s) { 488 int i = s.indexOf('&'); 489 int len = s.length(); 490 if (i < 0 || i == (len - 1)) { 491 return s; 492 } 493 int j = s.indexOf('&', i+1); 494 if (j == i+1) { 495 if (j+1 == len) { 496 return s.substring(0, i+1); // string ends with && 497 } else { 498 return s.substring(0, i+1) + removeMnemonics(s.substring(j+1)); 499 } 500 } 501 // ok first & not double && 502 if (i == 0) { 503 return removeMnemonics(s.substring(1)); 504 } else { 505 return (s.substring(0, i) + removeMnemonics(s.substring(i+1))); 506 } 507 } 508 509 510 /** 511 * Returns mnemonic character from resource 512 */ getMnemonic(String key)513 private static char getMnemonic(String key) { 514 String str = messageRB.getString(key).replace("&&", ""); 515 int index = str.indexOf('&'); 516 if (0 <= index && index < str.length() - 1) { 517 char c = str.charAt(index + 1); 518 return Character.toUpperCase(c); 519 } else { 520 return (char)0; 521 } 522 } 523 524 /** 525 * Returns the mnemonic as a KeyEvent.VK constant from the resource. 526 */ 527 static Class<?> _keyEventClazz = null; getVKMnemonic(String key)528 private static int getVKMnemonic(String key) { 529 String s = String.valueOf(getMnemonic(key)); 530 if ( s == null || s.length() != 1) { 531 return 0; 532 } 533 String vkString = "VK_" + s.toUpperCase(); 534 535 try { 536 if (_keyEventClazz == null) { 537 _keyEventClazz= Class.forName("java.awt.event.KeyEvent", 538 true, (ServiceDialog.class).getClassLoader()); 539 } 540 Field field = _keyEventClazz.getDeclaredField(vkString); 541 int value = field.getInt(null); 542 return value; 543 } catch (Exception e) { 544 } 545 return 0; 546 } 547 548 /** 549 * Returns URL for image resource 550 */ getImageResource(final String key)551 private static URL getImageResource(final String key) { 552 @SuppressWarnings("removal") 553 URL url = java.security.AccessController.doPrivileged( 554 new java.security.PrivilegedAction<URL>() { 555 public URL run() { 556 URL url = ServiceDialog.class.getResource( 557 "resources/" + key); 558 return url; 559 } 560 }); 561 562 if (url == null) { 563 throw new Error("Fatal: Resource for ServiceUI is broken; " + 564 "there is no " + key + " key in resource"); 565 } 566 567 return url; 568 } 569 570 /** 571 * Creates a new JButton and sets its text, mnemonic, and ActionListener 572 */ createButton(String key, ActionListener al)573 private static JButton createButton(String key, ActionListener al) { 574 JButton btn = new JButton(getMsg(key)); 575 btn.setMnemonic(getMnemonic(key)); 576 btn.addActionListener(al); 577 578 return btn; 579 } 580 581 /** 582 * Creates a new JButton and sets its text, and ActionListener 583 */ createExitButton(String key, ActionListener al)584 private static JButton createExitButton(String key, ActionListener al) { 585 String str = getMsg(key); 586 JButton btn = new JButton(str); 587 btn.addActionListener(al); 588 btn.getAccessibleContext().setAccessibleDescription(str); 589 return btn; 590 } 591 592 /** 593 * Creates a new JCheckBox and sets its text, mnemonic, and ActionListener 594 */ createCheckBox(String key, ActionListener al)595 private static JCheckBox createCheckBox(String key, ActionListener al) { 596 JCheckBox cb = new JCheckBox(getMsg(key)); 597 cb.setMnemonic(getMnemonic(key)); 598 cb.addActionListener(al); 599 600 return cb; 601 } 602 603 /** 604 * Creates a new JRadioButton and sets its text, mnemonic, 605 * and ActionListener 606 */ createRadioButton(String key, ActionListener al)607 private static JRadioButton createRadioButton(String key, 608 ActionListener al) 609 { 610 JRadioButton rb = new JRadioButton(getMsg(key)); 611 rb.setMnemonic(getMnemonic(key)); 612 rb.addActionListener(al); 613 614 return rb; 615 } 616 617 /** 618 * Creates a pop-up dialog for "no print service" 619 */ showNoPrintService(GraphicsConfiguration gc)620 public static void showNoPrintService(GraphicsConfiguration gc) 621 { 622 Frame dlgFrame = new Frame(gc); 623 JOptionPane.showMessageDialog(dlgFrame, 624 getMsg("dialog.noprintermsg")); 625 dlgFrame.dispose(); 626 } 627 628 /** 629 * Sets the constraints for the GridBagLayout and adds the Component 630 * to the given Container 631 */ addToGB(Component comp, Container cont, GridBagLayout gridbag, GridBagConstraints constraints)632 private static void addToGB(Component comp, Container cont, 633 GridBagLayout gridbag, 634 GridBagConstraints constraints) 635 { 636 gridbag.setConstraints(comp, constraints); 637 cont.add(comp); 638 } 639 640 /** 641 * Adds the AbstractButton to both the given ButtonGroup and Container 642 */ addToBG(AbstractButton button, Container cont, ButtonGroup bg)643 private static void addToBG(AbstractButton button, Container cont, 644 ButtonGroup bg) 645 { 646 bg.add(button); 647 cont.add(button); 648 } 649 650 651 652 653 /** 654 * The "General" tab. Includes the controls for PrintService, 655 * PageRange, and Copies/Collate. 656 */ 657 @SuppressWarnings("serial") // Superclass is not serializable across versions 658 private class GeneralPanel extends JPanel { 659 660 private PrintServicePanel pnlPrintService; 661 private PrintRangePanel pnlPrintRange; 662 private CopiesPanel pnlCopies; 663 GeneralPanel()664 public GeneralPanel() { 665 super(); 666 667 GridBagLayout gridbag = new GridBagLayout(); 668 GridBagConstraints c = new GridBagConstraints(); 669 670 setLayout(gridbag); 671 672 c.fill = GridBagConstraints.BOTH; 673 c.insets = panelInsets; 674 c.weightx = 1.0; 675 c.weighty = 1.0; 676 677 c.gridwidth = GridBagConstraints.REMAINDER; 678 pnlPrintService = new PrintServicePanel(); 679 addToGB(pnlPrintService, this, gridbag, c); 680 681 c.gridwidth = GridBagConstraints.RELATIVE; 682 pnlPrintRange = new PrintRangePanel(); 683 addToGB(pnlPrintRange, this, gridbag, c); 684 685 c.gridwidth = GridBagConstraints.REMAINDER; 686 pnlCopies = new CopiesPanel(); 687 addToGB(pnlCopies, this, gridbag, c); 688 } 689 isPrintToFileRequested()690 public boolean isPrintToFileRequested() { 691 return (pnlPrintService.isPrintToFileSelected()); 692 } 693 updateInfo()694 public void updateInfo() { 695 pnlPrintService.updateInfo(); 696 pnlPrintRange.updateInfo(); 697 pnlCopies.updateInfo(); 698 } 699 } 700 701 @SuppressWarnings("serial") // Superclass is not serializable across versions 702 private class PrintServicePanel extends JPanel 703 implements ActionListener, ItemListener, PopupMenuListener 704 { 705 private final String strTitle = getMsg("border.printservice"); 706 private FilePermission printToFilePermission; 707 private JButton btnProperties; 708 private JCheckBox cbPrintToFile; 709 private JComboBox<String> cbName; 710 private JLabel lblType, lblStatus, lblInfo; 711 private ServiceUIFactory uiFactory; 712 private boolean changedService = false; 713 private boolean filePermission; 714 PrintServicePanel()715 public PrintServicePanel() { 716 super(); 717 718 uiFactory = psCurrent.getServiceUIFactory(); 719 720 GridBagLayout gridbag = new GridBagLayout(); 721 GridBagConstraints c = new GridBagConstraints(); 722 723 setLayout(gridbag); 724 setBorder(BorderFactory.createTitledBorder(strTitle)); 725 726 String[] psnames = new String[services.length]; 727 for (int i = 0; i < psnames.length; i++) { 728 psnames[i] = services[i].getName(); 729 } 730 cbName = new JComboBox<>(psnames); 731 cbName.setSelectedIndex(defaultServiceIndex); 732 cbName.addItemListener(this); 733 cbName.addPopupMenuListener(this); 734 735 c.fill = GridBagConstraints.BOTH; 736 c.insets = compInsets; 737 738 c.weightx = 0.0; 739 JLabel lblName = new JLabel(getMsg("label.psname"), JLabel.TRAILING); 740 lblName.setDisplayedMnemonic(getMnemonic("label.psname")); 741 lblName.setLabelFor(cbName); 742 addToGB(lblName, this, gridbag, c); 743 c.weightx = 1.0; 744 c.gridwidth = GridBagConstraints.RELATIVE; 745 addToGB(cbName, this, gridbag, c); 746 c.weightx = 0.0; 747 c.gridwidth = GridBagConstraints.REMAINDER; 748 btnProperties = createButton("button.properties", this); 749 addToGB(btnProperties, this, gridbag, c); 750 751 c.weighty = 1.0; 752 lblStatus = addLabel(getMsg("label.status"), gridbag, c); 753 lblStatus.setLabelFor(null); 754 755 lblType = addLabel(getMsg("label.pstype"), gridbag, c); 756 lblType.setLabelFor(null); 757 758 c.gridwidth = 1; 759 addToGB(new JLabel(getMsg("label.info"), JLabel.TRAILING), 760 this, gridbag, c); 761 c.gridwidth = GridBagConstraints.RELATIVE; 762 lblInfo = new JLabel(); 763 lblInfo.setLabelFor(null); 764 765 addToGB(lblInfo, this, gridbag, c); 766 767 c.gridwidth = GridBagConstraints.REMAINDER; 768 cbPrintToFile = createCheckBox("checkbox.printtofile", this); 769 addToGB(cbPrintToFile, this, gridbag, c); 770 771 filePermission = allowedToPrintToFile(); 772 } 773 isPrintToFileSelected()774 public boolean isPrintToFileSelected() { 775 return cbPrintToFile.isSelected(); 776 } 777 addLabel(String text, GridBagLayout gridbag, GridBagConstraints c)778 private JLabel addLabel(String text, 779 GridBagLayout gridbag, GridBagConstraints c) 780 { 781 c.gridwidth = 1; 782 addToGB(new JLabel(text, JLabel.TRAILING), this, gridbag, c); 783 784 c.gridwidth = GridBagConstraints.REMAINDER; 785 JLabel label = new JLabel(); 786 addToGB(label, this, gridbag, c); 787 788 return label; 789 } 790 791 @SuppressWarnings("deprecation") actionPerformed(ActionEvent e)792 public void actionPerformed(ActionEvent e) { 793 Object source = e.getSource(); 794 795 if (source == btnProperties) { 796 if (uiFactory != null) { 797 JDialog dialog = (JDialog)uiFactory.getUI( 798 ServiceUIFactory.MAIN_UIROLE, 799 ServiceUIFactory.JDIALOG_UI); 800 801 if (dialog != null) { 802 dialog.show(); 803 } else { 804 DocumentPropertiesUI docPropertiesUI = null; 805 try { 806 docPropertiesUI = 807 (DocumentPropertiesUI)uiFactory.getUI 808 (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE, 809 DocumentPropertiesUI.DOCPROPERTIESCLASSNAME); 810 } catch (Exception ex) { 811 } 812 if (docPropertiesUI != null) { 813 PrinterJobWrapper wrapper = (PrinterJobWrapper) 814 asCurrent.get(PrinterJobWrapper.class); 815 if (wrapper == null) { 816 return; // should not happen, defensive only. 817 } 818 PrinterJob job = wrapper.getPrinterJob(); 819 if (job == null) { 820 return; // should not happen, defensive only. 821 } 822 PrintRequestAttributeSet newAttrs = 823 docPropertiesUI.showDocumentProperties 824 (job, ServiceDialog.this, psCurrent, asCurrent); 825 if (newAttrs != null) { 826 asCurrent.addAll(newAttrs); 827 updatePanels(); 828 } 829 } 830 } 831 } 832 } 833 } 834 itemStateChanged(ItemEvent e)835 public void itemStateChanged(ItemEvent e) { 836 if (e.getStateChange() == ItemEvent.SELECTED) { 837 int index = cbName.getSelectedIndex(); 838 839 if ((index >= 0) && (index < services.length)) { 840 if (!services[index].equals(psCurrent)) { 841 psCurrent = services[index]; 842 uiFactory = psCurrent.getServiceUIFactory(); 843 changedService = true; 844 845 Destination dest = 846 (Destination)asOriginal.get(Destination.class); 847 // to preserve the state of Print To File 848 if ((dest != null || isPrintToFileSelected()) 849 && psCurrent.isAttributeCategorySupported( 850 Destination.class)) { 851 852 if (dest != null) { 853 asCurrent.add(dest); 854 } else { 855 dest = (Destination)psCurrent. 856 getDefaultAttributeValue(Destination.class); 857 // "dest" should not be null. The following code 858 // is only added to safeguard against a possible 859 // buggy implementation of a PrintService having a 860 // null default Destination. 861 if (dest == null) { 862 try { 863 dest = 864 new Destination(new URI("file:out.prn")); 865 } catch (URISyntaxException ue) { 866 } 867 } 868 869 if (dest != null) { 870 asCurrent.add(dest); 871 } 872 } 873 } else { 874 asCurrent.remove(Destination.class); 875 } 876 } 877 } 878 } 879 } 880 popupMenuWillBecomeVisible(PopupMenuEvent e)881 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 882 changedService = false; 883 } 884 popupMenuWillBecomeInvisible(PopupMenuEvent e)885 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 886 if (changedService) { 887 changedService = false; 888 updatePanels(); 889 } 890 } 891 popupMenuCanceled(PopupMenuEvent e)892 public void popupMenuCanceled(PopupMenuEvent e) { 893 } 894 895 /** 896 * We disable the "Print To File" checkbox if this returns false 897 */ allowedToPrintToFile()898 private boolean allowedToPrintToFile() { 899 try { 900 throwPrintToFile(); 901 return true; 902 } catch (SecurityException e) { 903 return false; 904 } 905 } 906 907 /** 908 * Break this out as it may be useful when we allow API to 909 * specify printing to a file. In that case its probably right 910 * to throw a SecurityException if the permission is not granted. 911 */ throwPrintToFile()912 private void throwPrintToFile() { 913 @SuppressWarnings("removal") 914 SecurityManager security = System.getSecurityManager(); 915 if (security != null) { 916 if (printToFilePermission == null) { 917 printToFilePermission = 918 new FilePermission("<<ALL FILES>>", "read,write"); 919 } 920 security.checkPermission(printToFilePermission); 921 } 922 } 923 updateInfo()924 public void updateInfo() { 925 Class<Destination> dstCategory = Destination.class; 926 boolean dstSupported = false; 927 boolean dstSelected = false; 928 boolean dstAllowed = filePermission ? 929 allowedToPrintToFile() : false; 930 931 // setup Destination (print-to-file) widgets 932 Destination dst = (Destination)asCurrent.get(dstCategory); 933 if (dst != null) { 934 try { 935 dst.getURI().toURL(); 936 if (psCurrent.isAttributeValueSupported(dst, docFlavor, 937 asCurrent)) { 938 dstSupported = true; 939 dstSelected = true; 940 } 941 } catch (MalformedURLException ex) { 942 dstSupported = true; 943 } 944 } else { 945 if (psCurrent.isAttributeCategorySupported(dstCategory)) { 946 dstSupported = true; 947 } 948 } 949 cbPrintToFile.setEnabled(dstSupported && dstAllowed); 950 cbPrintToFile.setSelected(dstSelected && dstAllowed 951 && dstSupported); 952 953 // setup PrintService information widgets 954 Attribute type = psCurrent.getAttribute(PrinterMakeAndModel.class); 955 if (type != null) { 956 lblType.setText(type.toString()); 957 } 958 Attribute status = 959 psCurrent.getAttribute(PrinterIsAcceptingJobs.class); 960 if (status != null) { 961 lblStatus.setText(getMsg(status.toString())); 962 } 963 Attribute info = psCurrent.getAttribute(PrinterInfo.class); 964 if (info != null) { 965 lblInfo.setText(info.toString()); 966 } 967 PrinterJob job = null; 968 PrinterJobWrapper wrapper = (PrinterJobWrapper) 969 asCurrent.get(PrinterJobWrapper.class); 970 if (wrapper != null) { 971 job = wrapper.getPrinterJob(); 972 } 973 btnProperties.setEnabled(uiFactory != null && job != null); 974 } 975 } 976 977 @SuppressWarnings("serial") // Superclass is not serializable across versions 978 private class PrintRangePanel extends JPanel 979 implements ActionListener, FocusListener 980 { 981 private final String strTitle = getMsg("border.printrange"); 982 private final PageRanges prAll = new PageRanges(1, Integer.MAX_VALUE); 983 private JRadioButton rbAll, rbPages, rbSelect; 984 private JFormattedTextField tfRangeFrom, tfRangeTo; 985 private JLabel lblRangeTo; 986 private boolean prSupported; 987 private boolean prPgRngSupported; 988 PrintRangePanel()989 public PrintRangePanel() { 990 super(); 991 992 GridBagLayout gridbag = new GridBagLayout(); 993 GridBagConstraints c = new GridBagConstraints(); 994 995 setLayout(gridbag); 996 setBorder(BorderFactory.createTitledBorder(strTitle)); 997 998 c.fill = GridBagConstraints.BOTH; 999 c.insets = compInsets; 1000 c.gridwidth = GridBagConstraints.REMAINDER; 1001 1002 ButtonGroup bg = new ButtonGroup(); 1003 JPanel pnlTop = new JPanel(new FlowLayout(FlowLayout.LEADING)); 1004 rbAll = createRadioButton("radiobutton.rangeall", this); 1005 rbAll.setSelected(true); 1006 bg.add(rbAll); 1007 pnlTop.add(rbAll); 1008 addToGB(pnlTop, this, gridbag, c); 1009 1010 // Selection never seemed to work so I'm commenting this part. 1011 /* 1012 if (isAWT) { 1013 JPanel pnlMiddle = 1014 new JPanel(new FlowLayout(FlowLayout.LEADING)); 1015 rbSelect = 1016 createRadioButton("radiobutton.selection", this); 1017 bg.add(rbSelect); 1018 pnlMiddle.add(rbSelect); 1019 addToGB(pnlMiddle, this, gridbag, c); 1020 } 1021 */ 1022 1023 JPanel pnlBottom = new JPanel(new FlowLayout(FlowLayout.LEADING)); 1024 rbPages = createRadioButton("radiobutton.rangepages", this); 1025 bg.add(rbPages); 1026 pnlBottom.add(rbPages); 1027 DecimalFormat format = new DecimalFormat("####0"); 1028 format.setMinimumFractionDigits(0); 1029 format.setMaximumFractionDigits(0); 1030 format.setMinimumIntegerDigits(0); 1031 format.setMaximumIntegerDigits(5); 1032 format.setParseIntegerOnly(true); 1033 format.setDecimalSeparatorAlwaysShown(false); 1034 NumberFormatter nf = new NumberFormatter(format); 1035 nf.setMinimum(1); 1036 nf.setMaximum(Integer.MAX_VALUE); 1037 nf.setAllowsInvalid(true); 1038 nf.setCommitsOnValidEdit(true); 1039 tfRangeFrom = new JFormattedTextField(nf); 1040 tfRangeFrom.setColumns(4); 1041 tfRangeFrom.setEnabled(false); 1042 tfRangeFrom.addActionListener(this); 1043 tfRangeFrom.addFocusListener(this); 1044 tfRangeFrom.setFocusLostBehavior( 1045 JFormattedTextField.PERSIST); 1046 tfRangeFrom.getAccessibleContext().setAccessibleName( 1047 getMsg("radiobutton.rangepages")); 1048 pnlBottom.add(tfRangeFrom); 1049 lblRangeTo = new JLabel(getMsg("label.rangeto")); 1050 lblRangeTo.setEnabled(false); 1051 pnlBottom.add(lblRangeTo); 1052 NumberFormatter nfto; 1053 try { 1054 nfto = (NumberFormatter)nf.clone(); 1055 } catch (CloneNotSupportedException e) { 1056 nfto = new NumberFormatter(); 1057 } 1058 tfRangeTo = new JFormattedTextField(nfto); 1059 tfRangeTo.setColumns(4); 1060 tfRangeTo.setEnabled(false); 1061 tfRangeTo.addFocusListener(this); 1062 tfRangeTo.getAccessibleContext().setAccessibleName( 1063 getMsg("label.rangeto")); 1064 pnlBottom.add(tfRangeTo); 1065 addToGB(pnlBottom, this, gridbag, c); 1066 } 1067 actionPerformed(ActionEvent e)1068 public void actionPerformed(ActionEvent e) { 1069 Object source = e.getSource(); 1070 SunPageSelection select = SunPageSelection.ALL; 1071 1072 setupRangeWidgets(); 1073 1074 if (source == rbAll) { 1075 asCurrent.add(prAll); 1076 } else if (source == rbSelect) { 1077 select = SunPageSelection.SELECTION; 1078 } else if (source == rbPages || 1079 source == tfRangeFrom || 1080 source == tfRangeTo) { 1081 updateRangeAttribute(); 1082 select = SunPageSelection.RANGE; 1083 } 1084 1085 if (isAWT) { 1086 asCurrent.add(select); 1087 } 1088 } 1089 focusLost(FocusEvent e)1090 public void focusLost(FocusEvent e) { 1091 Object source = e.getSource(); 1092 1093 if ((source == tfRangeFrom) || (source == tfRangeTo)) { 1094 updateRangeAttribute(); 1095 } 1096 } 1097 focusGained(FocusEvent e)1098 public void focusGained(FocusEvent e) {} 1099 setupRangeWidgets()1100 private void setupRangeWidgets() { 1101 boolean rangeEnabled = (rbPages.isSelected() && prPgRngSupported); 1102 tfRangeFrom.setEnabled(rangeEnabled); 1103 tfRangeTo.setEnabled(rangeEnabled); 1104 lblRangeTo.setEnabled(rangeEnabled); 1105 } 1106 updateRangeAttribute()1107 private void updateRangeAttribute() { 1108 String strFrom = tfRangeFrom.getText(); 1109 String strTo = tfRangeTo.getText(); 1110 1111 int min; 1112 int max; 1113 1114 try { 1115 min = Integer.parseInt(strFrom); 1116 } catch (NumberFormatException e) { 1117 min = 1; 1118 } 1119 1120 try { 1121 max = Integer.parseInt(strTo); 1122 } catch (NumberFormatException e) { 1123 max = min; 1124 } 1125 1126 if (min < 1) { 1127 min = 1; 1128 tfRangeFrom.setValue(1); 1129 } 1130 1131 if (max < min) { 1132 max = min; 1133 tfRangeTo.setValue(min); 1134 } 1135 1136 PageRanges pr = new PageRanges(min, max); 1137 asCurrent.add(pr); 1138 } 1139 updateInfo()1140 public void updateInfo() { 1141 Class<PageRanges> prCategory = PageRanges.class; 1142 prSupported = false; 1143 1144 if (psCurrent.isAttributeCategorySupported(prCategory) || 1145 isAWT) { 1146 prSupported = true; 1147 prPgRngSupported = psCurrent.isAttributeValueSupported(prAll, 1148 docFlavor, 1149 asCurrent); 1150 } 1151 1152 SunPageSelection select = SunPageSelection.ALL; 1153 int min = 1; 1154 int max = 1; 1155 1156 PageRanges pr = (PageRanges)asCurrent.get(prCategory); 1157 if (pr != null) { 1158 if (!pr.equals(prAll)) { 1159 select = SunPageSelection.RANGE; 1160 1161 int[][] members = pr.getMembers(); 1162 if ((members.length > 0) && 1163 (members[0].length > 1)) { 1164 min = members[0][0]; 1165 max = members[0][1]; 1166 } 1167 } 1168 } 1169 1170 if (isAWT) { 1171 select = (SunPageSelection)asCurrent.get( 1172 SunPageSelection.class); 1173 } 1174 1175 if (select == SunPageSelection.ALL) { 1176 rbAll.setSelected(true); 1177 } else if (select == SunPageSelection.SELECTION) { 1178 // Comment this for now - rbSelect is not initialized 1179 // because Selection button is not added. 1180 // See PrintRangePanel above. 1181 1182 //rbSelect.setSelected(true); 1183 } else { // RANGE 1184 rbPages.setSelected(true); 1185 } 1186 tfRangeFrom.setValue(min); 1187 tfRangeTo.setValue(max); 1188 rbAll.setEnabled(prSupported); 1189 rbPages.setEnabled(prPgRngSupported); 1190 setupRangeWidgets(); 1191 } 1192 } 1193 1194 @SuppressWarnings("serial") // Superclass is not serializable across versions 1195 private class CopiesPanel extends JPanel 1196 implements ActionListener, ChangeListener 1197 { 1198 private final String strTitle = getMsg("border.copies"); 1199 private SpinnerNumberModel snModel; 1200 private JSpinner spinCopies; 1201 private JLabel lblCopies; 1202 private JCheckBox cbCollate; 1203 private boolean scSupported; 1204 CopiesPanel()1205 public CopiesPanel() { 1206 super(); 1207 1208 GridBagLayout gridbag = new GridBagLayout(); 1209 GridBagConstraints c = new GridBagConstraints(); 1210 1211 setLayout(gridbag); 1212 setBorder(BorderFactory.createTitledBorder(strTitle)); 1213 1214 c.fill = GridBagConstraints.HORIZONTAL; 1215 c.insets = compInsets; 1216 1217 lblCopies = new JLabel(getMsg("label.numcopies"), JLabel.TRAILING); 1218 lblCopies.setDisplayedMnemonic(getMnemonic("label.numcopies")); 1219 lblCopies.getAccessibleContext().setAccessibleName( 1220 getMsg("label.numcopies")); 1221 addToGB(lblCopies, this, gridbag, c); 1222 1223 snModel = new SpinnerNumberModel(1, 1, 999, 1); 1224 spinCopies = new JSpinner(snModel); 1225 lblCopies.setLabelFor(spinCopies); 1226 // REMIND 1227 ((JSpinner.NumberEditor)spinCopies.getEditor()).getTextField().setColumns(3); 1228 spinCopies.addChangeListener(this); 1229 c.gridwidth = GridBagConstraints.REMAINDER; 1230 addToGB(spinCopies, this, gridbag, c); 1231 1232 cbCollate = createCheckBox("checkbox.collate", this); 1233 cbCollate.setEnabled(false); 1234 addToGB(cbCollate, this, gridbag, c); 1235 } 1236 actionPerformed(ActionEvent e)1237 public void actionPerformed(ActionEvent e) { 1238 if (cbCollate.isSelected()) { 1239 asCurrent.add(SheetCollate.COLLATED); 1240 } else { 1241 asCurrent.add(SheetCollate.UNCOLLATED); 1242 } 1243 } 1244 stateChanged(ChangeEvent e)1245 public void stateChanged(ChangeEvent e) { 1246 updateCollateCB(); 1247 1248 asCurrent.add(new Copies(snModel.getNumber().intValue())); 1249 } 1250 updateCollateCB()1251 private void updateCollateCB() { 1252 int num = snModel.getNumber().intValue(); 1253 if (isAWT) { 1254 cbCollate.setEnabled(true); 1255 } else { 1256 cbCollate.setEnabled((num > 1) && scSupported); 1257 } 1258 } 1259 updateInfo()1260 public void updateInfo() { 1261 Class<Copies> cpCategory = Copies.class; 1262 Class<SheetCollate> scCategory = SheetCollate.class; 1263 boolean cpSupported = false; 1264 scSupported = false; 1265 1266 // setup Copies spinner 1267 if (psCurrent.isAttributeCategorySupported(cpCategory)) { 1268 cpSupported = true; 1269 } 1270 CopiesSupported cs = 1271 (CopiesSupported)psCurrent.getSupportedAttributeValues( 1272 cpCategory, null, null); 1273 if (cs == null) { 1274 cs = new CopiesSupported(1, 999); 1275 } 1276 Copies cp = (Copies)asCurrent.get(cpCategory); 1277 if (cp == null) { 1278 cp = (Copies)psCurrent.getDefaultAttributeValue(cpCategory); 1279 if (cp == null) { 1280 cp = new Copies(1); 1281 } 1282 } 1283 spinCopies.setEnabled(cpSupported); 1284 lblCopies.setEnabled(cpSupported); 1285 1286 int[][] members = cs.getMembers(); 1287 int min, max; 1288 if ((members.length > 0) && (members[0].length > 0)) { 1289 min = members[0][0]; 1290 max = members[0][1]; 1291 } else { 1292 min = 1; 1293 max = Integer.MAX_VALUE; 1294 } 1295 snModel.setMinimum(min); 1296 snModel.setMaximum(max); 1297 1298 int value = cp.getValue(); 1299 if ((value < min) || (value > max)) { 1300 value = min; 1301 } 1302 snModel.setValue(value); 1303 1304 // setup Collate checkbox 1305 if (psCurrent.isAttributeCategorySupported(scCategory)) { 1306 scSupported = true; 1307 } 1308 SheetCollate sc = (SheetCollate)asCurrent.get(scCategory); 1309 if (sc == null) { 1310 sc = (SheetCollate)psCurrent.getDefaultAttributeValue(scCategory); 1311 if (sc == null) { 1312 sc = SheetCollate.UNCOLLATED; 1313 } 1314 if (sc != null && 1315 !psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { 1316 scSupported = false; 1317 } 1318 } else { 1319 if (!psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { 1320 scSupported = false; 1321 } 1322 } 1323 cbCollate.setSelected(sc == SheetCollate.COLLATED && scSupported); 1324 updateCollateCB(); 1325 } 1326 } 1327 1328 1329 1330 1331 /** 1332 * The "Page Setup" tab. Includes the controls for MediaSource/MediaTray, 1333 * OrientationRequested, and Sides. 1334 */ 1335 @SuppressWarnings("serial") // Superclass is not serializable across versions 1336 private class PageSetupPanel extends JPanel { 1337 1338 private MediaPanel pnlMedia; 1339 private OrientationPanel pnlOrientation; 1340 private MarginsPanel pnlMargins; 1341 PageSetupPanel()1342 public PageSetupPanel() { 1343 super(); 1344 1345 GridBagLayout gridbag = new GridBagLayout(); 1346 GridBagConstraints c = new GridBagConstraints(); 1347 1348 setLayout(gridbag); 1349 1350 c.fill = GridBagConstraints.BOTH; 1351 c.insets = panelInsets; 1352 c.weightx = 1.0; 1353 c.weighty = 1.0; 1354 1355 c.gridwidth = GridBagConstraints.REMAINDER; 1356 pnlMedia = new MediaPanel(); 1357 addToGB(pnlMedia, this, gridbag, c); 1358 1359 pnlOrientation = new OrientationPanel(); 1360 c.gridwidth = GridBagConstraints.RELATIVE; 1361 addToGB(pnlOrientation, this, gridbag, c); 1362 1363 pnlMargins = new MarginsPanel(); 1364 pnlOrientation.addOrientationListener(pnlMargins); 1365 pnlMedia.addMediaListener(pnlMargins); 1366 c.gridwidth = GridBagConstraints.REMAINDER; 1367 addToGB(pnlMargins, this, gridbag, c); 1368 } 1369 updateInfo()1370 public void updateInfo() { 1371 pnlMedia.updateInfo(); 1372 pnlOrientation.updateInfo(); 1373 pnlMargins.updateInfo(); 1374 } 1375 } 1376 1377 @SuppressWarnings("serial") // Superclass is not serializable across versions 1378 private class MarginsPanel extends JPanel 1379 implements ActionListener, FocusListener { 1380 1381 private final String strTitle = getMsg("border.margins"); 1382 private JFormattedTextField leftMargin, rightMargin, 1383 topMargin, bottomMargin; 1384 private JLabel lblLeft, lblRight, lblTop, lblBottom; 1385 private int units = MediaPrintableArea.MM; 1386 // storage for the last margin values calculated, -ve is uninitialised 1387 private float lmVal = -1f,rmVal = -1f, tmVal = -1f, bmVal = -1f; 1388 // storage for margins as objects mapped into orientation for display 1389 private Float lmObj,rmObj,tmObj,bmObj; 1390 MarginsPanel()1391 public MarginsPanel() { 1392 super(); 1393 1394 GridBagLayout gridbag = new GridBagLayout(); 1395 GridBagConstraints c = new GridBagConstraints(); 1396 c.fill = GridBagConstraints.HORIZONTAL; 1397 c.weightx = 1.0; 1398 c.weighty = 0.0; 1399 c.insets = compInsets; 1400 1401 setLayout(gridbag); 1402 setBorder(BorderFactory.createTitledBorder(strTitle)); 1403 1404 String unitsKey = "label.millimetres"; 1405 String defaultCountry = Locale.getDefault().getCountry(); 1406 if (defaultCountry != null && 1407 (defaultCountry.isEmpty() || 1408 defaultCountry.equals(Locale.US.getCountry()) || 1409 defaultCountry.equals(Locale.CANADA.getCountry()))) { 1410 unitsKey = "label.inches"; 1411 units = MediaPrintableArea.INCH; 1412 } 1413 String unitsMsg = getMsg(unitsKey); 1414 1415 DecimalFormat format; 1416 if (units == MediaPrintableArea.MM) { 1417 format = new DecimalFormat("###.##"); 1418 format.setMaximumIntegerDigits(3); 1419 } else { 1420 format = new DecimalFormat("##.##"); 1421 format.setMaximumIntegerDigits(2); 1422 } 1423 1424 format.setMinimumFractionDigits(1); 1425 format.setMaximumFractionDigits(2); 1426 format.setMinimumIntegerDigits(1); 1427 format.setParseIntegerOnly(false); 1428 format.setDecimalSeparatorAlwaysShown(true); 1429 NumberFormatter nf = new NumberFormatter(format); 1430 nf.setMinimum(Float.valueOf(0.0f)); 1431 nf.setMaximum(Float.valueOf(999.0f)); 1432 nf.setAllowsInvalid(true); 1433 nf.setCommitsOnValidEdit(true); 1434 1435 leftMargin = new JFormattedTextField(nf); 1436 leftMargin.addFocusListener(this); 1437 leftMargin.addActionListener(this); 1438 leftMargin.getAccessibleContext().setAccessibleName( 1439 getMsg("label.leftmargin")); 1440 rightMargin = new JFormattedTextField(nf); 1441 rightMargin.addFocusListener(this); 1442 rightMargin.addActionListener(this); 1443 rightMargin.getAccessibleContext().setAccessibleName( 1444 getMsg("label.rightmargin")); 1445 topMargin = new JFormattedTextField(nf); 1446 topMargin.addFocusListener(this); 1447 topMargin.addActionListener(this); 1448 topMargin.getAccessibleContext().setAccessibleName( 1449 getMsg("label.topmargin")); 1450 1451 bottomMargin = new JFormattedTextField(nf); 1452 bottomMargin.addFocusListener(this); 1453 bottomMargin.addActionListener(this); 1454 bottomMargin.getAccessibleContext().setAccessibleName( 1455 getMsg("label.bottommargin")); 1456 1457 c.gridwidth = GridBagConstraints.RELATIVE; 1458 lblLeft = new JLabel(getMsg("label.leftmargin") + " " + unitsMsg, 1459 JLabel.LEADING); 1460 lblLeft.setDisplayedMnemonic(getMnemonic("label.leftmargin")); 1461 lblLeft.setLabelFor(leftMargin); 1462 addToGB(lblLeft, this, gridbag, c); 1463 1464 c.gridwidth = GridBagConstraints.REMAINDER; 1465 lblRight = new JLabel(getMsg("label.rightmargin") + " " + unitsMsg, 1466 JLabel.LEADING); 1467 lblRight.setDisplayedMnemonic(getMnemonic("label.rightmargin")); 1468 lblRight.setLabelFor(rightMargin); 1469 addToGB(lblRight, this, gridbag, c); 1470 1471 c.gridwidth = GridBagConstraints.RELATIVE; 1472 addToGB(leftMargin, this, gridbag, c); 1473 1474 c.gridwidth = GridBagConstraints.REMAINDER; 1475 addToGB(rightMargin, this, gridbag, c); 1476 1477 // add an invisible spacing component. 1478 addToGB(new JPanel(), this, gridbag, c); 1479 1480 c.gridwidth = GridBagConstraints.RELATIVE; 1481 lblTop = new JLabel(getMsg("label.topmargin") + " " + unitsMsg, 1482 JLabel.LEADING); 1483 lblTop.setDisplayedMnemonic(getMnemonic("label.topmargin")); 1484 lblTop.setLabelFor(topMargin); 1485 addToGB(lblTop, this, gridbag, c); 1486 1487 c.gridwidth = GridBagConstraints.REMAINDER; 1488 lblBottom = new JLabel(getMsg("label.bottommargin") + 1489 " " + unitsMsg, JLabel.LEADING); 1490 lblBottom.setDisplayedMnemonic(getMnemonic("label.bottommargin")); 1491 lblBottom.setLabelFor(bottomMargin); 1492 addToGB(lblBottom, this, gridbag, c); 1493 1494 c.gridwidth = GridBagConstraints.RELATIVE; 1495 addToGB(topMargin, this, gridbag, c); 1496 1497 c.gridwidth = GridBagConstraints.REMAINDER; 1498 addToGB(bottomMargin, this, gridbag, c); 1499 1500 } 1501 actionPerformed(ActionEvent e)1502 public void actionPerformed(ActionEvent e) { 1503 Object source = e.getSource(); 1504 updateMargins(source); 1505 } 1506 focusLost(FocusEvent e)1507 public void focusLost(FocusEvent e) { 1508 Object source = e.getSource(); 1509 updateMargins(source); 1510 } 1511 focusGained(FocusEvent e)1512 public void focusGained(FocusEvent e) {} 1513 1514 /* Get the numbers, use to create a MPA. 1515 * If its valid, accept it and update the attribute set. 1516 * If its not valid, then reject it and call updateInfo() 1517 * to re-establish the previous entries. 1518 */ updateMargins(Object source)1519 public void updateMargins(Object source) { 1520 if (!(source instanceof JFormattedTextField)) { 1521 return; 1522 } else { 1523 JFormattedTextField tf = (JFormattedTextField)source; 1524 Float val = (Float)tf.getValue(); 1525 if (val == null) { 1526 return; 1527 } 1528 if (tf == leftMargin && val.equals(lmObj)) { 1529 return; 1530 } 1531 if (tf == rightMargin && val.equals(rmObj)) { 1532 return; 1533 } 1534 if (tf == topMargin && val.equals(tmObj)) { 1535 return; 1536 } 1537 if (tf == bottomMargin && val.equals(bmObj)) { 1538 return; 1539 } 1540 } 1541 1542 Float lmTmpObj = (Float)leftMargin.getValue(); 1543 Float rmTmpObj = (Float)rightMargin.getValue(); 1544 Float tmTmpObj = (Float)topMargin.getValue(); 1545 Float bmTmpObj = (Float)bottomMargin.getValue(); 1546 1547 float lm = lmTmpObj.floatValue(); 1548 float rm = rmTmpObj.floatValue(); 1549 float tm = tmTmpObj.floatValue(); 1550 float bm = bmTmpObj.floatValue(); 1551 1552 /* adjust for orientation */ 1553 Class<OrientationRequested> orCategory = OrientationRequested.class; 1554 OrientationRequested or = 1555 (OrientationRequested)asCurrent.get(orCategory); 1556 1557 if (or == null) { 1558 or = (OrientationRequested) 1559 psCurrent.getDefaultAttributeValue(orCategory); 1560 } 1561 1562 float tmp; 1563 if (or == OrientationRequested.REVERSE_PORTRAIT) { 1564 tmp = lm; lm = rm; rm = tmp; 1565 tmp = tm; tm = bm; bm = tmp; 1566 } else if (or == OrientationRequested.LANDSCAPE) { 1567 tmp = lm; 1568 lm = tm; 1569 tm = rm; 1570 rm = bm; 1571 bm = tmp; 1572 } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { 1573 tmp = lm; 1574 lm = bm; 1575 bm = rm; 1576 rm = tm; 1577 tm = tmp; 1578 } 1579 MediaPrintableArea mpa; 1580 if ((mpa = validateMargins(lm, rm, tm, bm)) != null) { 1581 asCurrent.add(mpa); 1582 lmVal = lm; 1583 rmVal = rm; 1584 tmVal = tm; 1585 bmVal = bm; 1586 lmObj = lmTmpObj; 1587 rmObj = rmTmpObj; 1588 tmObj = tmTmpObj; 1589 bmObj = bmTmpObj; 1590 } else { 1591 if (lmObj == null || rmObj == null || 1592 tmObj == null || bmObj == null) { 1593 return; 1594 } else { 1595 leftMargin.setValue(lmObj); 1596 rightMargin.setValue(rmObj); 1597 topMargin.setValue(tmObj); 1598 bottomMargin.setValue(bmObj); 1599 1600 } 1601 } 1602 } 1603 1604 /* 1605 * This method either accepts the values and creates a new 1606 * MediaPrintableArea, or does nothing. 1607 * It should not attempt to create a printable area from anything 1608 * other than the exact values passed in. 1609 * But REMIND/TBD: it would be user friendly to replace margins the 1610 * user entered but are out of bounds with the minimum. 1611 * At that point this method will need to take responsibility for 1612 * updating the "stored" values and the UI. 1613 */ validateMargins(float lm, float rm, float tm, float bm)1614 private MediaPrintableArea validateMargins(float lm, float rm, 1615 float tm, float bm) { 1616 1617 Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; 1618 MediaPrintableArea mpa; 1619 MediaPrintableArea mpaMax = null; 1620 MediaSize mediaSize = null; 1621 1622 Media media = (Media)asCurrent.get(Media.class); 1623 if (media == null || !(media instanceof MediaSizeName)) { 1624 media = (Media)psCurrent.getDefaultAttributeValue(Media.class); 1625 } 1626 if (media != null && (media instanceof MediaSizeName)) { 1627 MediaSizeName msn = (MediaSizeName)media; 1628 mediaSize = MediaSize.getMediaSizeForName(msn); 1629 } 1630 if (mediaSize == null) { 1631 mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); 1632 } 1633 1634 if (media != null) { 1635 PrintRequestAttributeSet tmpASet = 1636 new HashPrintRequestAttributeSet(asCurrent); 1637 tmpASet.add(media); 1638 1639 Object values = 1640 psCurrent.getSupportedAttributeValues(mpaCategory, 1641 docFlavor, 1642 tmpASet); 1643 if (values instanceof MediaPrintableArea[] && 1644 ((MediaPrintableArea[])values).length > 0) { 1645 mpaMax = ((MediaPrintableArea[])values)[0]; 1646 1647 } 1648 } 1649 if (mpaMax == null) { 1650 mpaMax = new MediaPrintableArea(0f, 0f, 1651 mediaSize.getX(units), 1652 mediaSize.getY(units), 1653 units); 1654 } 1655 1656 float wid = mediaSize.getX(units); 1657 float hgt = mediaSize.getY(units); 1658 float pax = lm; 1659 float pay = tm; 1660 float par = rm; 1661 float pab = bm; 1662 float paw = wid - lm - rm; 1663 float pah = hgt - tm - bm; 1664 1665 if (paw <= 0f || pah <= 0f || pax < 0f || pay < 0f || 1666 par <= 0f || pab <= 0f || 1667 pax < mpaMax.getX(units) || paw > mpaMax.getWidth(units) || 1668 pay < mpaMax.getY(units) || pah > mpaMax.getHeight(units)) { 1669 return null; 1670 } else { 1671 return new MediaPrintableArea(lm, tm, paw, pah, units); 1672 } 1673 } 1674 1675 /* This is complex as a MediaPrintableArea is valid only within 1676 * a particular context of media size. 1677 * So we need a MediaSize as well as a MediaPrintableArea. 1678 * MediaSize can be obtained from MediaSizeName. 1679 * If the application specifies a MediaPrintableArea, we accept it 1680 * to the extent its valid for the Media they specify. If they 1681 * don't specify a Media, then the default is assumed. 1682 * 1683 * If an application doesn't define a MediaPrintableArea, we need to 1684 * create a suitable one, this is created using the specified (or 1685 * default) Media and default 1 inch margins. This is validated 1686 * against the paper in case this is too large for tiny media. 1687 */ updateInfo()1688 public void updateInfo() { 1689 1690 if (isAWT) { 1691 leftMargin.setEnabled(false); 1692 rightMargin.setEnabled(false); 1693 topMargin.setEnabled(false); 1694 bottomMargin.setEnabled(false); 1695 lblLeft.setEnabled(false); 1696 lblRight.setEnabled(false); 1697 lblTop.setEnabled(false); 1698 lblBottom.setEnabled(false); 1699 return; 1700 } 1701 1702 Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; 1703 MediaPrintableArea mpa = 1704 (MediaPrintableArea)asCurrent.get(mpaCategory); 1705 MediaPrintableArea mpaMax = null; 1706 MediaSize mediaSize = null; 1707 1708 Media media = (Media)asCurrent.get(Media.class); 1709 if (media == null || !(media instanceof MediaSizeName)) { 1710 media = (Media)psCurrent.getDefaultAttributeValue(Media.class); 1711 } 1712 if (media != null && (media instanceof MediaSizeName)) { 1713 MediaSizeName msn = (MediaSizeName)media; 1714 mediaSize = MediaSize.getMediaSizeForName(msn); 1715 } 1716 if (mediaSize == null) { 1717 mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); 1718 } 1719 1720 if (media != null) { 1721 PrintRequestAttributeSet tmpASet = 1722 new HashPrintRequestAttributeSet(asCurrent); 1723 tmpASet.add(media); 1724 1725 Object values = 1726 psCurrent.getSupportedAttributeValues(mpaCategory, 1727 docFlavor, 1728 tmpASet); 1729 if (values instanceof MediaPrintableArea[] && 1730 ((MediaPrintableArea[])values).length > 0) { 1731 mpaMax = ((MediaPrintableArea[])values)[0]; 1732 1733 } else if (values instanceof MediaPrintableArea) { 1734 mpaMax = (MediaPrintableArea)values; 1735 } 1736 } 1737 if (mpaMax == null) { 1738 mpaMax = new MediaPrintableArea(0f, 0f, 1739 mediaSize.getX(units), 1740 mediaSize.getY(units), 1741 units); 1742 } 1743 1744 /* 1745 * At this point we now know as best we can :- 1746 * - the media size 1747 * - the maximum corresponding printable area 1748 * - the media printable area specified by the client, if any. 1749 * The next step is to create a default MPA if none was specified. 1750 * 1" margins are used unless they are disproportionately 1751 * large compared to the size of the media. 1752 */ 1753 1754 float wid = mediaSize.getX(MediaPrintableArea.INCH); 1755 float hgt = mediaSize.getY(MediaPrintableArea.INCH); 1756 float maxMarginRatio = 5f; 1757 float xMgn, yMgn; 1758 if (wid > maxMarginRatio) { 1759 xMgn = 1f; 1760 } else { 1761 xMgn = wid / maxMarginRatio; 1762 } 1763 if (hgt > maxMarginRatio) { 1764 yMgn = 1f; 1765 } else { 1766 yMgn = hgt / maxMarginRatio; 1767 } 1768 1769 if (mpa == null) { 1770 mpa = new MediaPrintableArea(xMgn, yMgn, 1771 wid-(2*xMgn), hgt-(2*yMgn), 1772 MediaPrintableArea.INCH); 1773 asCurrent.add(mpa); 1774 } 1775 float pax = mpa.getX(units); 1776 float pay = mpa.getY(units); 1777 float paw = mpa.getWidth(units); 1778 float pah = mpa.getHeight(units); 1779 float paxMax = mpaMax.getX(units); 1780 float payMax = mpaMax.getY(units); 1781 float pawMax = mpaMax.getWidth(units); 1782 float pahMax = mpaMax.getHeight(units); 1783 1784 1785 boolean invalid = false; 1786 1787 // If the paper is set to something which is too small to 1788 // accommodate a specified printable area, perhaps carried 1789 // over from a larger paper, the adjustment that needs to be 1790 // performed should seem the most natural from a user's viewpoint. 1791 // Since the user is specifying margins, then we are biased 1792 // towards keeping the margins as close to what is specified as 1793 // possible, shrinking or growing the printable area. 1794 // But the API uses printable area, so you need to know the 1795 // media size in which the margins were previously interpreted, 1796 // or at least have a record of the margins. 1797 // In the case that this is the creation of this UI we do not 1798 // have this record, so we are somewhat reliant on the client 1799 // to supply a reasonable default 1800 wid = mediaSize.getX(units); 1801 hgt = mediaSize.getY(units); 1802 if (lmVal >= 0f) { 1803 invalid = true; 1804 1805 if (lmVal + rmVal > wid) { 1806 // margins impossible, but maintain P.A if can 1807 if (paw > pawMax) { 1808 paw = pawMax; 1809 } 1810 // try to centre the printable area. 1811 pax = (wid - paw)/2f; 1812 } else { 1813 pax = (lmVal >= paxMax) ? lmVal : paxMax; 1814 paw = wid - pax - rmVal; 1815 } 1816 if (tmVal + bmVal > hgt) { 1817 if (pah > pahMax) { 1818 pah = pahMax; 1819 } 1820 pay = (hgt - pah)/2f; 1821 } else { 1822 pay = (tmVal >= payMax) ? tmVal : payMax; 1823 pah = hgt - pay - bmVal; 1824 } 1825 } 1826 if (pax < paxMax) { 1827 invalid = true; 1828 pax = paxMax; 1829 } 1830 if (pay < payMax) { 1831 invalid = true; 1832 pay = payMax; 1833 } 1834 if (paw > pawMax) { 1835 invalid = true; 1836 paw = pawMax; 1837 } 1838 if (pah > pahMax) { 1839 invalid = true; 1840 pah = pahMax; 1841 } 1842 1843 if ((pax + paw > paxMax + pawMax) || (paw <= 0f)) { 1844 invalid = true; 1845 pax = paxMax; 1846 paw = pawMax; 1847 } 1848 if ((pay + pah > payMax + pahMax) || (pah <= 0f)) { 1849 invalid = true; 1850 pay = payMax; 1851 pah = pahMax; 1852 } 1853 1854 if (invalid) { 1855 mpa = new MediaPrintableArea(pax, pay, paw, pah, units); 1856 asCurrent.add(mpa); 1857 } 1858 1859 /* We now have a valid printable area. 1860 * Turn it into margins, using the mediaSize 1861 */ 1862 lmVal = pax; 1863 tmVal = pay; 1864 rmVal = mediaSize.getX(units) - pax - paw; 1865 bmVal = mediaSize.getY(units) - pay - pah; 1866 1867 lmObj = lmVal; 1868 rmObj = rmVal; 1869 tmObj = tmVal; 1870 bmObj = bmVal; 1871 1872 /* Now we know the values to use, we need to assign them 1873 * to the fields appropriate for the orientation. 1874 * Note: if orientation changes this method must be called. 1875 */ 1876 Class<OrientationRequested> orCategory = OrientationRequested.class; 1877 OrientationRequested or = 1878 (OrientationRequested)asCurrent.get(orCategory); 1879 1880 if (or == null) { 1881 or = (OrientationRequested) 1882 psCurrent.getDefaultAttributeValue(orCategory); 1883 } 1884 1885 Float tmp; 1886 1887 if (or == OrientationRequested.REVERSE_PORTRAIT) { 1888 tmp = lmObj; lmObj = rmObj; rmObj = tmp; 1889 tmp = tmObj; tmObj = bmObj; bmObj = tmp; 1890 } else if (or == OrientationRequested.LANDSCAPE) { 1891 tmp = lmObj; 1892 lmObj = bmObj; 1893 bmObj = rmObj; 1894 rmObj = tmObj; 1895 tmObj = tmp; 1896 } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { 1897 tmp = lmObj; 1898 lmObj = tmObj; 1899 tmObj = rmObj; 1900 rmObj = bmObj; 1901 bmObj = tmp; 1902 } 1903 1904 leftMargin.setValue(lmObj); 1905 rightMargin.setValue(rmObj); 1906 topMargin.setValue(tmObj); 1907 bottomMargin.setValue(bmObj); 1908 } 1909 } 1910 1911 @SuppressWarnings("serial") // Superclass is not serializable across versions 1912 private class MediaPanel extends JPanel implements ItemListener { 1913 1914 private final String strTitle = getMsg("border.media"); 1915 private JLabel lblSize, lblSource; 1916 private JComboBox<Object> cbSize, cbSource; 1917 private Vector<MediaSizeName> sizes = new Vector<>(); 1918 private Vector<MediaTray> sources = new Vector<>(); 1919 private MarginsPanel pnlMargins = null; 1920 MediaPanel()1921 public MediaPanel() { 1922 super(); 1923 1924 GridBagLayout gridbag = new GridBagLayout(); 1925 GridBagConstraints c = new GridBagConstraints(); 1926 1927 setLayout(gridbag); 1928 setBorder(BorderFactory.createTitledBorder(strTitle)); 1929 1930 cbSize = new JComboBox<>(); 1931 cbSource = new JComboBox<>(); 1932 1933 c.fill = GridBagConstraints.BOTH; 1934 c.insets = compInsets; 1935 c.weighty = 1.0; 1936 1937 c.weightx = 0.0; 1938 lblSize = new JLabel(getMsg("label.size"), JLabel.TRAILING); 1939 lblSize.setDisplayedMnemonic(getMnemonic("label.size")); 1940 lblSize.setLabelFor(cbSize); 1941 addToGB(lblSize, this, gridbag, c); 1942 c.weightx = 1.0; 1943 c.gridwidth = GridBagConstraints.REMAINDER; 1944 addToGB(cbSize, this, gridbag, c); 1945 1946 c.weightx = 0.0; 1947 c.gridwidth = 1; 1948 lblSource = new JLabel(getMsg("label.source"), JLabel.TRAILING); 1949 lblSource.setDisplayedMnemonic(getMnemonic("label.source")); 1950 lblSource.setLabelFor(cbSource); 1951 addToGB(lblSource, this, gridbag, c); 1952 c.gridwidth = GridBagConstraints.REMAINDER; 1953 addToGB(cbSource, this, gridbag, c); 1954 } 1955 getMediaName(String key)1956 private String getMediaName(String key) { 1957 try { 1958 // replace characters that would be invalid in 1959 // a resource key with valid characters 1960 String newkey = key.replace(' ', '-'); 1961 newkey = newkey.replace('#', 'n'); 1962 1963 return messageRB.getString(newkey); 1964 } catch (java.util.MissingResourceException e) { 1965 return key; 1966 } 1967 } 1968 itemStateChanged(ItemEvent e)1969 public void itemStateChanged(ItemEvent e) { 1970 Object source = e.getSource(); 1971 1972 if (e.getStateChange() == ItemEvent.SELECTED) { 1973 if (source == cbSize) { 1974 int index = cbSize.getSelectedIndex(); 1975 1976 if ((index >= 0) && (index < sizes.size())) { 1977 if ((cbSource.getItemCount() > 1) && 1978 (cbSource.getSelectedIndex() >= 1)) 1979 { 1980 int src = cbSource.getSelectedIndex() - 1; 1981 MediaTray mt = sources.get(src); 1982 asCurrent.add(new SunAlternateMedia(mt)); 1983 } 1984 asCurrent.add(sizes.get(index)); 1985 } 1986 } else if (source == cbSource) { 1987 int index = cbSource.getSelectedIndex(); 1988 1989 if ((index >= 1) && (index < (sources.size() + 1))) { 1990 asCurrent.remove(SunAlternateMedia.class); 1991 MediaTray newTray = sources.get(index - 1); 1992 Media m = (Media)asCurrent.get(Media.class); 1993 if (m == null || m instanceof MediaTray) { 1994 asCurrent.add(newTray); 1995 } else if (m instanceof MediaSizeName) { 1996 MediaSizeName msn = (MediaSizeName)m; 1997 Media def = (Media)psCurrent.getDefaultAttributeValue(Media.class); 1998 if (def instanceof MediaSizeName && def.equals(msn)) { 1999 asCurrent.add(newTray); 2000 } else { 2001 /* Non-default paper size, so need to store tray 2002 * as SunAlternateMedia 2003 */ 2004 asCurrent.add(new SunAlternateMedia(newTray)); 2005 } 2006 } 2007 } else if (index == 0) { 2008 asCurrent.remove(SunAlternateMedia.class); 2009 if (cbSize.getItemCount() > 0) { 2010 int size = cbSize.getSelectedIndex(); 2011 asCurrent.add(sizes.get(size)); 2012 } 2013 } 2014 } 2015 // orientation affects display of margins. 2016 if (pnlMargins != null) { 2017 pnlMargins.updateInfo(); 2018 } 2019 } 2020 } 2021 2022 2023 /* this is ad hoc to keep things simple */ addMediaListener(MarginsPanel pnl)2024 public void addMediaListener(MarginsPanel pnl) { 2025 pnlMargins = pnl; 2026 } updateInfo()2027 public void updateInfo() { 2028 Class<Media> mdCategory = Media.class; 2029 Class<SunAlternateMedia> amCategory = SunAlternateMedia.class; 2030 boolean mediaSupported = false; 2031 2032 cbSize.removeItemListener(this); 2033 cbSize.removeAllItems(); 2034 cbSource.removeItemListener(this); 2035 cbSource.removeAllItems(); 2036 cbSource.addItem(getMediaName("auto-select")); 2037 2038 sizes.clear(); 2039 sources.clear(); 2040 2041 if (psCurrent.isAttributeCategorySupported(mdCategory)) { 2042 mediaSupported = true; 2043 2044 Object values = 2045 psCurrent.getSupportedAttributeValues(mdCategory, 2046 docFlavor, 2047 asCurrent); 2048 2049 if (values instanceof Media[]) { 2050 Media[] media = (Media[])values; 2051 2052 for (int i = 0; i < media.length; i++) { 2053 Media medium = media[i]; 2054 2055 if (medium instanceof MediaSizeName) { 2056 sizes.add((MediaSizeName)medium); 2057 cbSize.addItem(getMediaName(medium.toString())); 2058 } else if (medium instanceof MediaTray) { 2059 sources.add((MediaTray)medium); 2060 cbSource.addItem(getMediaName(medium.toString())); 2061 } 2062 } 2063 } 2064 } 2065 2066 boolean msSupported = (mediaSupported && (sizes.size() > 0)); 2067 lblSize.setEnabled(msSupported); 2068 cbSize.setEnabled(msSupported); 2069 2070 if (isAWT) { 2071 cbSource.setEnabled(false); 2072 lblSource.setEnabled(false); 2073 } else { 2074 cbSource.setEnabled(mediaSupported); 2075 } 2076 2077 if (mediaSupported) { 2078 2079 Media medium = (Media)asCurrent.get(mdCategory); 2080 2081 // initialize size selection to default 2082 Media defMedia = (Media)psCurrent.getDefaultAttributeValue(mdCategory); 2083 if (defMedia instanceof MediaSizeName) { 2084 cbSize.setSelectedIndex(sizes.size() > 0 ? sizes.indexOf(defMedia) : -1); 2085 } 2086 2087 if (medium == null || 2088 !psCurrent.isAttributeValueSupported(medium, 2089 docFlavor, asCurrent)) { 2090 2091 medium = defMedia; 2092 2093 if (medium == null) { 2094 if (sizes.size() > 0) { 2095 medium = (Media)sizes.get(0); 2096 } 2097 } 2098 if (medium != null) { 2099 asCurrent.add(medium); 2100 } 2101 } 2102 if (medium != null) { 2103 if (medium instanceof MediaSizeName) { 2104 MediaSizeName ms = (MediaSizeName)medium; 2105 cbSize.setSelectedIndex(sizes.indexOf(ms)); 2106 } else if (medium instanceof MediaTray) { 2107 MediaTray mt = (MediaTray)medium; 2108 cbSource.setSelectedIndex(sources.indexOf(mt) + 1); 2109 } 2110 } else { 2111 cbSize.setSelectedIndex(sizes.size() > 0 ? 0 : -1); 2112 cbSource.setSelectedIndex(0); 2113 } 2114 2115 SunAlternateMedia alt = (SunAlternateMedia)asCurrent.get(amCategory); 2116 if (alt != null) { 2117 Media md = alt.getMedia(); 2118 if (md instanceof MediaTray) { 2119 MediaTray mt = (MediaTray)md; 2120 cbSource.setSelectedIndex(sources.indexOf(mt) + 1); 2121 } 2122 } 2123 2124 int selIndex = cbSize.getSelectedIndex(); 2125 if ((selIndex >= 0) && (selIndex < sizes.size())) { 2126 asCurrent.add(sizes.get(selIndex)); 2127 } 2128 2129 selIndex = cbSource.getSelectedIndex(); 2130 if ((selIndex >= 1) && (selIndex < (sources.size()+1))) { 2131 MediaTray mt = sources.get(selIndex-1); 2132 if (medium instanceof MediaTray) { 2133 asCurrent.add(mt); 2134 } else { 2135 asCurrent.add(new SunAlternateMedia(mt)); 2136 } 2137 } 2138 2139 2140 } 2141 cbSize.addItemListener(this); 2142 cbSource.addItemListener(this); 2143 } 2144 } 2145 2146 @SuppressWarnings("serial") // Superclass is not serializable across versions 2147 private class OrientationPanel extends JPanel 2148 implements ActionListener 2149 { 2150 private final String strTitle = getMsg("border.orientation"); 2151 private IconRadioButton rbPortrait, rbLandscape, 2152 rbRevPortrait, rbRevLandscape; 2153 private MarginsPanel pnlMargins = null; 2154 OrientationPanel()2155 public OrientationPanel() { 2156 super(); 2157 2158 GridBagLayout gridbag = new GridBagLayout(); 2159 GridBagConstraints c = new GridBagConstraints(); 2160 2161 setLayout(gridbag); 2162 setBorder(BorderFactory.createTitledBorder(strTitle)); 2163 2164 c.fill = GridBagConstraints.BOTH; 2165 c.insets = compInsets; 2166 c.weighty = 1.0; 2167 c.gridwidth = GridBagConstraints.REMAINDER; 2168 2169 ButtonGroup bg = new ButtonGroup(); 2170 rbPortrait = new IconRadioButton("radiobutton.portrait", 2171 "orientPortrait.png", true, 2172 bg, this); 2173 rbPortrait.addActionListener(this); 2174 addToGB(rbPortrait, this, gridbag, c); 2175 rbLandscape = new IconRadioButton("radiobutton.landscape", 2176 "orientLandscape.png", false, 2177 bg, this); 2178 rbLandscape.addActionListener(this); 2179 addToGB(rbLandscape, this, gridbag, c); 2180 rbRevPortrait = new IconRadioButton("radiobutton.revportrait", 2181 "orientRevPortrait.png", false, 2182 bg, this); 2183 rbRevPortrait.addActionListener(this); 2184 addToGB(rbRevPortrait, this, gridbag, c); 2185 rbRevLandscape = new IconRadioButton("radiobutton.revlandscape", 2186 "orientRevLandscape.png", false, 2187 bg, this); 2188 rbRevLandscape.addActionListener(this); 2189 addToGB(rbRevLandscape, this, gridbag, c); 2190 } 2191 actionPerformed(ActionEvent e)2192 public void actionPerformed(ActionEvent e) { 2193 Object source = e.getSource(); 2194 2195 if (rbPortrait.isSameAs(source)) { 2196 asCurrent.add(OrientationRequested.PORTRAIT); 2197 } else if (rbLandscape.isSameAs(source)) { 2198 asCurrent.add(OrientationRequested.LANDSCAPE); 2199 } else if (rbRevPortrait.isSameAs(source)) { 2200 asCurrent.add(OrientationRequested.REVERSE_PORTRAIT); 2201 } else if (rbRevLandscape.isSameAs(source)) { 2202 asCurrent.add(OrientationRequested.REVERSE_LANDSCAPE); 2203 } 2204 // orientation affects display of margins. 2205 if (pnlMargins != null) { 2206 pnlMargins.updateInfo(); 2207 } 2208 } 2209 2210 /* This is ad hoc to keep things simple */ addOrientationListener(MarginsPanel pnl)2211 void addOrientationListener(MarginsPanel pnl) { 2212 pnlMargins = pnl; 2213 } 2214 updateInfo()2215 public void updateInfo() { 2216 Class<OrientationRequested> orCategory = OrientationRequested.class; 2217 boolean pSupported = false; 2218 boolean lSupported = false; 2219 boolean rpSupported = false; 2220 boolean rlSupported = false; 2221 2222 if (isAWT) { 2223 pSupported = true; 2224 lSupported = true; 2225 } else 2226 if (psCurrent.isAttributeCategorySupported(orCategory)) { 2227 Object values = 2228 psCurrent.getSupportedAttributeValues(orCategory, 2229 docFlavor, 2230 asCurrent); 2231 2232 if (values instanceof OrientationRequested[]) { 2233 OrientationRequested[] ovalues = 2234 (OrientationRequested[])values; 2235 2236 for (int i = 0; i < ovalues.length; i++) { 2237 OrientationRequested value = ovalues[i]; 2238 2239 if (value == OrientationRequested.PORTRAIT) { 2240 pSupported = true; 2241 } else if (value == OrientationRequested.LANDSCAPE) { 2242 lSupported = true; 2243 } else if (value == OrientationRequested.REVERSE_PORTRAIT) { 2244 rpSupported = true; 2245 } else if (value == OrientationRequested.REVERSE_LANDSCAPE) { 2246 rlSupported = true; 2247 } 2248 } 2249 } 2250 } 2251 2252 2253 rbPortrait.setEnabled(pSupported); 2254 rbLandscape.setEnabled(lSupported); 2255 rbRevPortrait.setEnabled(rpSupported); 2256 rbRevLandscape.setEnabled(rlSupported); 2257 2258 OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); 2259 if (or == null || 2260 !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { 2261 2262 or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); 2263 // need to validate if default is not supported 2264 if ((or != null) && 2265 !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { 2266 or = null; 2267 Object values = 2268 psCurrent.getSupportedAttributeValues(orCategory, 2269 docFlavor, 2270 asCurrent); 2271 if (values instanceof OrientationRequested[]) { 2272 OrientationRequested[] orValues = 2273 (OrientationRequested[])values; 2274 if (orValues.length > 1) { 2275 // get the first in the list 2276 or = orValues[0]; 2277 } 2278 } 2279 } 2280 2281 if (or == null) { 2282 or = OrientationRequested.PORTRAIT; 2283 } 2284 asCurrent.add(or); 2285 } 2286 2287 if (or == OrientationRequested.PORTRAIT) { 2288 rbPortrait.setSelected(true); 2289 } else if (or == OrientationRequested.LANDSCAPE) { 2290 rbLandscape.setSelected(true); 2291 } else if (or == OrientationRequested.REVERSE_PORTRAIT) { 2292 rbRevPortrait.setSelected(true); 2293 } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) 2294 rbRevLandscape.setSelected(true); 2295 } 2296 } 2297 } 2298 2299 2300 2301 /** 2302 * The "Appearance" tab. Includes the controls for Chromaticity, 2303 * PrintQuality, JobPriority, JobName, and other related job attributes. 2304 */ 2305 @SuppressWarnings("serial") // Superclass is not serializable across versions 2306 private class AppearancePanel extends JPanel { 2307 2308 private ChromaticityPanel pnlChromaticity; 2309 private QualityPanel pnlQuality; 2310 private JobAttributesPanel pnlJobAttributes; 2311 private SidesPanel pnlSides; 2312 AppearancePanel()2313 public AppearancePanel() { 2314 super(); 2315 2316 GridBagLayout gridbag = new GridBagLayout(); 2317 GridBagConstraints c = new GridBagConstraints(); 2318 2319 setLayout(gridbag); 2320 2321 c.fill = GridBagConstraints.BOTH; 2322 c.insets = panelInsets; 2323 c.weightx = 1.0; 2324 c.weighty = 1.0; 2325 2326 c.gridwidth = GridBagConstraints.RELATIVE; 2327 pnlChromaticity = new ChromaticityPanel(); 2328 addToGB(pnlChromaticity, this, gridbag, c); 2329 2330 c.gridwidth = GridBagConstraints.REMAINDER; 2331 pnlQuality = new QualityPanel(); 2332 addToGB(pnlQuality, this, gridbag, c); 2333 2334 c.gridwidth = 1; 2335 pnlSides = new SidesPanel(); 2336 addToGB(pnlSides, this, gridbag, c); 2337 2338 c.gridwidth = GridBagConstraints.REMAINDER; 2339 pnlJobAttributes = new JobAttributesPanel(); 2340 addToGB(pnlJobAttributes, this, gridbag, c); 2341 2342 } 2343 updateInfo()2344 public void updateInfo() { 2345 pnlChromaticity.updateInfo(); 2346 pnlQuality.updateInfo(); 2347 pnlSides.updateInfo(); 2348 pnlJobAttributes.updateInfo(); 2349 } 2350 } 2351 2352 @SuppressWarnings("serial") // Superclass is not serializable across versions 2353 private class ChromaticityPanel extends JPanel 2354 implements ActionListener 2355 { 2356 private final String strTitle = getMsg("border.chromaticity"); 2357 private JRadioButton rbMonochrome, rbColor; 2358 ChromaticityPanel()2359 public ChromaticityPanel() { 2360 super(); 2361 2362 GridBagLayout gridbag = new GridBagLayout(); 2363 GridBagConstraints c = new GridBagConstraints(); 2364 2365 setLayout(gridbag); 2366 setBorder(BorderFactory.createTitledBorder(strTitle)); 2367 2368 c.fill = GridBagConstraints.BOTH; 2369 c.gridwidth = GridBagConstraints.REMAINDER; 2370 c.weighty = 1.0; 2371 2372 ButtonGroup bg = new ButtonGroup(); 2373 rbMonochrome = createRadioButton("radiobutton.monochrome", this); 2374 rbMonochrome.setSelected(true); 2375 bg.add(rbMonochrome); 2376 addToGB(rbMonochrome, this, gridbag, c); 2377 rbColor = createRadioButton("radiobutton.color", this); 2378 bg.add(rbColor); 2379 addToGB(rbColor, this, gridbag, c); 2380 } 2381 actionPerformed(ActionEvent e)2382 public void actionPerformed(ActionEvent e) { 2383 Object source = e.getSource(); 2384 2385 // REMIND: use isSameAs if we move to a IconRB in the future 2386 if (source == rbMonochrome) { 2387 asCurrent.add(Chromaticity.MONOCHROME); 2388 } else if (source == rbColor) { 2389 asCurrent.add(Chromaticity.COLOR); 2390 } 2391 } 2392 updateInfo()2393 public void updateInfo() { 2394 Class<Chromaticity> chCategory = Chromaticity.class; 2395 boolean monoSupported = false; 2396 boolean colorSupported = false; 2397 2398 if (isAWT) { 2399 monoSupported = true; 2400 colorSupported = true; 2401 } else 2402 if (psCurrent.isAttributeCategorySupported(chCategory)) { 2403 Object values = 2404 psCurrent.getSupportedAttributeValues(chCategory, 2405 docFlavor, 2406 asCurrent); 2407 2408 if (values instanceof Chromaticity[]) { 2409 Chromaticity[] cvalues = (Chromaticity[])values; 2410 2411 for (int i = 0; i < cvalues.length; i++) { 2412 Chromaticity value = cvalues[i]; 2413 2414 if (value == Chromaticity.MONOCHROME) { 2415 monoSupported = true; 2416 } else if (value == Chromaticity.COLOR) { 2417 colorSupported = true; 2418 } 2419 } 2420 } 2421 } 2422 2423 2424 rbMonochrome.setEnabled(monoSupported); 2425 rbColor.setEnabled(colorSupported); 2426 2427 Chromaticity ch = (Chromaticity)asCurrent.get(chCategory); 2428 if (ch == null) { 2429 ch = (Chromaticity)psCurrent.getDefaultAttributeValue(chCategory); 2430 if (ch == null) { 2431 ch = Chromaticity.MONOCHROME; 2432 } 2433 } 2434 2435 if (ch == Chromaticity.MONOCHROME) { 2436 rbMonochrome.setSelected(true); 2437 } else { // if (ch == Chromaticity.COLOR) 2438 rbColor.setSelected(true); 2439 } 2440 } 2441 } 2442 2443 @SuppressWarnings("serial") // Superclass is not serializable across versions 2444 private class QualityPanel extends JPanel 2445 implements ActionListener 2446 { 2447 private final String strTitle = getMsg("border.quality"); 2448 private JRadioButton rbDraft, rbNormal, rbHigh; 2449 QualityPanel()2450 public QualityPanel() { 2451 super(); 2452 2453 GridBagLayout gridbag = new GridBagLayout(); 2454 GridBagConstraints c = new GridBagConstraints(); 2455 2456 setLayout(gridbag); 2457 setBorder(BorderFactory.createTitledBorder(strTitle)); 2458 2459 c.fill = GridBagConstraints.BOTH; 2460 c.gridwidth = GridBagConstraints.REMAINDER; 2461 c.weighty = 1.0; 2462 2463 ButtonGroup bg = new ButtonGroup(); 2464 rbDraft = createRadioButton("radiobutton.draftq", this); 2465 bg.add(rbDraft); 2466 addToGB(rbDraft, this, gridbag, c); 2467 rbNormal = createRadioButton("radiobutton.normalq", this); 2468 rbNormal.setSelected(true); 2469 bg.add(rbNormal); 2470 addToGB(rbNormal, this, gridbag, c); 2471 rbHigh = createRadioButton("radiobutton.highq", this); 2472 bg.add(rbHigh); 2473 addToGB(rbHigh, this, gridbag, c); 2474 } 2475 actionPerformed(ActionEvent e)2476 public void actionPerformed(ActionEvent e) { 2477 Object source = e.getSource(); 2478 2479 if (source == rbDraft) { 2480 asCurrent.add(PrintQuality.DRAFT); 2481 } else if (source == rbNormal) { 2482 asCurrent.add(PrintQuality.NORMAL); 2483 } else if (source == rbHigh) { 2484 asCurrent.add(PrintQuality.HIGH); 2485 } 2486 } 2487 updateInfo()2488 public void updateInfo() { 2489 Class<PrintQuality> pqCategory = PrintQuality.class; 2490 boolean draftSupported = false; 2491 boolean normalSupported = false; 2492 boolean highSupported = false; 2493 2494 if (isAWT) { 2495 draftSupported = true; 2496 normalSupported = true; 2497 highSupported = true; 2498 } else 2499 if (psCurrent.isAttributeCategorySupported(pqCategory)) { 2500 Object values = 2501 psCurrent.getSupportedAttributeValues(pqCategory, 2502 docFlavor, 2503 asCurrent); 2504 2505 if (values instanceof PrintQuality[]) { 2506 PrintQuality[] qvalues = (PrintQuality[])values; 2507 2508 for (int i = 0; i < qvalues.length; i++) { 2509 PrintQuality value = qvalues[i]; 2510 2511 if (value == PrintQuality.DRAFT) { 2512 draftSupported = true; 2513 } else if (value == PrintQuality.NORMAL) { 2514 normalSupported = true; 2515 } else if (value == PrintQuality.HIGH) { 2516 highSupported = true; 2517 } 2518 } 2519 } 2520 } 2521 2522 rbDraft.setEnabled(draftSupported); 2523 rbNormal.setEnabled(normalSupported); 2524 rbHigh.setEnabled(highSupported); 2525 2526 PrintQuality pq = (PrintQuality)asCurrent.get(pqCategory); 2527 if (pq == null) { 2528 pq = (PrintQuality)psCurrent.getDefaultAttributeValue(pqCategory); 2529 if (pq == null) { 2530 pq = PrintQuality.NORMAL; 2531 } 2532 } 2533 2534 if (pq == PrintQuality.DRAFT) { 2535 rbDraft.setSelected(true); 2536 } else if (pq == PrintQuality.NORMAL) { 2537 rbNormal.setSelected(true); 2538 } else { // if (pq == PrintQuality.HIGH) 2539 rbHigh.setSelected(true); 2540 } 2541 } 2542 2543 2544 } 2545 2546 @SuppressWarnings("serial") // Superclass is not serializable across versions 2547 private class SidesPanel extends JPanel 2548 implements ActionListener 2549 { 2550 private final String strTitle = getMsg("border.sides"); 2551 private IconRadioButton rbOneSide, rbTumble, rbDuplex; 2552 SidesPanel()2553 public SidesPanel() { 2554 super(); 2555 2556 GridBagLayout gridbag = new GridBagLayout(); 2557 GridBagConstraints c = new GridBagConstraints(); 2558 2559 setLayout(gridbag); 2560 setBorder(BorderFactory.createTitledBorder(strTitle)); 2561 2562 c.fill = GridBagConstraints.BOTH; 2563 c.insets = compInsets; 2564 c.weighty = 1.0; 2565 c.gridwidth = GridBagConstraints.REMAINDER; 2566 2567 ButtonGroup bg = new ButtonGroup(); 2568 rbOneSide = new IconRadioButton("radiobutton.oneside", 2569 "oneside.png", true, 2570 bg, this); 2571 rbOneSide.addActionListener(this); 2572 addToGB(rbOneSide, this, gridbag, c); 2573 rbTumble = new IconRadioButton("radiobutton.tumble", 2574 "tumble.png", false, 2575 bg, this); 2576 rbTumble.addActionListener(this); 2577 addToGB(rbTumble, this, gridbag, c); 2578 rbDuplex = new IconRadioButton("radiobutton.duplex", 2579 "duplex.png", false, 2580 bg, this); 2581 rbDuplex.addActionListener(this); 2582 c.gridwidth = GridBagConstraints.REMAINDER; 2583 addToGB(rbDuplex, this, gridbag, c); 2584 } 2585 actionPerformed(ActionEvent e)2586 public void actionPerformed(ActionEvent e) { 2587 Object source = e.getSource(); 2588 2589 if (rbOneSide.isSameAs(source)) { 2590 asCurrent.add(Sides.ONE_SIDED); 2591 } else if (rbTumble.isSameAs(source)) { 2592 asCurrent.add(Sides.TUMBLE); 2593 } else if (rbDuplex.isSameAs(source)) { 2594 asCurrent.add(Sides.DUPLEX); 2595 } 2596 } 2597 updateInfo()2598 public void updateInfo() { 2599 Class<Sides> sdCategory = Sides.class; 2600 boolean osSupported = false; 2601 boolean tSupported = false; 2602 boolean dSupported = false; 2603 2604 if (psCurrent.isAttributeCategorySupported(sdCategory)) { 2605 Object values = 2606 psCurrent.getSupportedAttributeValues(sdCategory, 2607 docFlavor, 2608 asCurrent); 2609 2610 if (values instanceof Sides[]) { 2611 Sides[] svalues = (Sides[])values; 2612 2613 for (int i = 0; i < svalues.length; i++) { 2614 Sides value = svalues[i]; 2615 2616 if (value == Sides.ONE_SIDED) { 2617 osSupported = true; 2618 } else if (value == Sides.TUMBLE) { 2619 tSupported = true; 2620 } else if (value == Sides.DUPLEX) { 2621 dSupported = true; 2622 } 2623 } 2624 } 2625 } 2626 rbOneSide.setEnabled(osSupported); 2627 rbTumble.setEnabled(tSupported); 2628 rbDuplex.setEnabled(dSupported); 2629 2630 Sides sd = (Sides)asCurrent.get(sdCategory); 2631 if (sd == null) { 2632 sd = (Sides)psCurrent.getDefaultAttributeValue(sdCategory); 2633 if (sd == null) { 2634 sd = Sides.ONE_SIDED; 2635 } 2636 } 2637 2638 if (sd == Sides.ONE_SIDED) { 2639 rbOneSide.setSelected(true); 2640 } else if (sd == Sides.TUMBLE) { 2641 rbTumble.setSelected(true); 2642 } else { // if (sd == Sides.DUPLEX) 2643 rbDuplex.setSelected(true); 2644 } 2645 } 2646 } 2647 2648 2649 @SuppressWarnings("serial") // Superclass is not serializable across versions 2650 private class JobAttributesPanel extends JPanel 2651 implements ActionListener, ChangeListener, FocusListener 2652 { 2653 private final String strTitle = getMsg("border.jobattributes"); 2654 private JLabel lblPriority, lblJobName, lblUserName; 2655 private JSpinner spinPriority; 2656 private SpinnerNumberModel snModel; 2657 private JCheckBox cbJobSheets; 2658 private JTextField tfJobName, tfUserName; 2659 JobAttributesPanel()2660 public JobAttributesPanel() { 2661 super(); 2662 2663 GridBagLayout gridbag = new GridBagLayout(); 2664 GridBagConstraints c = new GridBagConstraints(); 2665 2666 setLayout(gridbag); 2667 setBorder(BorderFactory.createTitledBorder(strTitle)); 2668 2669 c.fill = GridBagConstraints.NONE; 2670 c.insets = compInsets; 2671 c.weighty = 1.0; 2672 2673 cbJobSheets = createCheckBox("checkbox.jobsheets", this); 2674 c.anchor = GridBagConstraints.LINE_START; 2675 addToGB(cbJobSheets, this, gridbag, c); 2676 2677 JPanel pnlTop = new JPanel(); 2678 lblPriority = new JLabel(getMsg("label.priority"), JLabel.TRAILING); 2679 lblPriority.setDisplayedMnemonic(getMnemonic("label.priority")); 2680 2681 pnlTop.add(lblPriority); 2682 snModel = new SpinnerNumberModel(1, 1, 100, 1); 2683 spinPriority = new JSpinner(snModel); 2684 lblPriority.setLabelFor(spinPriority); 2685 // REMIND 2686 ((JSpinner.NumberEditor)spinPriority.getEditor()).getTextField().setColumns(3); 2687 spinPriority.addChangeListener(this); 2688 pnlTop.add(spinPriority); 2689 c.anchor = GridBagConstraints.LINE_END; 2690 c.gridwidth = GridBagConstraints.REMAINDER; 2691 pnlTop.getAccessibleContext().setAccessibleName( 2692 getMsg("label.priority")); 2693 addToGB(pnlTop, this, gridbag, c); 2694 2695 c.fill = GridBagConstraints.HORIZONTAL; 2696 c.anchor = GridBagConstraints.CENTER; 2697 c.weightx = 0.0; 2698 c.gridwidth = 1; 2699 char jmnemonic = getMnemonic("label.jobname"); 2700 lblJobName = new JLabel(getMsg("label.jobname"), JLabel.TRAILING); 2701 lblJobName.setDisplayedMnemonic(jmnemonic); 2702 addToGB(lblJobName, this, gridbag, c); 2703 c.weightx = 1.0; 2704 c.gridwidth = GridBagConstraints.REMAINDER; 2705 tfJobName = new JTextField(); 2706 lblJobName.setLabelFor(tfJobName); 2707 tfJobName.addFocusListener(this); 2708 tfJobName.setFocusAccelerator(jmnemonic); 2709 tfJobName.getAccessibleContext().setAccessibleName( 2710 getMsg("label.jobname")); 2711 addToGB(tfJobName, this, gridbag, c); 2712 2713 c.weightx = 0.0; 2714 c.gridwidth = 1; 2715 char umnemonic = getMnemonic("label.username"); 2716 lblUserName = new JLabel(getMsg("label.username"), JLabel.TRAILING); 2717 lblUserName.setDisplayedMnemonic(umnemonic); 2718 addToGB(lblUserName, this, gridbag, c); 2719 c.gridwidth = GridBagConstraints.REMAINDER; 2720 tfUserName = new JTextField(); 2721 lblUserName.setLabelFor(tfUserName); 2722 tfUserName.addFocusListener(this); 2723 tfUserName.setFocusAccelerator(umnemonic); 2724 tfUserName.getAccessibleContext().setAccessibleName( 2725 getMsg("label.username")); 2726 addToGB(tfUserName, this, gridbag, c); 2727 } 2728 actionPerformed(ActionEvent e)2729 public void actionPerformed(ActionEvent e) { 2730 if (cbJobSheets.isSelected()) { 2731 asCurrent.add(JobSheets.STANDARD); 2732 } else { 2733 asCurrent.add(JobSheets.NONE); 2734 } 2735 } 2736 stateChanged(ChangeEvent e)2737 public void stateChanged(ChangeEvent e) { 2738 asCurrent.add(new JobPriority(snModel.getNumber().intValue())); 2739 } 2740 focusLost(FocusEvent e)2741 public void focusLost(FocusEvent e) { 2742 Object source = e.getSource(); 2743 2744 if (source == tfJobName) { 2745 asCurrent.add(new JobName(tfJobName.getText(), 2746 Locale.getDefault())); 2747 } else if (source == tfUserName) { 2748 asCurrent.add(new RequestingUserName(tfUserName.getText(), 2749 Locale.getDefault())); 2750 } 2751 } 2752 focusGained(FocusEvent e)2753 public void focusGained(FocusEvent e) {} 2754 updateInfo()2755 public void updateInfo() { 2756 Class<JobSheets> jsCategory = JobSheets.class; 2757 Class<JobPriority> jpCategory = JobPriority.class; 2758 Class<JobName> jnCategory = JobName.class; 2759 Class<RequestingUserName> unCategory = RequestingUserName.class; 2760 boolean jsSupported = false; 2761 boolean jpSupported = false; 2762 boolean jnSupported = false; 2763 boolean unSupported = false; 2764 2765 // setup JobSheets checkbox 2766 if (psCurrent.isAttributeCategorySupported(jsCategory)) { 2767 jsSupported = true; 2768 } 2769 JobSheets js = (JobSheets)asCurrent.get(jsCategory); 2770 if (js == null) { 2771 js = (JobSheets)psCurrent.getDefaultAttributeValue(jsCategory); 2772 if (js == null) { 2773 js = JobSheets.STANDARD; 2774 } 2775 } 2776 cbJobSheets.setSelected(js != JobSheets.NONE && jsSupported); 2777 cbJobSheets.setEnabled(jsSupported); 2778 2779 // setup JobPriority spinner 2780 if (!isAWT && psCurrent.isAttributeCategorySupported(jpCategory)) { 2781 jpSupported = true; 2782 } 2783 JobPriority jp = (JobPriority)asCurrent.get(jpCategory); 2784 if (jp == null) { 2785 jp = (JobPriority)psCurrent.getDefaultAttributeValue(jpCategory); 2786 if (jp == null) { 2787 jp = new JobPriority(1); 2788 } 2789 } 2790 int value = jp.getValue(); 2791 if ((value < 1) || (value > 100)) { 2792 value = 1; 2793 } 2794 snModel.setValue(value); 2795 lblPriority.setEnabled(jpSupported); 2796 spinPriority.setEnabled(jpSupported); 2797 2798 // setup JobName text field 2799 if (psCurrent.isAttributeCategorySupported(jnCategory)) { 2800 jnSupported = true; 2801 } 2802 JobName jn = (JobName)asCurrent.get(jnCategory); 2803 if (jn == null) { 2804 jn = (JobName)psCurrent.getDefaultAttributeValue(jnCategory); 2805 if (jn == null) { 2806 jn = new JobName("", Locale.getDefault()); 2807 } 2808 } 2809 tfJobName.setText(jn.getValue()); 2810 tfJobName.setEnabled(jnSupported); 2811 lblJobName.setEnabled(jnSupported); 2812 2813 // setup RequestingUserName text field 2814 if (!isAWT && psCurrent.isAttributeCategorySupported(unCategory)) { 2815 unSupported = true; 2816 } 2817 RequestingUserName un = (RequestingUserName)asCurrent.get(unCategory); 2818 if (un == null) { 2819 un = (RequestingUserName)psCurrent.getDefaultAttributeValue(unCategory); 2820 if (un == null) { 2821 un = new RequestingUserName("", Locale.getDefault()); 2822 } 2823 } 2824 tfUserName.setText(un.getValue()); 2825 tfUserName.setEnabled(unSupported); 2826 lblUserName.setEnabled(unSupported); 2827 } 2828 } 2829 2830 2831 2832 2833 /** 2834 * A special widget that groups a JRadioButton with an associated icon, 2835 * placed to the left of the radio button. 2836 */ 2837 @SuppressWarnings("serial") // Superclass is not serializable across versions 2838 private class IconRadioButton extends JPanel { 2839 2840 private JRadioButton rb; 2841 private JLabel lbl; 2842 IconRadioButton(String key, String img, boolean selected, ButtonGroup bg, ActionListener al)2843 public IconRadioButton(String key, String img, boolean selected, 2844 ButtonGroup bg, ActionListener al) 2845 { 2846 super(new FlowLayout(FlowLayout.LEADING)); 2847 final URL imgURL = getImageResource(img); 2848 @SuppressWarnings("removal") 2849 Icon icon = java.security.AccessController.doPrivileged( 2850 new java.security.PrivilegedAction<Icon>() { 2851 public Icon run() { 2852 Icon icon = new ImageIcon(imgURL); 2853 return icon; 2854 } 2855 }); 2856 lbl = new JLabel(icon); 2857 add(lbl); 2858 2859 rb = createRadioButton(key, al); 2860 rb.setSelected(selected); 2861 addToBG(rb, this, bg); 2862 } 2863 addActionListener(ActionListener al)2864 public void addActionListener(ActionListener al) { 2865 rb.addActionListener(al); 2866 } 2867 isSameAs(Object source)2868 public boolean isSameAs(Object source) { 2869 return (rb == source); 2870 } 2871 setEnabled(boolean enabled)2872 public void setEnabled(boolean enabled) { 2873 rb.setEnabled(enabled); 2874 lbl.setEnabled(enabled); 2875 } 2876 isSelected()2877 public boolean isSelected() { 2878 return rb.isSelected(); 2879 } 2880 setSelected(boolean selected)2881 public void setSelected(boolean selected) { 2882 rb.setSelected(selected); 2883 } 2884 } 2885 2886 /** 2887 * Similar in functionality to the default JFileChooser, except this 2888 * chooser will pop up a "Do you want to overwrite..." dialog if the 2889 * user selects a file that already exists. 2890 */ 2891 @SuppressWarnings("serial") // JDK implementation class 2892 private class ValidatingFileChooser extends JFileChooser { approveSelection()2893 public void approveSelection() { 2894 File selected = getSelectedFile(); 2895 boolean exists; 2896 2897 try { 2898 exists = selected.exists(); 2899 } catch (SecurityException e) { 2900 exists = false; 2901 } 2902 2903 if (exists) { 2904 int val; 2905 val = JOptionPane.showConfirmDialog(this, 2906 getMsg("dialog.overwrite"), 2907 getMsg("dialog.owtitle"), 2908 JOptionPane.YES_NO_OPTION); 2909 if (val != JOptionPane.YES_OPTION) { 2910 return; 2911 } 2912 } 2913 2914 try { 2915 if (selected.createNewFile()) { 2916 selected.delete(); 2917 } 2918 } catch (IOException ioe) { 2919 JOptionPane.showMessageDialog(this, 2920 getMsg("dialog.writeerror")+" "+selected, 2921 getMsg("dialog.owtitle"), 2922 JOptionPane.WARNING_MESSAGE); 2923 return; 2924 } catch (SecurityException se) { 2925 //There is already file read/write access so at this point 2926 // only delete access is denied. Just ignore it because in 2927 // most cases the file created in createNewFile gets 2928 // overwritten anyway. 2929 } 2930 File pFile = selected.getParentFile(); 2931 if ((selected.exists() && 2932 (!selected.isFile() || !selected.canWrite())) || 2933 ((pFile != null) && 2934 (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { 2935 JOptionPane.showMessageDialog(this, 2936 getMsg("dialog.writeerror")+" "+selected, 2937 getMsg("dialog.owtitle"), 2938 JOptionPane.WARNING_MESSAGE); 2939 return; 2940 } 2941 2942 super.approveSelection(); 2943 } 2944 } 2945 } 2946