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