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