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