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