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