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