1 /* 2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.print; 27 28 import java.awt.BorderLayout; 29 import java.awt.Color; 30 import java.awt.Component; 31 import java.awt.Container; 32 import java.awt.Dialog; 33 import java.awt.FlowLayout; 34 import java.awt.Frame; 35 import java.awt.GraphicsConfiguration; 36 import java.awt.GridBagLayout; 37 import java.awt.GridBagConstraints; 38 import java.awt.GridLayout; 39 import java.awt.Insets; 40 import java.awt.Toolkit; 41 import java.awt.event.ActionEvent; 42 import java.awt.event.ActionListener; 43 import java.awt.event.FocusEvent; 44 import java.awt.event.FocusListener; 45 import java.awt.event.ItemEvent; 46 import java.awt.event.ItemListener; 47 import java.awt.event.WindowEvent; 48 import java.awt.event.WindowAdapter; 49 import java.awt.print.PrinterJob; 50 import java.io.File; 51 import java.io.FilePermission; 52 import java.io.IOException; 53 import java.net.URI; 54 import java.net.URL; 55 import java.text.DecimalFormat; 56 import java.util.Locale; 57 import java.util.ResourceBundle; 58 import java.util.Vector; 59 import javax.print.*; 60 import javax.print.attribute.*; 61 import javax.print.attribute.standard.*; 62 import javax.swing.*; 63 import javax.swing.border.Border; 64 import javax.swing.border.EmptyBorder; 65 import javax.swing.border.TitledBorder; 66 import javax.swing.event.ChangeEvent; 67 import javax.swing.event.ChangeListener; 68 import javax.swing.event.DocumentEvent; 69 import javax.swing.event.DocumentListener; 70 import javax.swing.event.PopupMenuEvent; 71 import javax.swing.event.PopupMenuListener; 72 import javax.swing.text.NumberFormatter; 73 import sun.print.SunPageSelection; 74 import java.awt.event.KeyEvent; 75 import java.net.URISyntaxException; 76 import java.lang.reflect.Field; 77 import java.net.MalformedURLException; 78 79 /** 80 * A class which implements a cross-platform print dialog. 81 * 82 * @author Chris Campbell 83 */ 84 @SuppressWarnings("serial") // Superclass is not serializable across versions 85 public class ServiceDialog extends JDialog implements ActionListener { 86 87 /** 88 * Waiting print status (user response pending). 89 */ 90 public static final int WAITING = 0; 91 92 /** 93 * Approve print status (user activated "Print" or "OK"). 94 */ 95 public static final int APPROVE = 1; 96 97 /** 98 * Cancel print status (user activated "Cancel"); 99 */ 100 public static final int CANCEL = 2; 101 102 private static final String strBundle = "sun.print.resources.serviceui"; 103 private static final Insets panelInsets = new Insets(6, 6, 6, 6); 104 private static final Insets compInsets = new Insets(3, 6, 3, 6); 105 106 private static ResourceBundle messageRB; 107 private JTabbedPane tpTabs; 108 private JButton btnCancel, btnApprove; 109 private PrintService[] services; 110 private int defaultServiceIndex; 111 private PrintRequestAttributeSet asOriginal; 112 private HashPrintRequestAttributeSet asCurrent; 113 private PrintService psCurrent; 114 private DocFlavor docFlavor; 115 private int status; 116 117 private ValidatingFileChooser jfc; 118 119 private GeneralPanel pnlGeneral; 120 private PageSetupPanel pnlPageSetup; 121 private AppearancePanel pnlAppearance; 122 123 private boolean isAWT = false; 124 static { 125 initResource(); 126 } 127 128 129 /** 130 * Constructor for the "standard" print dialog (containing all relevant 131 * tabs) 132 */ 133 public ServiceDialog(GraphicsConfiguration gc, 134 int x, int y, 135 PrintService[] services, 136 int defaultServiceIndex, 137 DocFlavor flavor, 138 PrintRequestAttributeSet attributes, 139 Dialog dialog) 140 { 141 super(dialog, getMsg("dialog.printtitle"), true, gc); 142 initPrintDialog(x, y, services, defaultServiceIndex, 143 flavor, attributes); 144 } 145 146 147 148 /** 149 * Constructor for the "standard" print dialog (containing all relevant 150 * tabs) 151 */ 152 public ServiceDialog(GraphicsConfiguration gc, 153 int x, int y, 154 PrintService[] services, 155 int defaultServiceIndex, 156 DocFlavor flavor, 157 PrintRequestAttributeSet attributes, 158 Frame frame) 159 { 160 super(frame, getMsg("dialog.printtitle"), true, gc); 161 initPrintDialog(x, y, services, defaultServiceIndex, 162 flavor, attributes); 163 } 164 165 166 /** 167 * Initialize print dialog. 168 */ 169 void initPrintDialog(int x, int y, 170 PrintService[] services, 171 int defaultServiceIndex, 172 DocFlavor flavor, 173 PrintRequestAttributeSet attributes) 174 { 175 this.services = services; 176 this.defaultServiceIndex = defaultServiceIndex; 177 this.asOriginal = attributes; 178 this.asCurrent = new HashPrintRequestAttributeSet(attributes); 179 this.psCurrent = services[defaultServiceIndex]; 180 this.docFlavor = flavor; 181 SunPageSelection pages = 182 (SunPageSelection)attributes.get(SunPageSelection.class); 183 if (pages != null) { 184 isAWT = true; 185 } 186 187 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 @SuppressWarnings("deprecation") 796 public void actionPerformed(ActionEvent e) { 797 Object source = e.getSource(); 798 799 if (source == btnProperties) { 800 if (uiFactory != null) { 801 JDialog dialog = (JDialog)uiFactory.getUI( 802 ServiceUIFactory.MAIN_UIROLE, 803 ServiceUIFactory.JDIALOG_UI); 804 805 if (dialog != null) { 806 dialog.show(); 807 } else { 808 DocumentPropertiesUI docPropertiesUI = null; 809 try { 810 docPropertiesUI = 811 (DocumentPropertiesUI)uiFactory.getUI 812 (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE, 813 DocumentPropertiesUI.DOCPROPERTIESCLASSNAME); 814 } catch (Exception ex) { 815 } 816 if (docPropertiesUI != null) { 817 PrinterJobWrapper wrapper = (PrinterJobWrapper) 818 asCurrent.get(PrinterJobWrapper.class); 819 if (wrapper == null) { 820 return; // should not happen, defensive only. 821 } 822 PrinterJob job = wrapper.getPrinterJob(); 823 if (job == null) { 824 return; // should not happen, defensive only. 825 } 826 PrintRequestAttributeSet newAttrs = 827 docPropertiesUI.showDocumentProperties 828 (job, ServiceDialog.this, psCurrent, asCurrent); 829 if (newAttrs != null) { 830 asCurrent.addAll(newAttrs); 831 updatePanels(); 832 } 833 } 834 } 835 } 836 } 837 } 838 839 public void itemStateChanged(ItemEvent e) { 840 if (e.getStateChange() == ItemEvent.SELECTED) { 841 int index = cbName.getSelectedIndex(); 842 843 if ((index >= 0) && (index < services.length)) { 844 if (!services[index].equals(psCurrent)) { 845 psCurrent = services[index]; 846 uiFactory = psCurrent.getServiceUIFactory(); 847 changedService = true; 848 849 Destination dest = 850 (Destination)asOriginal.get(Destination.class); 851 // to preserve the state of Print To File 852 if ((dest != null || isPrintToFileSelected()) 853 && psCurrent.isAttributeCategorySupported( 854 Destination.class)) { 855 856 if (dest != null) { 857 asCurrent.add(dest); 858 } else { 859 dest = (Destination)psCurrent. 860 getDefaultAttributeValue(Destination.class); 861 // "dest" should not be null. The following code 862 // is only added to safeguard against a possible 863 // buggy implementation of a PrintService having a 864 // null default Destination. 865 if (dest == null) { 866 try { 867 dest = 868 new Destination(new URI("file:out.prn")); 869 } catch (URISyntaxException ue) { 870 } 871 } 872 873 if (dest != null) { 874 asCurrent.add(dest); 875 } 876 } 877 } else { 878 asCurrent.remove(Destination.class); 879 } 880 } 881 } 882 } 883 } 884 885 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 886 changedService = false; 887 } 888 889 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 890 if (changedService) { 891 changedService = false; 892 updatePanels(); 893 } 894 } 895 896 public void popupMenuCanceled(PopupMenuEvent e) { 897 } 898 899 /** 900 * We disable the "Print To File" checkbox if this returns false 901 */ 902 private boolean allowedToPrintToFile() { 903 try { 904 throwPrintToFile(); 905 return true; 906 } catch (SecurityException e) { 907 return false; 908 } 909 } 910 911 /** 912 * Break this out as it may be useful when we allow API to 913 * specify printing to a file. In that case its probably right 914 * to throw a SecurityException if the permission is not granted. 915 */ 916 private void throwPrintToFile() { 917 SecurityManager security = System.getSecurityManager(); 918 if (security != null) { 919 if (printToFilePermission == null) { 920 printToFilePermission = 921 new FilePermission("<<ALL FILES>>", "read,write"); 922 } 923 security.checkPermission(printToFilePermission); 924 } 925 } 926 927 public void updateInfo() { 928 Class<Destination> dstCategory = Destination.class; 929 boolean dstSupported = false; 930 boolean dstSelected = false; 931 boolean dstAllowed = filePermission ? 932 allowedToPrintToFile() : false; 933 934 // setup Destination (print-to-file) widgets 935 Destination dst = (Destination)asCurrent.get(dstCategory); 936 if (dst != null) { 937 try { 938 dst.getURI().toURL(); 939 if (psCurrent.isAttributeValueSupported(dst, docFlavor, 940 asCurrent)) { 941 dstSupported = true; 942 dstSelected = true; 943 } 944 } catch (MalformedURLException ex) { 945 dstSupported = true; 946 } 947 } else { 948 if (psCurrent.isAttributeCategorySupported(dstCategory)) { 949 dstSupported = true; 950 } 951 } 952 cbPrintToFile.setEnabled(dstSupported && dstAllowed); 953 cbPrintToFile.setSelected(dstSelected && dstAllowed 954 && dstSupported); 955 956 // setup PrintService information widgets 957 Attribute type = psCurrent.getAttribute(PrinterMakeAndModel.class); 958 if (type != null) { 959 lblType.setText(type.toString()); 960 } 961 Attribute status = 962 psCurrent.getAttribute(PrinterIsAcceptingJobs.class); 963 if (status != null) { 964 lblStatus.setText(getMsg(status.toString())); 965 } 966 Attribute info = psCurrent.getAttribute(PrinterInfo.class); 967 if (info != null) { 968 lblInfo.setText(info.toString()); 969 } 970 btnProperties.setEnabled(uiFactory != null); 971 } 972 } 973 974 @SuppressWarnings("serial") // Superclass is not serializable across versions 975 private class PrintRangePanel extends JPanel 976 implements ActionListener, FocusListener 977 { 978 private final String strTitle = getMsg("border.printrange"); 979 private final PageRanges prAll = new PageRanges(1, Integer.MAX_VALUE); 980 private JRadioButton rbAll, rbPages, rbSelect; 981 private JFormattedTextField tfRangeFrom, tfRangeTo; 982 private JLabel lblRangeTo; 983 private boolean prSupported; 984 private boolean prPgRngSupported; 985 986 public PrintRangePanel() { 987 super(); 988 989 GridBagLayout gridbag = new GridBagLayout(); 990 GridBagConstraints c = new GridBagConstraints(); 991 992 setLayout(gridbag); 993 setBorder(BorderFactory.createTitledBorder(strTitle)); 994 995 c.fill = GridBagConstraints.BOTH; 996 c.insets = compInsets; 997 c.gridwidth = GridBagConstraints.REMAINDER; 998 999 ButtonGroup bg = new ButtonGroup(); 1000 JPanel pnlTop = new JPanel(new FlowLayout(FlowLayout.LEADING)); 1001 rbAll = createRadioButton("radiobutton.rangeall", this); 1002 rbAll.setSelected(true); 1003 bg.add(rbAll); 1004 pnlTop.add(rbAll); 1005 addToGB(pnlTop, this, gridbag, c); 1006 1007 // Selection never seemed to work so I'm commenting this part. 1008 /* 1009 if (isAWT) { 1010 JPanel pnlMiddle = 1011 new JPanel(new FlowLayout(FlowLayout.LEADING)); 1012 rbSelect = 1013 createRadioButton("radiobutton.selection", this); 1014 bg.add(rbSelect); 1015 pnlMiddle.add(rbSelect); 1016 addToGB(pnlMiddle, this, gridbag, c); 1017 } 1018 */ 1019 1020 JPanel pnlBottom = new JPanel(new FlowLayout(FlowLayout.LEADING)); 1021 rbPages = createRadioButton("radiobutton.rangepages", this); 1022 bg.add(rbPages); 1023 pnlBottom.add(rbPages); 1024 DecimalFormat format = new DecimalFormat("####0"); 1025 format.setMinimumFractionDigits(0); 1026 format.setMaximumFractionDigits(0); 1027 format.setMinimumIntegerDigits(0); 1028 format.setMaximumIntegerDigits(5); 1029 format.setParseIntegerOnly(true); 1030 format.setDecimalSeparatorAlwaysShown(false); 1031 NumberFormatter nf = new NumberFormatter(format); 1032 nf.setMinimum(1); 1033 nf.setMaximum(Integer.MAX_VALUE); 1034 nf.setAllowsInvalid(true); 1035 nf.setCommitsOnValidEdit(true); 1036 tfRangeFrom = new JFormattedTextField(nf); 1037 tfRangeFrom.setColumns(4); 1038 tfRangeFrom.setEnabled(false); 1039 tfRangeFrom.addActionListener(this); 1040 tfRangeFrom.addFocusListener(this); 1041 tfRangeFrom.setFocusLostBehavior( 1042 JFormattedTextField.PERSIST); 1043 tfRangeFrom.getAccessibleContext().setAccessibleName( 1044 getMsg("radiobutton.rangepages")); 1045 pnlBottom.add(tfRangeFrom); 1046 lblRangeTo = new JLabel(getMsg("label.rangeto")); 1047 lblRangeTo.setEnabled(false); 1048 pnlBottom.add(lblRangeTo); 1049 NumberFormatter nfto; 1050 try { 1051 nfto = (NumberFormatter)nf.clone(); 1052 } catch (CloneNotSupportedException e) { 1053 nfto = new NumberFormatter(); 1054 } 1055 tfRangeTo = new JFormattedTextField(nfto); 1056 tfRangeTo.setColumns(4); 1057 tfRangeTo.setEnabled(false); 1058 tfRangeTo.addFocusListener(this); 1059 tfRangeTo.getAccessibleContext().setAccessibleName( 1060 getMsg("label.rangeto")); 1061 pnlBottom.add(tfRangeTo); 1062 addToGB(pnlBottom, this, gridbag, c); 1063 } 1064 1065 public void actionPerformed(ActionEvent e) { 1066 Object source = e.getSource(); 1067 SunPageSelection select = SunPageSelection.ALL; 1068 1069 setupRangeWidgets(); 1070 1071 if (source == rbAll) { 1072 asCurrent.add(prAll); 1073 } else if (source == rbSelect) { 1074 select = SunPageSelection.SELECTION; 1075 } else if (source == rbPages || 1076 source == tfRangeFrom || 1077 source == tfRangeTo) { 1078 updateRangeAttribute(); 1079 select = SunPageSelection.RANGE; 1080 } 1081 1082 if (isAWT) { 1083 asCurrent.add(select); 1084 } 1085 } 1086 1087 public void focusLost(FocusEvent e) { 1088 Object source = e.getSource(); 1089 1090 if ((source == tfRangeFrom) || (source == tfRangeTo)) { 1091 updateRangeAttribute(); 1092 } 1093 } 1094 1095 public void focusGained(FocusEvent e) {} 1096 1097 private void setupRangeWidgets() { 1098 boolean rangeEnabled = (rbPages.isSelected() && prPgRngSupported); 1099 tfRangeFrom.setEnabled(rangeEnabled); 1100 tfRangeTo.setEnabled(rangeEnabled); 1101 lblRangeTo.setEnabled(rangeEnabled); 1102 } 1103 1104 private void updateRangeAttribute() { 1105 String strFrom = tfRangeFrom.getText(); 1106 String strTo = tfRangeTo.getText(); 1107 1108 int min; 1109 int max; 1110 1111 try { 1112 min = Integer.parseInt(strFrom); 1113 } catch (NumberFormatException e) { 1114 min = 1; 1115 } 1116 1117 try { 1118 max = Integer.parseInt(strTo); 1119 } catch (NumberFormatException e) { 1120 max = min; 1121 } 1122 1123 if (min < 1) { 1124 min = 1; 1125 tfRangeFrom.setValue(1); 1126 } 1127 1128 if (max < min) { 1129 max = min; 1130 tfRangeTo.setValue(min); 1131 } 1132 1133 PageRanges pr = new PageRanges(min, max); 1134 asCurrent.add(pr); 1135 } 1136 1137 public void updateInfo() { 1138 Class<PageRanges> prCategory = PageRanges.class; 1139 prSupported = false; 1140 1141 if (psCurrent.isAttributeCategorySupported(prCategory) || 1142 isAWT) { 1143 prSupported = true; 1144 prPgRngSupported = psCurrent.isAttributeValueSupported(prAll, 1145 docFlavor, 1146 asCurrent); 1147 } 1148 1149 SunPageSelection select = SunPageSelection.ALL; 1150 int min = 1; 1151 int max = 1; 1152 1153 PageRanges pr = (PageRanges)asCurrent.get(prCategory); 1154 if (pr != null) { 1155 if (!pr.equals(prAll)) { 1156 select = SunPageSelection.RANGE; 1157 1158 int[][] members = pr.getMembers(); 1159 if ((members.length > 0) && 1160 (members[0].length > 1)) { 1161 min = members[0][0]; 1162 max = members[0][1]; 1163 } 1164 } 1165 } 1166 1167 if (isAWT) { 1168 select = (SunPageSelection)asCurrent.get( 1169 SunPageSelection.class); 1170 } 1171 1172 if (select == SunPageSelection.ALL) { 1173 rbAll.setSelected(true); 1174 } else if (select == SunPageSelection.SELECTION) { 1175 // Comment this for now - rbSelect is not initialized 1176 // because Selection button is not added. 1177 // See PrintRangePanel above. 1178 1179 //rbSelect.setSelected(true); 1180 } else { // RANGE 1181 rbPages.setSelected(true); 1182 } 1183 tfRangeFrom.setValue(min); 1184 tfRangeTo.setValue(max); 1185 rbAll.setEnabled(prSupported); 1186 rbPages.setEnabled(prPgRngSupported); 1187 setupRangeWidgets(); 1188 } 1189 } 1190 1191 @SuppressWarnings("serial") // Superclass is not serializable across versions 1192 private class CopiesPanel extends JPanel 1193 implements ActionListener, ChangeListener 1194 { 1195 private final String strTitle = getMsg("border.copies"); 1196 private SpinnerNumberModel snModel; 1197 private JSpinner spinCopies; 1198 private JLabel lblCopies; 1199 private JCheckBox cbCollate; 1200 private boolean scSupported; 1201 1202 public CopiesPanel() { 1203 super(); 1204 1205 GridBagLayout gridbag = new GridBagLayout(); 1206 GridBagConstraints c = new GridBagConstraints(); 1207 1208 setLayout(gridbag); 1209 setBorder(BorderFactory.createTitledBorder(strTitle)); 1210 1211 c.fill = GridBagConstraints.HORIZONTAL; 1212 c.insets = compInsets; 1213 1214 lblCopies = new JLabel(getMsg("label.numcopies"), JLabel.TRAILING); 1215 lblCopies.setDisplayedMnemonic(getMnemonic("label.numcopies")); 1216 lblCopies.getAccessibleContext().setAccessibleName( 1217 getMsg("label.numcopies")); 1218 addToGB(lblCopies, this, gridbag, c); 1219 1220 snModel = new SpinnerNumberModel(1, 1, 999, 1); 1221 spinCopies = new JSpinner(snModel); 1222 lblCopies.setLabelFor(spinCopies); 1223 // REMIND 1224 ((JSpinner.NumberEditor)spinCopies.getEditor()).getTextField().setColumns(3); 1225 spinCopies.addChangeListener(this); 1226 c.gridwidth = GridBagConstraints.REMAINDER; 1227 addToGB(spinCopies, this, gridbag, c); 1228 1229 cbCollate = createCheckBox("checkbox.collate", this); 1230 cbCollate.setEnabled(false); 1231 addToGB(cbCollate, this, gridbag, c); 1232 } 1233 1234 public void actionPerformed(ActionEvent e) { 1235 if (cbCollate.isSelected()) { 1236 asCurrent.add(SheetCollate.COLLATED); 1237 } else { 1238 asCurrent.add(SheetCollate.UNCOLLATED); 1239 } 1240 } 1241 1242 public void stateChanged(ChangeEvent e) { 1243 updateCollateCB(); 1244 1245 asCurrent.add(new Copies(snModel.getNumber().intValue())); 1246 } 1247 1248 private void updateCollateCB() { 1249 int num = snModel.getNumber().intValue(); 1250 if (isAWT) { 1251 // sync with IPPPrintService#getSupportedAttributeCategories 1252 // where for linux, SheetCollate is not added to supported category 1253 String osname = java.security.AccessController.doPrivileged( 1254 new sun.security.action.GetPropertyAction("os.name")); 1255 if (osname.equals("Linux")) { 1256 cbCollate.setEnabled((num > 1) && scSupported); 1257 } else { 1258 cbCollate.setEnabled(true); 1259 } 1260 } else { 1261 cbCollate.setEnabled((num > 1) && scSupported); 1262 } 1263 } 1264 1265 public void updateInfo() { 1266 Class<Copies> cpCategory = Copies.class; 1267 Class<SheetCollate> scCategory = SheetCollate.class; 1268 boolean cpSupported = false; 1269 scSupported = false; 1270 1271 // setup Copies spinner 1272 if (psCurrent.isAttributeCategorySupported(cpCategory)) { 1273 cpSupported = true; 1274 } 1275 CopiesSupported cs = 1276 (CopiesSupported)psCurrent.getSupportedAttributeValues( 1277 cpCategory, null, null); 1278 if (cs == null) { 1279 cs = new CopiesSupported(1, 999); 1280 } 1281 Copies cp = (Copies)asCurrent.get(cpCategory); 1282 if (cp == null) { 1283 cp = (Copies)psCurrent.getDefaultAttributeValue(cpCategory); 1284 if (cp == null) { 1285 cp = new Copies(1); 1286 } 1287 } 1288 spinCopies.setEnabled(cpSupported); 1289 lblCopies.setEnabled(cpSupported); 1290 1291 int[][] members = cs.getMembers(); 1292 int min, max; 1293 if ((members.length > 0) && (members[0].length > 0)) { 1294 min = members[0][0]; 1295 max = members[0][1]; 1296 } else { 1297 min = 1; 1298 max = Integer.MAX_VALUE; 1299 } 1300 snModel.setMinimum(min); 1301 snModel.setMaximum(max); 1302 1303 int value = cp.getValue(); 1304 if ((value < min) || (value > max)) { 1305 value = min; 1306 } 1307 snModel.setValue(value); 1308 1309 // setup Collate checkbox 1310 if (psCurrent.isAttributeCategorySupported(scCategory)) { 1311 scSupported = true; 1312 } 1313 SheetCollate sc = (SheetCollate)asCurrent.get(scCategory); 1314 if (sc == null) { 1315 sc = (SheetCollate)psCurrent.getDefaultAttributeValue(scCategory); 1316 if (sc == null) { 1317 sc = SheetCollate.UNCOLLATED; 1318 } 1319 if (sc != null && 1320 !psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { 1321 scSupported = false; 1322 } 1323 } else { 1324 if (!psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { 1325 scSupported = false; 1326 } 1327 } 1328 cbCollate.setSelected(sc == SheetCollate.COLLATED && scSupported); 1329 updateCollateCB(); 1330 } 1331 } 1332 1333 1334 1335 1336 /** 1337 * The "Page Setup" tab. Includes the controls for MediaSource/MediaTray, 1338 * OrientationRequested, and Sides. 1339 */ 1340 @SuppressWarnings("serial") // Superclass is not serializable across versions 1341 private class PageSetupPanel extends JPanel { 1342 1343 private MediaPanel pnlMedia; 1344 private OrientationPanel pnlOrientation; 1345 private MarginsPanel pnlMargins; 1346 1347 public PageSetupPanel() { 1348 super(); 1349 1350 GridBagLayout gridbag = new GridBagLayout(); 1351 GridBagConstraints c = new GridBagConstraints(); 1352 1353 setLayout(gridbag); 1354 1355 c.fill = GridBagConstraints.BOTH; 1356 c.insets = panelInsets; 1357 c.weightx = 1.0; 1358 c.weighty = 1.0; 1359 1360 c.gridwidth = GridBagConstraints.REMAINDER; 1361 pnlMedia = new MediaPanel(); 1362 addToGB(pnlMedia, this, gridbag, c); 1363 1364 pnlOrientation = new OrientationPanel(); 1365 c.gridwidth = GridBagConstraints.RELATIVE; 1366 addToGB(pnlOrientation, this, gridbag, c); 1367 1368 pnlMargins = new MarginsPanel(); 1369 pnlOrientation.addOrientationListener(pnlMargins); 1370 pnlMedia.addMediaListener(pnlMargins); 1371 c.gridwidth = GridBagConstraints.REMAINDER; 1372 addToGB(pnlMargins, this, gridbag, c); 1373 } 1374 1375 public void updateInfo() { 1376 pnlMedia.updateInfo(); 1377 pnlOrientation.updateInfo(); 1378 pnlMargins.updateInfo(); 1379 } 1380 } 1381 1382 @SuppressWarnings("serial") // Superclass is not serializable across versions 1383 private class MarginsPanel extends JPanel 1384 implements ActionListener, FocusListener { 1385 1386 private final String strTitle = getMsg("border.margins"); 1387 private JFormattedTextField leftMargin, rightMargin, 1388 topMargin, bottomMargin; 1389 private JLabel lblLeft, lblRight, lblTop, lblBottom; 1390 private int units = MediaPrintableArea.MM; 1391 // storage for the last margin values calculated, -ve is uninitialised 1392 private float lmVal = -1f,rmVal = -1f, tmVal = -1f, bmVal = -1f; 1393 // storage for margins as objects mapped into orientation for display 1394 private Float lmObj,rmObj,tmObj,bmObj; 1395 1396 public MarginsPanel() { 1397 super(); 1398 1399 GridBagLayout gridbag = new GridBagLayout(); 1400 GridBagConstraints c = new GridBagConstraints(); 1401 c.fill = GridBagConstraints.HORIZONTAL; 1402 c.weightx = 1.0; 1403 c.weighty = 0.0; 1404 c.insets = compInsets; 1405 1406 setLayout(gridbag); 1407 setBorder(BorderFactory.createTitledBorder(strTitle)); 1408 1409 String unitsKey = "label.millimetres"; 1410 String defaultCountry = Locale.getDefault().getCountry(); 1411 if (defaultCountry != null && 1412 (defaultCountry.equals("") || 1413 defaultCountry.equals(Locale.US.getCountry()) || 1414 defaultCountry.equals(Locale.CANADA.getCountry()))) { 1415 unitsKey = "label.inches"; 1416 units = MediaPrintableArea.INCH; 1417 } 1418 String unitsMsg = getMsg(unitsKey); 1419 1420 DecimalFormat format; 1421 if (units == MediaPrintableArea.MM) { 1422 format = new DecimalFormat("###.##"); 1423 format.setMaximumIntegerDigits(3); 1424 } else { 1425 format = new DecimalFormat("##.##"); 1426 format.setMaximumIntegerDigits(2); 1427 } 1428 1429 format.setMinimumFractionDigits(1); 1430 format.setMaximumFractionDigits(2); 1431 format.setMinimumIntegerDigits(1); 1432 format.setParseIntegerOnly(false); 1433 format.setDecimalSeparatorAlwaysShown(true); 1434 NumberFormatter nf = new NumberFormatter(format); 1435 nf.setMinimum(Float.valueOf(0.0f)); 1436 nf.setMaximum(Float.valueOf(999.0f)); 1437 nf.setAllowsInvalid(true); 1438 nf.setCommitsOnValidEdit(true); 1439 1440 leftMargin = new JFormattedTextField(nf); 1441 leftMargin.addFocusListener(this); 1442 leftMargin.addActionListener(this); 1443 leftMargin.getAccessibleContext().setAccessibleName( 1444 getMsg("label.leftmargin")); 1445 rightMargin = new JFormattedTextField(nf); 1446 rightMargin.addFocusListener(this); 1447 rightMargin.addActionListener(this); 1448 rightMargin.getAccessibleContext().setAccessibleName( 1449 getMsg("label.rightmargin")); 1450 topMargin = new JFormattedTextField(nf); 1451 topMargin.addFocusListener(this); 1452 topMargin.addActionListener(this); 1453 topMargin.getAccessibleContext().setAccessibleName( 1454 getMsg("label.topmargin")); 1455 1456 bottomMargin = new JFormattedTextField(nf); 1457 bottomMargin.addFocusListener(this); 1458 bottomMargin.addActionListener(this); 1459 bottomMargin.getAccessibleContext().setAccessibleName( 1460 getMsg("label.bottommargin")); 1461 1462 c.gridwidth = GridBagConstraints.RELATIVE; 1463 lblLeft = new JLabel(getMsg("label.leftmargin") + " " + unitsMsg, 1464 JLabel.LEADING); 1465 lblLeft.setDisplayedMnemonic(getMnemonic("label.leftmargin")); 1466 lblLeft.setLabelFor(leftMargin); 1467 addToGB(lblLeft, this, gridbag, c); 1468 1469 c.gridwidth = GridBagConstraints.REMAINDER; 1470 lblRight = new JLabel(getMsg("label.rightmargin") + " " + unitsMsg, 1471 JLabel.LEADING); 1472 lblRight.setDisplayedMnemonic(getMnemonic("label.rightmargin")); 1473 lblRight.setLabelFor(rightMargin); 1474 addToGB(lblRight, this, gridbag, c); 1475 1476 c.gridwidth = GridBagConstraints.RELATIVE; 1477 addToGB(leftMargin, this, gridbag, c); 1478 1479 c.gridwidth = GridBagConstraints.REMAINDER; 1480 addToGB(rightMargin, this, gridbag, c); 1481 1482 // add an invisible spacing component. 1483 addToGB(new JPanel(), this, gridbag, c); 1484 1485 c.gridwidth = GridBagConstraints.RELATIVE; 1486 lblTop = new JLabel(getMsg("label.topmargin") + " " + unitsMsg, 1487 JLabel.LEADING); 1488 lblTop.setDisplayedMnemonic(getMnemonic("label.topmargin")); 1489 lblTop.setLabelFor(topMargin); 1490 addToGB(lblTop, this, gridbag, c); 1491 1492 c.gridwidth = GridBagConstraints.REMAINDER; 1493 lblBottom = new JLabel(getMsg("label.bottommargin") + 1494 " " + unitsMsg, JLabel.LEADING); 1495 lblBottom.setDisplayedMnemonic(getMnemonic("label.bottommargin")); 1496 lblBottom.setLabelFor(bottomMargin); 1497 addToGB(lblBottom, this, gridbag, c); 1498 1499 c.gridwidth = GridBagConstraints.RELATIVE; 1500 addToGB(topMargin, this, gridbag, c); 1501 1502 c.gridwidth = GridBagConstraints.REMAINDER; 1503 addToGB(bottomMargin, this, gridbag, c); 1504 1505 } 1506 1507 public void actionPerformed(ActionEvent e) { 1508 Object source = e.getSource(); 1509 updateMargins(source); 1510 } 1511 1512 public void focusLost(FocusEvent e) { 1513 Object source = e.getSource(); 1514 updateMargins(source); 1515 } 1516 1517 public void focusGained(FocusEvent e) {} 1518 1519 /* Get the numbers, use to create a MPA. 1520 * If its valid, accept it and update the attribute set. 1521 * If its not valid, then reject it and call updateInfo() 1522 * to re-establish the previous entries. 1523 */ 1524 public void updateMargins(Object source) { 1525 if (!(source instanceof JFormattedTextField)) { 1526 return; 1527 } else { 1528 JFormattedTextField tf = (JFormattedTextField)source; 1529 Float val = (Float)tf.getValue(); 1530 if (val == null) { 1531 return; 1532 } 1533 if (tf == leftMargin && val.equals(lmObj)) { 1534 return; 1535 } 1536 if (tf == rightMargin && val.equals(rmObj)) { 1537 return; 1538 } 1539 if (tf == topMargin && val.equals(tmObj)) { 1540 return; 1541 } 1542 if (tf == bottomMargin && val.equals(bmObj)) { 1543 return; 1544 } 1545 } 1546 1547 Float lmTmpObj = (Float)leftMargin.getValue(); 1548 Float rmTmpObj = (Float)rightMargin.getValue(); 1549 Float tmTmpObj = (Float)topMargin.getValue(); 1550 Float bmTmpObj = (Float)bottomMargin.getValue(); 1551 1552 float lm = lmTmpObj.floatValue(); 1553 float rm = rmTmpObj.floatValue(); 1554 float tm = tmTmpObj.floatValue(); 1555 float bm = bmTmpObj.floatValue(); 1556 1557 /* adjust for orientation */ 1558 Class<OrientationRequested> orCategory = OrientationRequested.class; 1559 OrientationRequested or = 1560 (OrientationRequested)asCurrent.get(orCategory); 1561 1562 if (or == null) { 1563 or = (OrientationRequested) 1564 psCurrent.getDefaultAttributeValue(orCategory); 1565 } 1566 1567 float tmp; 1568 if (or == OrientationRequested.REVERSE_PORTRAIT) { 1569 tmp = lm; lm = rm; rm = tmp; 1570 tmp = tm; tm = bm; bm = tmp; 1571 } else if (or == OrientationRequested.LANDSCAPE) { 1572 tmp = lm; 1573 lm = tm; 1574 tm = rm; 1575 rm = bm; 1576 bm = tmp; 1577 } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { 1578 tmp = lm; 1579 lm = bm; 1580 bm = rm; 1581 rm = tm; 1582 tm = tmp; 1583 } 1584 MediaPrintableArea mpa; 1585 if ((mpa = validateMargins(lm, rm, tm, bm)) != null) { 1586 asCurrent.add(mpa); 1587 lmVal = lm; 1588 rmVal = rm; 1589 tmVal = tm; 1590 bmVal = bm; 1591 lmObj = lmTmpObj; 1592 rmObj = rmTmpObj; 1593 tmObj = tmTmpObj; 1594 bmObj = bmTmpObj; 1595 } else { 1596 if (lmObj == null || rmObj == null || 1597 tmObj == null || bmObj == null) { 1598 return; 1599 } else { 1600 leftMargin.setValue(lmObj); 1601 rightMargin.setValue(rmObj); 1602 topMargin.setValue(tmObj); 1603 bottomMargin.setValue(bmObj); 1604 1605 } 1606 } 1607 } 1608 1609 /* 1610 * This method either accepts the values and creates a new 1611 * MediaPrintableArea, or does nothing. 1612 * It should not attempt to create a printable area from anything 1613 * other than the exact values passed in. 1614 * But REMIND/TBD: it would be user friendly to replace margins the 1615 * user entered but are out of bounds with the minimum. 1616 * At that point this method will need to take responsibility for 1617 * updating the "stored" values and the UI. 1618 */ 1619 private MediaPrintableArea validateMargins(float lm, float rm, 1620 float tm, float bm) { 1621 1622 Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; 1623 MediaPrintableArea mpa; 1624 MediaPrintableArea mpaMax = null; 1625 MediaSize mediaSize = null; 1626 1627 Media media = (Media)asCurrent.get(Media.class); 1628 if (media == null || !(media instanceof MediaSizeName)) { 1629 media = (Media)psCurrent.getDefaultAttributeValue(Media.class); 1630 } 1631 if (media != null && (media instanceof MediaSizeName)) { 1632 MediaSizeName msn = (MediaSizeName)media; 1633 mediaSize = MediaSize.getMediaSizeForName(msn); 1634 } 1635 if (mediaSize == null) { 1636 mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); 1637 } 1638 1639 if (media != null) { 1640 PrintRequestAttributeSet tmpASet = 1641 new HashPrintRequestAttributeSet(asCurrent); 1642 tmpASet.add(media); 1643 1644 Object values = 1645 psCurrent.getSupportedAttributeValues(mpaCategory, 1646 docFlavor, 1647 tmpASet); 1648 if (values instanceof MediaPrintableArea[] && 1649 ((MediaPrintableArea[])values).length > 0) { 1650 mpaMax = ((MediaPrintableArea[])values)[0]; 1651 1652 } 1653 } 1654 if (mpaMax == null) { 1655 mpaMax = new MediaPrintableArea(0f, 0f, 1656 mediaSize.getX(units), 1657 mediaSize.getY(units), 1658 units); 1659 } 1660 1661 float wid = mediaSize.getX(units); 1662 float hgt = mediaSize.getY(units); 1663 float pax = lm; 1664 float pay = tm; 1665 float par = rm; 1666 float pab = bm; 1667 float paw = wid - lm - rm; 1668 float pah = hgt - tm - bm; 1669 1670 if (paw <= 0f || pah <= 0f || pax < 0f || pay < 0f || 1671 par <= 0f || pab <= 0f || 1672 pax < mpaMax.getX(units) || paw > mpaMax.getWidth(units) || 1673 pay < mpaMax.getY(units) || pah > mpaMax.getHeight(units)) { 1674 return null; 1675 } else { 1676 return new MediaPrintableArea(lm, tm, paw, pah, units); 1677 } 1678 } 1679 1680 /* This is complex as a MediaPrintableArea is valid only within 1681 * a particular context of media size. 1682 * So we need a MediaSize as well as a MediaPrintableArea. 1683 * MediaSize can be obtained from MediaSizeName. 1684 * If the application specifies a MediaPrintableArea, we accept it 1685 * to the extent its valid for the Media they specify. If they 1686 * don't specify a Media, then the default is assumed. 1687 * 1688 * If an application doesn't define a MediaPrintableArea, we need to 1689 * create a suitable one, this is created using the specified (or 1690 * default) Media and default 1 inch margins. This is validated 1691 * against the paper in case this is too large for tiny media. 1692 */ 1693 public void updateInfo() { 1694 1695 if (isAWT) { 1696 leftMargin.setEnabled(false); 1697 rightMargin.setEnabled(false); 1698 topMargin.setEnabled(false); 1699 bottomMargin.setEnabled(false); 1700 lblLeft.setEnabled(false); 1701 lblRight.setEnabled(false); 1702 lblTop.setEnabled(false); 1703 lblBottom.setEnabled(false); 1704 return; 1705 } 1706 1707 Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; 1708 MediaPrintableArea mpa = 1709 (MediaPrintableArea)asCurrent.get(mpaCategory); 1710 MediaPrintableArea mpaMax = null; 1711 MediaSize mediaSize = null; 1712 1713 Media media = (Media)asCurrent.get(Media.class); 1714 if (media == null || !(media instanceof MediaSizeName)) { 1715 media = (Media)psCurrent.getDefaultAttributeValue(Media.class); 1716 } 1717 if (media != null && (media instanceof MediaSizeName)) { 1718 MediaSizeName msn = (MediaSizeName)media; 1719 mediaSize = MediaSize.getMediaSizeForName(msn); 1720 } 1721 if (mediaSize == null) { 1722 mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); 1723 } 1724 1725 if (media != null) { 1726 PrintRequestAttributeSet tmpASet = 1727 new HashPrintRequestAttributeSet(asCurrent); 1728 tmpASet.add(media); 1729 1730 Object values = 1731 psCurrent.getSupportedAttributeValues(mpaCategory, 1732 docFlavor, 1733 tmpASet); 1734 if (values instanceof MediaPrintableArea[] && 1735 ((MediaPrintableArea[])values).length > 0) { 1736 mpaMax = ((MediaPrintableArea[])values)[0]; 1737 1738 } else if (values instanceof MediaPrintableArea) { 1739 mpaMax = (MediaPrintableArea)values; 1740 } 1741 } 1742 if (mpaMax == null) { 1743 mpaMax = new MediaPrintableArea(0f, 0f, 1744 mediaSize.getX(units), 1745 mediaSize.getY(units), 1746 units); 1747 } 1748 1749 /* 1750 * At this point we now know as best we can :- 1751 * - the media size 1752 * - the maximum corresponding printable area 1753 * - the media printable area specified by the client, if any. 1754 * The next step is to create a default MPA if none was specified. 1755 * 1" margins are used unless they are disproportionately 1756 * large compared to the size of the media. 1757 */ 1758 1759 float wid = mediaSize.getX(MediaPrintableArea.INCH); 1760 float hgt = mediaSize.getY(MediaPrintableArea.INCH); 1761 float maxMarginRatio = 5f; 1762 float xMgn, yMgn; 1763 if (wid > maxMarginRatio) { 1764 xMgn = 1f; 1765 } else { 1766 xMgn = wid / maxMarginRatio; 1767 } 1768 if (hgt > maxMarginRatio) { 1769 yMgn = 1f; 1770 } else { 1771 yMgn = hgt / maxMarginRatio; 1772 } 1773 1774 if (mpa == null) { 1775 mpa = new MediaPrintableArea(xMgn, yMgn, 1776 wid-(2*xMgn), hgt-(2*yMgn), 1777 MediaPrintableArea.INCH); 1778 asCurrent.add(mpa); 1779 } 1780 float pax = mpa.getX(units); 1781 float pay = mpa.getY(units); 1782 float paw = mpa.getWidth(units); 1783 float pah = mpa.getHeight(units); 1784 float paxMax = mpaMax.getX(units); 1785 float payMax = mpaMax.getY(units); 1786 float pawMax = mpaMax.getWidth(units); 1787 float pahMax = mpaMax.getHeight(units); 1788 1789 1790 boolean invalid = false; 1791 1792 // If the paper is set to something which is too small to 1793 // accommodate a specified printable area, perhaps carried 1794 // over from a larger paper, the adjustment that needs to be 1795 // performed should seem the most natural from a user's viewpoint. 1796 // Since the user is specifying margins, then we are biased 1797 // towards keeping the margins as close to what is specified as 1798 // possible, shrinking or growing the printable area. 1799 // But the API uses printable area, so you need to know the 1800 // media size in which the margins were previously interpreted, 1801 // or at least have a record of the margins. 1802 // In the case that this is the creation of this UI we do not 1803 // have this record, so we are somewhat reliant on the client 1804 // to supply a reasonable default 1805 wid = mediaSize.getX(units); 1806 hgt = mediaSize.getY(units); 1807 if (lmVal >= 0f) { 1808 invalid = true; 1809 1810 if (lmVal + rmVal > wid) { 1811 // margins impossible, but maintain P.A if can 1812 if (paw > pawMax) { 1813 paw = pawMax; 1814 } 1815 // try to centre the printable area. 1816 pax = (wid - paw)/2f; 1817 } else { 1818 pax = (lmVal >= paxMax) ? lmVal : paxMax; 1819 paw = wid - pax - rmVal; 1820 } 1821 if (tmVal + bmVal > hgt) { 1822 if (pah > pahMax) { 1823 pah = pahMax; 1824 } 1825 pay = (hgt - pah)/2f; 1826 } else { 1827 pay = (tmVal >= payMax) ? tmVal : payMax; 1828 pah = hgt - pay - bmVal; 1829 } 1830 } 1831 if (pax < paxMax) { 1832 invalid = true; 1833 pax = paxMax; 1834 } 1835 if (pay < payMax) { 1836 invalid = true; 1837 pay = payMax; 1838 } 1839 if (paw > pawMax) { 1840 invalid = true; 1841 paw = pawMax; 1842 } 1843 if (pah > pahMax) { 1844 invalid = true; 1845 pah = pahMax; 1846 } 1847 1848 if ((pax + paw > paxMax + pawMax) || (paw <= 0f)) { 1849 invalid = true; 1850 pax = paxMax; 1851 paw = pawMax; 1852 } 1853 if ((pay + pah > payMax + pahMax) || (pah <= 0f)) { 1854 invalid = true; 1855 pay = payMax; 1856 pah = pahMax; 1857 } 1858 1859 if (invalid) { 1860 mpa = new MediaPrintableArea(pax, pay, paw, pah, units); 1861 asCurrent.add(mpa); 1862 } 1863 1864 /* We now have a valid printable area. 1865 * Turn it into margins, using the mediaSize 1866 */ 1867 lmVal = pax; 1868 tmVal = pay; 1869 rmVal = mediaSize.getX(units) - pax - paw; 1870 bmVal = mediaSize.getY(units) - pay - pah; 1871 1872 lmObj = lmVal; 1873 rmObj = rmVal; 1874 tmObj = tmVal; 1875 bmObj = bmVal; 1876 1877 /* Now we know the values to use, we need to assign them 1878 * to the fields appropriate for the orientation. 1879 * Note: if orientation changes this method must be called. 1880 */ 1881 Class<OrientationRequested> orCategory = OrientationRequested.class; 1882 OrientationRequested or = 1883 (OrientationRequested)asCurrent.get(orCategory); 1884 1885 if (or == null) { 1886 or = (OrientationRequested) 1887 psCurrent.getDefaultAttributeValue(orCategory); 1888 } 1889 1890 Float tmp; 1891 1892 if (or == OrientationRequested.REVERSE_PORTRAIT) { 1893 tmp = lmObj; lmObj = rmObj; rmObj = tmp; 1894 tmp = tmObj; tmObj = bmObj; bmObj = tmp; 1895 } else if (or == OrientationRequested.LANDSCAPE) { 1896 tmp = lmObj; 1897 lmObj = bmObj; 1898 bmObj = rmObj; 1899 rmObj = tmObj; 1900 tmObj = tmp; 1901 } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { 1902 tmp = lmObj; 1903 lmObj = tmObj; 1904 tmObj = rmObj; 1905 rmObj = bmObj; 1906 bmObj = tmp; 1907 } 1908 1909 leftMargin.setValue(lmObj); 1910 rightMargin.setValue(rmObj); 1911 topMargin.setValue(tmObj); 1912 bottomMargin.setValue(bmObj); 1913 } 1914 } 1915 1916 @SuppressWarnings("serial") // Superclass is not serializable across versions 1917 private class MediaPanel extends JPanel implements ItemListener { 1918 1919 private final String strTitle = getMsg("border.media"); 1920 private JLabel lblSize, lblSource; 1921 private JComboBox<Object> cbSize, cbSource; 1922 private Vector<MediaSizeName> sizes = new Vector<>(); 1923 private Vector<MediaTray> sources = new Vector<>(); 1924 private MarginsPanel pnlMargins = null; 1925 1926 public MediaPanel() { 1927 super(); 1928 1929 GridBagLayout gridbag = new GridBagLayout(); 1930 GridBagConstraints c = new GridBagConstraints(); 1931 1932 setLayout(gridbag); 1933 setBorder(BorderFactory.createTitledBorder(strTitle)); 1934 1935 cbSize = new JComboBox<>(); 1936 cbSource = new JComboBox<>(); 1937 1938 c.fill = GridBagConstraints.BOTH; 1939 c.insets = compInsets; 1940 c.weighty = 1.0; 1941 1942 c.weightx = 0.0; 1943 lblSize = new JLabel(getMsg("label.size"), JLabel.TRAILING); 1944 lblSize.setDisplayedMnemonic(getMnemonic("label.size")); 1945 lblSize.setLabelFor(cbSize); 1946 addToGB(lblSize, this, gridbag, c); 1947 c.weightx = 1.0; 1948 c.gridwidth = GridBagConstraints.REMAINDER; 1949 addToGB(cbSize, this, gridbag, c); 1950 1951 c.weightx = 0.0; 1952 c.gridwidth = 1; 1953 lblSource = new JLabel(getMsg("label.source"), JLabel.TRAILING); 1954 lblSource.setDisplayedMnemonic(getMnemonic("label.source")); 1955 lblSource.setLabelFor(cbSource); 1956 addToGB(lblSource, this, gridbag, c); 1957 c.gridwidth = GridBagConstraints.REMAINDER; 1958 addToGB(cbSource, this, gridbag, c); 1959 } 1960 1961 private String getMediaName(String key) { 1962 try { 1963 // replace characters that would be invalid in 1964 // a resource key with valid characters 1965 String newkey = key.replace(' ', '-'); 1966 newkey = newkey.replace('#', 'n'); 1967 1968 return messageRB.getString(newkey); 1969 } catch (java.util.MissingResourceException e) { 1970 return key; 1971 } 1972 } 1973 1974 public void itemStateChanged(ItemEvent e) { 1975 Object source = e.getSource(); 1976 1977 if (e.getStateChange() == ItemEvent.SELECTED) { 1978 if (source == cbSize) { 1979 int index = cbSize.getSelectedIndex(); 1980 1981 if ((index >= 0) && (index < sizes.size())) { 1982 if ((cbSource.getItemCount() > 1) && 1983 (cbSource.getSelectedIndex() >= 1)) 1984 { 1985 int src = cbSource.getSelectedIndex() - 1; 1986 MediaTray mt = sources.get(src); 1987 asCurrent.add(new SunAlternateMedia(mt)); 1988 } 1989 asCurrent.add(sizes.get(index)); 1990 } 1991 } else if (source == cbSource) { 1992 int index = cbSource.getSelectedIndex(); 1993 1994 if ((index >= 1) && (index < (sources.size() + 1))) { 1995 asCurrent.remove(SunAlternateMedia.class); 1996 MediaTray newTray = sources.get(index - 1); 1997 Media m = (Media)asCurrent.get(Media.class); 1998 if (m == null || m instanceof MediaTray) { 1999 asCurrent.add(newTray); 2000 } else if (m instanceof MediaSizeName) { 2001 MediaSizeName msn = (MediaSizeName)m; 2002 Media def = (Media)psCurrent.getDefaultAttributeValue(Media.class); 2003 if (def instanceof MediaSizeName && def.equals(msn)) { 2004 asCurrent.add(newTray); 2005 } else { 2006 /* Non-default paper size, so need to store tray 2007 * as SunAlternateMedia 2008 */ 2009 asCurrent.add(new SunAlternateMedia(newTray)); 2010 } 2011 } 2012 } else if (index == 0) { 2013 asCurrent.remove(SunAlternateMedia.class); 2014 if (cbSize.getItemCount() > 0) { 2015 int size = cbSize.getSelectedIndex(); 2016 asCurrent.add(sizes.get(size)); 2017 } 2018 } 2019 } 2020 // orientation affects display of margins. 2021 if (pnlMargins != null) { 2022 pnlMargins.updateInfo(); 2023 } 2024 } 2025 } 2026 2027 2028 /* this is ad hoc to keep things simple */ 2029 public void addMediaListener(MarginsPanel pnl) { 2030 pnlMargins = pnl; 2031 } 2032 public void updateInfo() { 2033 Class<Media> mdCategory = Media.class; 2034 Class<SunAlternateMedia> amCategory = SunAlternateMedia.class; 2035 boolean mediaSupported = false; 2036 2037 cbSize.removeItemListener(this); 2038 cbSize.removeAllItems(); 2039 cbSource.removeItemListener(this); 2040 cbSource.removeAllItems(); 2041 cbSource.addItem(getMediaName("auto-select")); 2042 2043 sizes.clear(); 2044 sources.clear(); 2045 2046 if (psCurrent.isAttributeCategorySupported(mdCategory)) { 2047 mediaSupported = true; 2048 2049 Object values = 2050 psCurrent.getSupportedAttributeValues(mdCategory, 2051 docFlavor, 2052 asCurrent); 2053 2054 if (values instanceof Media[]) { 2055 Media[] media = (Media[])values; 2056 2057 for (int i = 0; i < media.length; i++) { 2058 Media medium = media[i]; 2059 2060 if (medium instanceof MediaSizeName) { 2061 sizes.add((MediaSizeName)medium); 2062 cbSize.addItem(getMediaName(medium.toString())); 2063 } else if (medium instanceof MediaTray) { 2064 sources.add((MediaTray)medium); 2065 cbSource.addItem(getMediaName(medium.toString())); 2066 } 2067 } 2068 } 2069 } 2070 2071 boolean msSupported = (mediaSupported && (sizes.size() > 0)); 2072 lblSize.setEnabled(msSupported); 2073 cbSize.setEnabled(msSupported); 2074 2075 if (isAWT) { 2076 cbSource.setEnabled(false); 2077 lblSource.setEnabled(false); 2078 } else { 2079 cbSource.setEnabled(mediaSupported); 2080 } 2081 2082 if (mediaSupported) { 2083 2084 Media medium = (Media)asCurrent.get(mdCategory); 2085 2086 // initialize size selection to default 2087 Media defMedia = (Media)psCurrent.getDefaultAttributeValue(mdCategory); 2088 if (defMedia instanceof MediaSizeName) { 2089 cbSize.setSelectedIndex(sizes.size() > 0 ? sizes.indexOf(defMedia) : -1); 2090 } 2091 2092 if (medium == null || 2093 !psCurrent.isAttributeValueSupported(medium, 2094 docFlavor, asCurrent)) { 2095 2096 medium = defMedia; 2097 2098 if (medium == null) { 2099 if (sizes.size() > 0) { 2100 medium = (Media)sizes.get(0); 2101 } 2102 } 2103 if (medium != null) { 2104 asCurrent.add(medium); 2105 } 2106 } 2107 if (medium != null) { 2108 if (medium instanceof MediaSizeName) { 2109 MediaSizeName ms = (MediaSizeName)medium; 2110 cbSize.setSelectedIndex(sizes.indexOf(ms)); 2111 } else if (medium instanceof MediaTray) { 2112 MediaTray mt = (MediaTray)medium; 2113 cbSource.setSelectedIndex(sources.indexOf(mt) + 1); 2114 } 2115 } else { 2116 cbSize.setSelectedIndex(sizes.size() > 0 ? 0 : -1); 2117 cbSource.setSelectedIndex(0); 2118 } 2119 2120 SunAlternateMedia alt = (SunAlternateMedia)asCurrent.get(amCategory); 2121 if (alt != null) { 2122 Media md = alt.getMedia(); 2123 if (md instanceof MediaTray) { 2124 MediaTray mt = (MediaTray)md; 2125 cbSource.setSelectedIndex(sources.indexOf(mt) + 1); 2126 } 2127 } 2128 2129 int selIndex = cbSize.getSelectedIndex(); 2130 if ((selIndex >= 0) && (selIndex < sizes.size())) { 2131 asCurrent.add(sizes.get(selIndex)); 2132 } 2133 2134 selIndex = cbSource.getSelectedIndex(); 2135 if ((selIndex >= 1) && (selIndex < (sources.size()+1))) { 2136 MediaTray mt = sources.get(selIndex-1); 2137 if (medium instanceof MediaTray) { 2138 asCurrent.add(mt); 2139 } else { 2140 asCurrent.add(new SunAlternateMedia(mt)); 2141 } 2142 } 2143 2144 2145 } 2146 cbSize.addItemListener(this); 2147 cbSource.addItemListener(this); 2148 } 2149 } 2150 2151 @SuppressWarnings("serial") // Superclass is not serializable across versions 2152 private class OrientationPanel extends JPanel 2153 implements ActionListener 2154 { 2155 private final String strTitle = getMsg("border.orientation"); 2156 private IconRadioButton rbPortrait, rbLandscape, 2157 rbRevPortrait, rbRevLandscape; 2158 private MarginsPanel pnlMargins = null; 2159 2160 public OrientationPanel() { 2161 super(); 2162 2163 GridBagLayout gridbag = new GridBagLayout(); 2164 GridBagConstraints c = new GridBagConstraints(); 2165 2166 setLayout(gridbag); 2167 setBorder(BorderFactory.createTitledBorder(strTitle)); 2168 2169 c.fill = GridBagConstraints.BOTH; 2170 c.insets = compInsets; 2171 c.weighty = 1.0; 2172 c.gridwidth = GridBagConstraints.REMAINDER; 2173 2174 ButtonGroup bg = new ButtonGroup(); 2175 rbPortrait = new IconRadioButton("radiobutton.portrait", 2176 "orientPortrait.png", true, 2177 bg, this); 2178 rbPortrait.addActionListener(this); 2179 addToGB(rbPortrait, this, gridbag, c); 2180 rbLandscape = new IconRadioButton("radiobutton.landscape", 2181 "orientLandscape.png", false, 2182 bg, this); 2183 rbLandscape.addActionListener(this); 2184 addToGB(rbLandscape, this, gridbag, c); 2185 rbRevPortrait = new IconRadioButton("radiobutton.revportrait", 2186 "orientRevPortrait.png", false, 2187 bg, this); 2188 rbRevPortrait.addActionListener(this); 2189 addToGB(rbRevPortrait, this, gridbag, c); 2190 rbRevLandscape = new IconRadioButton("radiobutton.revlandscape", 2191 "orientRevLandscape.png", false, 2192 bg, this); 2193 rbRevLandscape.addActionListener(this); 2194 addToGB(rbRevLandscape, this, gridbag, c); 2195 } 2196 2197 public void actionPerformed(ActionEvent e) { 2198 Object source = e.getSource(); 2199 2200 if (rbPortrait.isSameAs(source)) { 2201 asCurrent.add(OrientationRequested.PORTRAIT); 2202 } else if (rbLandscape.isSameAs(source)) { 2203 asCurrent.add(OrientationRequested.LANDSCAPE); 2204 } else if (rbRevPortrait.isSameAs(source)) { 2205 asCurrent.add(OrientationRequested.REVERSE_PORTRAIT); 2206 } else if (rbRevLandscape.isSameAs(source)) { 2207 asCurrent.add(OrientationRequested.REVERSE_LANDSCAPE); 2208 } 2209 // orientation affects display of margins. 2210 if (pnlMargins != null) { 2211 pnlMargins.updateInfo(); 2212 } 2213 } 2214 2215 /* This is ad hoc to keep things simple */ 2216 void addOrientationListener(MarginsPanel pnl) { 2217 pnlMargins = pnl; 2218 } 2219 2220 public void updateInfo() { 2221 Class<OrientationRequested> orCategory = OrientationRequested.class; 2222 boolean pSupported = false; 2223 boolean lSupported = false; 2224 boolean rpSupported = false; 2225 boolean rlSupported = false; 2226 2227 if (isAWT) { 2228 pSupported = true; 2229 lSupported = true; 2230 } else 2231 if (psCurrent.isAttributeCategorySupported(orCategory)) { 2232 Object values = 2233 psCurrent.getSupportedAttributeValues(orCategory, 2234 docFlavor, 2235 asCurrent); 2236 2237 if (values instanceof OrientationRequested[]) { 2238 OrientationRequested[] ovalues = 2239 (OrientationRequested[])values; 2240 2241 for (int i = 0; i < ovalues.length; i++) { 2242 OrientationRequested value = ovalues[i]; 2243 2244 if (value == OrientationRequested.PORTRAIT) { 2245 pSupported = true; 2246 } else if (value == OrientationRequested.LANDSCAPE) { 2247 lSupported = true; 2248 } else if (value == OrientationRequested.REVERSE_PORTRAIT) { 2249 rpSupported = true; 2250 } else if (value == OrientationRequested.REVERSE_LANDSCAPE) { 2251 rlSupported = true; 2252 } 2253 } 2254 } 2255 } 2256 2257 2258 rbPortrait.setEnabled(pSupported); 2259 rbLandscape.setEnabled(lSupported); 2260 rbRevPortrait.setEnabled(rpSupported); 2261 rbRevLandscape.setEnabled(rlSupported); 2262 2263 OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); 2264 if (or == null || 2265 !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { 2266 2267 or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); 2268 // need to validate if default is not supported 2269 if ((or != null) && 2270 !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { 2271 or = null; 2272 Object values = 2273 psCurrent.getSupportedAttributeValues(orCategory, 2274 docFlavor, 2275 asCurrent); 2276 if (values instanceof OrientationRequested[]) { 2277 OrientationRequested[] orValues = 2278 (OrientationRequested[])values; 2279 if (orValues.length > 1) { 2280 // get the first in the list 2281 or = orValues[0]; 2282 } 2283 } 2284 } 2285 2286 if (or == null) { 2287 or = OrientationRequested.PORTRAIT; 2288 } 2289 asCurrent.add(or); 2290 } 2291 2292 if (or == OrientationRequested.PORTRAIT) { 2293 rbPortrait.setSelected(true); 2294 } else if (or == OrientationRequested.LANDSCAPE) { 2295 rbLandscape.setSelected(true); 2296 } else if (or == OrientationRequested.REVERSE_PORTRAIT) { 2297 rbRevPortrait.setSelected(true); 2298 } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) 2299 rbRevLandscape.setSelected(true); 2300 } 2301 } 2302 } 2303 2304 2305 2306 /** 2307 * The "Appearance" tab. Includes the controls for Chromaticity, 2308 * PrintQuality, JobPriority, JobName, and other related job attributes. 2309 */ 2310 @SuppressWarnings("serial") // Superclass is not serializable across versions 2311 private class AppearancePanel extends JPanel { 2312 2313 private ChromaticityPanel pnlChromaticity; 2314 private QualityPanel pnlQuality; 2315 private JobAttributesPanel pnlJobAttributes; 2316 private SidesPanel pnlSides; 2317 2318 public AppearancePanel() { 2319 super(); 2320 2321 GridBagLayout gridbag = new GridBagLayout(); 2322 GridBagConstraints c = new GridBagConstraints(); 2323 2324 setLayout(gridbag); 2325 2326 c.fill = GridBagConstraints.BOTH; 2327 c.insets = panelInsets; 2328 c.weightx = 1.0; 2329 c.weighty = 1.0; 2330 2331 c.gridwidth = GridBagConstraints.RELATIVE; 2332 pnlChromaticity = new ChromaticityPanel(); 2333 addToGB(pnlChromaticity, this, gridbag, c); 2334 2335 c.gridwidth = GridBagConstraints.REMAINDER; 2336 pnlQuality = new QualityPanel(); 2337 addToGB(pnlQuality, this, gridbag, c); 2338 2339 c.gridwidth = 1; 2340 pnlSides = new SidesPanel(); 2341 addToGB(pnlSides, this, gridbag, c); 2342 2343 c.gridwidth = GridBagConstraints.REMAINDER; 2344 pnlJobAttributes = new JobAttributesPanel(); 2345 addToGB(pnlJobAttributes, this, gridbag, c); 2346 2347 } 2348 2349 public void updateInfo() { 2350 pnlChromaticity.updateInfo(); 2351 pnlQuality.updateInfo(); 2352 pnlSides.updateInfo(); 2353 pnlJobAttributes.updateInfo(); 2354 } 2355 } 2356 2357 @SuppressWarnings("serial") // Superclass is not serializable across versions 2358 private class ChromaticityPanel extends JPanel 2359 implements ActionListener 2360 { 2361 private final String strTitle = getMsg("border.chromaticity"); 2362 private JRadioButton rbMonochrome, rbColor; 2363 2364 public ChromaticityPanel() { 2365 super(); 2366 2367 GridBagLayout gridbag = new GridBagLayout(); 2368 GridBagConstraints c = new GridBagConstraints(); 2369 2370 setLayout(gridbag); 2371 setBorder(BorderFactory.createTitledBorder(strTitle)); 2372 2373 c.fill = GridBagConstraints.BOTH; 2374 c.gridwidth = GridBagConstraints.REMAINDER; 2375 c.weighty = 1.0; 2376 2377 ButtonGroup bg = new ButtonGroup(); 2378 rbMonochrome = createRadioButton("radiobutton.monochrome", this); 2379 rbMonochrome.setSelected(true); 2380 bg.add(rbMonochrome); 2381 addToGB(rbMonochrome, this, gridbag, c); 2382 rbColor = createRadioButton("radiobutton.color", this); 2383 bg.add(rbColor); 2384 addToGB(rbColor, this, gridbag, c); 2385 } 2386 2387 public void actionPerformed(ActionEvent e) { 2388 Object source = e.getSource(); 2389 2390 // REMIND: use isSameAs if we move to a IconRB in the future 2391 if (source == rbMonochrome) { 2392 asCurrent.add(Chromaticity.MONOCHROME); 2393 } else if (source == rbColor) { 2394 asCurrent.add(Chromaticity.COLOR); 2395 } 2396 } 2397 2398 public void updateInfo() { 2399 Class<Chromaticity> chCategory = Chromaticity.class; 2400 boolean monoSupported = false; 2401 boolean colorSupported = false; 2402 2403 if (isAWT) { 2404 monoSupported = true; 2405 colorSupported = true; 2406 } else 2407 if (psCurrent.isAttributeCategorySupported(chCategory)) { 2408 Object values = 2409 psCurrent.getSupportedAttributeValues(chCategory, 2410 docFlavor, 2411 asCurrent); 2412 2413 if (values instanceof Chromaticity[]) { 2414 Chromaticity[] cvalues = (Chromaticity[])values; 2415 2416 for (int i = 0; i < cvalues.length; i++) { 2417 Chromaticity value = cvalues[i]; 2418 2419 if (value == Chromaticity.MONOCHROME) { 2420 monoSupported = true; 2421 } else if (value == Chromaticity.COLOR) { 2422 colorSupported = true; 2423 } 2424 } 2425 } 2426 } 2427 2428 2429 rbMonochrome.setEnabled(monoSupported); 2430 rbColor.setEnabled(colorSupported); 2431 2432 Chromaticity ch = (Chromaticity)asCurrent.get(chCategory); 2433 if (ch == null) { 2434 ch = (Chromaticity)psCurrent.getDefaultAttributeValue(chCategory); 2435 if (ch == null) { 2436 ch = Chromaticity.MONOCHROME; 2437 } 2438 } 2439 2440 if (ch == Chromaticity.MONOCHROME) { 2441 rbMonochrome.setSelected(true); 2442 } else { // if (ch == Chromaticity.COLOR) 2443 rbColor.setSelected(true); 2444 } 2445 } 2446 } 2447 2448 @SuppressWarnings("serial") // Superclass is not serializable across versions 2449 private class QualityPanel extends JPanel 2450 implements ActionListener 2451 { 2452 private final String strTitle = getMsg("border.quality"); 2453 private JRadioButton rbDraft, rbNormal, rbHigh; 2454 2455 public QualityPanel() { 2456 super(); 2457 2458 GridBagLayout gridbag = new GridBagLayout(); 2459 GridBagConstraints c = new GridBagConstraints(); 2460 2461 setLayout(gridbag); 2462 setBorder(BorderFactory.createTitledBorder(strTitle)); 2463 2464 c.fill = GridBagConstraints.BOTH; 2465 c.gridwidth = GridBagConstraints.REMAINDER; 2466 c.weighty = 1.0; 2467 2468 ButtonGroup bg = new ButtonGroup(); 2469 rbDraft = createRadioButton("radiobutton.draftq", this); 2470 bg.add(rbDraft); 2471 addToGB(rbDraft, this, gridbag, c); 2472 rbNormal = createRadioButton("radiobutton.normalq", this); 2473 rbNormal.setSelected(true); 2474 bg.add(rbNormal); 2475 addToGB(rbNormal, this, gridbag, c); 2476 rbHigh = createRadioButton("radiobutton.highq", this); 2477 bg.add(rbHigh); 2478 addToGB(rbHigh, this, gridbag, c); 2479 } 2480 2481 public void actionPerformed(ActionEvent e) { 2482 Object source = e.getSource(); 2483 2484 if (source == rbDraft) { 2485 asCurrent.add(PrintQuality.DRAFT); 2486 } else if (source == rbNormal) { 2487 asCurrent.add(PrintQuality.NORMAL); 2488 } else if (source == rbHigh) { 2489 asCurrent.add(PrintQuality.HIGH); 2490 } 2491 } 2492 2493 public void updateInfo() { 2494 Class<PrintQuality> pqCategory = PrintQuality.class; 2495 boolean draftSupported = false; 2496 boolean normalSupported = false; 2497 boolean highSupported = false; 2498 2499 if (isAWT) { 2500 draftSupported = true; 2501 normalSupported = true; 2502 highSupported = true; 2503 } else 2504 if (psCurrent.isAttributeCategorySupported(pqCategory)) { 2505 Object values = 2506 psCurrent.getSupportedAttributeValues(pqCategory, 2507 docFlavor, 2508 asCurrent); 2509 2510 if (values instanceof PrintQuality[]) { 2511 PrintQuality[] qvalues = (PrintQuality[])values; 2512 2513 for (int i = 0; i < qvalues.length; i++) { 2514 PrintQuality value = qvalues[i]; 2515 2516 if (value == PrintQuality.DRAFT) { 2517 draftSupported = true; 2518 } else if (value == PrintQuality.NORMAL) { 2519 normalSupported = true; 2520 } else if (value == PrintQuality.HIGH) { 2521 highSupported = true; 2522 } 2523 } 2524 } 2525 } 2526 2527 rbDraft.setEnabled(draftSupported); 2528 rbNormal.setEnabled(normalSupported); 2529 rbHigh.setEnabled(highSupported); 2530 2531 PrintQuality pq = (PrintQuality)asCurrent.get(pqCategory); 2532 if (pq == null) { 2533 pq = (PrintQuality)psCurrent.getDefaultAttributeValue(pqCategory); 2534 if (pq == null) { 2535 pq = PrintQuality.NORMAL; 2536 } 2537 } 2538 2539 if (pq == PrintQuality.DRAFT) { 2540 rbDraft.setSelected(true); 2541 } else if (pq == PrintQuality.NORMAL) { 2542 rbNormal.setSelected(true); 2543 } else { // if (pq == PrintQuality.HIGH) 2544 rbHigh.setSelected(true); 2545 } 2546 } 2547 2548 2549 } 2550 2551 @SuppressWarnings("serial") // Superclass is not serializable across versions 2552 private class SidesPanel extends JPanel 2553 implements ActionListener 2554 { 2555 private final String strTitle = getMsg("border.sides"); 2556 private IconRadioButton rbOneSide, rbTumble, rbDuplex; 2557 2558 public SidesPanel() { 2559 super(); 2560 2561 GridBagLayout gridbag = new GridBagLayout(); 2562 GridBagConstraints c = new GridBagConstraints(); 2563 2564 setLayout(gridbag); 2565 setBorder(BorderFactory.createTitledBorder(strTitle)); 2566 2567 c.fill = GridBagConstraints.BOTH; 2568 c.insets = compInsets; 2569 c.weighty = 1.0; 2570 c.gridwidth = GridBagConstraints.REMAINDER; 2571 2572 ButtonGroup bg = new ButtonGroup(); 2573 rbOneSide = new IconRadioButton("radiobutton.oneside", 2574 "oneside.png", true, 2575 bg, this); 2576 rbOneSide.addActionListener(this); 2577 addToGB(rbOneSide, this, gridbag, c); 2578 rbTumble = new IconRadioButton("radiobutton.tumble", 2579 "tumble.png", false, 2580 bg, this); 2581 rbTumble.addActionListener(this); 2582 addToGB(rbTumble, this, gridbag, c); 2583 rbDuplex = new IconRadioButton("radiobutton.duplex", 2584 "duplex.png", false, 2585 bg, this); 2586 rbDuplex.addActionListener(this); 2587 c.gridwidth = GridBagConstraints.REMAINDER; 2588 addToGB(rbDuplex, this, gridbag, c); 2589 } 2590 2591 public void actionPerformed(ActionEvent e) { 2592 Object source = e.getSource(); 2593 2594 if (rbOneSide.isSameAs(source)) { 2595 asCurrent.add(Sides.ONE_SIDED); 2596 } else if (rbTumble.isSameAs(source)) { 2597 asCurrent.add(Sides.TUMBLE); 2598 } else if (rbDuplex.isSameAs(source)) { 2599 asCurrent.add(Sides.DUPLEX); 2600 } 2601 } 2602 2603 public void updateInfo() { 2604 Class<Sides> sdCategory = Sides.class; 2605 boolean osSupported = false; 2606 boolean tSupported = false; 2607 boolean dSupported = false; 2608 2609 if (psCurrent.isAttributeCategorySupported(sdCategory)) { 2610 Object values = 2611 psCurrent.getSupportedAttributeValues(sdCategory, 2612 docFlavor, 2613 asCurrent); 2614 2615 if (values instanceof Sides[]) { 2616 Sides[] svalues = (Sides[])values; 2617 2618 for (int i = 0; i < svalues.length; i++) { 2619 Sides value = svalues[i]; 2620 2621 if (value == Sides.ONE_SIDED) { 2622 osSupported = true; 2623 } else if (value == Sides.TUMBLE) { 2624 tSupported = true; 2625 } else if (value == Sides.DUPLEX) { 2626 dSupported = true; 2627 } 2628 } 2629 } 2630 } 2631 rbOneSide.setEnabled(osSupported); 2632 rbTumble.setEnabled(tSupported); 2633 rbDuplex.setEnabled(dSupported); 2634 2635 Sides sd = (Sides)asCurrent.get(sdCategory); 2636 if (sd == null) { 2637 sd = (Sides)psCurrent.getDefaultAttributeValue(sdCategory); 2638 if (sd == null) { 2639 sd = Sides.ONE_SIDED; 2640 } 2641 } 2642 2643 if (sd == Sides.ONE_SIDED) { 2644 rbOneSide.setSelected(true); 2645 } else if (sd == Sides.TUMBLE) { 2646 rbTumble.setSelected(true); 2647 } else { // if (sd == Sides.DUPLEX) 2648 rbDuplex.setSelected(true); 2649 } 2650 } 2651 } 2652 2653 2654 @SuppressWarnings("serial") // Superclass is not serializable across versions 2655 private class JobAttributesPanel extends JPanel 2656 implements ActionListener, ChangeListener, FocusListener 2657 { 2658 private final String strTitle = getMsg("border.jobattributes"); 2659 private JLabel lblPriority, lblJobName, lblUserName; 2660 private JSpinner spinPriority; 2661 private SpinnerNumberModel snModel; 2662 private JCheckBox cbJobSheets; 2663 private JTextField tfJobName, tfUserName; 2664 2665 public JobAttributesPanel() { 2666 super(); 2667 2668 GridBagLayout gridbag = new GridBagLayout(); 2669 GridBagConstraints c = new GridBagConstraints(); 2670 2671 setLayout(gridbag); 2672 setBorder(BorderFactory.createTitledBorder(strTitle)); 2673 2674 c.fill = GridBagConstraints.NONE; 2675 c.insets = compInsets; 2676 c.weighty = 1.0; 2677 2678 cbJobSheets = createCheckBox("checkbox.jobsheets", this); 2679 c.anchor = GridBagConstraints.LINE_START; 2680 addToGB(cbJobSheets, this, gridbag, c); 2681 2682 JPanel pnlTop = new JPanel(); 2683 lblPriority = new JLabel(getMsg("label.priority"), JLabel.TRAILING); 2684 lblPriority.setDisplayedMnemonic(getMnemonic("label.priority")); 2685 2686 pnlTop.add(lblPriority); 2687 snModel = new SpinnerNumberModel(1, 1, 100, 1); 2688 spinPriority = new JSpinner(snModel); 2689 lblPriority.setLabelFor(spinPriority); 2690 // REMIND 2691 ((JSpinner.NumberEditor)spinPriority.getEditor()).getTextField().setColumns(3); 2692 spinPriority.addChangeListener(this); 2693 pnlTop.add(spinPriority); 2694 c.anchor = GridBagConstraints.LINE_END; 2695 c.gridwidth = GridBagConstraints.REMAINDER; 2696 pnlTop.getAccessibleContext().setAccessibleName( 2697 getMsg("label.priority")); 2698 addToGB(pnlTop, this, gridbag, c); 2699 2700 c.fill = GridBagConstraints.HORIZONTAL; 2701 c.anchor = GridBagConstraints.CENTER; 2702 c.weightx = 0.0; 2703 c.gridwidth = 1; 2704 char jmnemonic = getMnemonic("label.jobname"); 2705 lblJobName = new JLabel(getMsg("label.jobname"), JLabel.TRAILING); 2706 lblJobName.setDisplayedMnemonic(jmnemonic); 2707 addToGB(lblJobName, this, gridbag, c); 2708 c.weightx = 1.0; 2709 c.gridwidth = GridBagConstraints.REMAINDER; 2710 tfJobName = new JTextField(); 2711 lblJobName.setLabelFor(tfJobName); 2712 tfJobName.addFocusListener(this); 2713 tfJobName.setFocusAccelerator(jmnemonic); 2714 tfJobName.getAccessibleContext().setAccessibleName( 2715 getMsg("label.jobname")); 2716 addToGB(tfJobName, this, gridbag, c); 2717 2718 c.weightx = 0.0; 2719 c.gridwidth = 1; 2720 char umnemonic = getMnemonic("label.username"); 2721 lblUserName = new JLabel(getMsg("label.username"), JLabel.TRAILING); 2722 lblUserName.setDisplayedMnemonic(umnemonic); 2723 addToGB(lblUserName, this, gridbag, c); 2724 c.gridwidth = GridBagConstraints.REMAINDER; 2725 tfUserName = new JTextField(); 2726 lblUserName.setLabelFor(tfUserName); 2727 tfUserName.addFocusListener(this); 2728 tfUserName.setFocusAccelerator(umnemonic); 2729 tfUserName.getAccessibleContext().setAccessibleName( 2730 getMsg("label.username")); 2731 addToGB(tfUserName, this, gridbag, c); 2732 } 2733 2734 public void actionPerformed(ActionEvent e) { 2735 if (cbJobSheets.isSelected()) { 2736 asCurrent.add(JobSheets.STANDARD); 2737 } else { 2738 asCurrent.add(JobSheets.NONE); 2739 } 2740 } 2741 2742 public void stateChanged(ChangeEvent e) { 2743 asCurrent.add(new JobPriority(snModel.getNumber().intValue())); 2744 } 2745 2746 public void focusLost(FocusEvent e) { 2747 Object source = e.getSource(); 2748 2749 if (source == tfJobName) { 2750 asCurrent.add(new JobName(tfJobName.getText(), 2751 Locale.getDefault())); 2752 } else if (source == tfUserName) { 2753 asCurrent.add(new RequestingUserName(tfUserName.getText(), 2754 Locale.getDefault())); 2755 } 2756 } 2757 2758 public void focusGained(FocusEvent e) {} 2759 2760 public void updateInfo() { 2761 Class<JobSheets> jsCategory = JobSheets.class; 2762 Class<JobPriority> jpCategory = JobPriority.class; 2763 Class<JobName> jnCategory = JobName.class; 2764 Class<RequestingUserName> unCategory = RequestingUserName.class; 2765 boolean jsSupported = false; 2766 boolean jpSupported = false; 2767 boolean jnSupported = false; 2768 boolean unSupported = false; 2769 2770 // setup JobSheets checkbox 2771 if (psCurrent.isAttributeCategorySupported(jsCategory)) { 2772 jsSupported = true; 2773 } 2774 JobSheets js = (JobSheets)asCurrent.get(jsCategory); 2775 if (js == null) { 2776 js = (JobSheets)psCurrent.getDefaultAttributeValue(jsCategory); 2777 if (js == null) { 2778 js = JobSheets.STANDARD; 2779 } 2780 } 2781 cbJobSheets.setSelected(js != JobSheets.NONE && jsSupported); 2782 cbJobSheets.setEnabled(jsSupported); 2783 2784 // setup JobPriority spinner 2785 if (!isAWT && psCurrent.isAttributeCategorySupported(jpCategory)) { 2786 jpSupported = true; 2787 } 2788 JobPriority jp = (JobPriority)asCurrent.get(jpCategory); 2789 if (jp == null) { 2790 jp = (JobPriority)psCurrent.getDefaultAttributeValue(jpCategory); 2791 if (jp == null) { 2792 jp = new JobPriority(1); 2793 } 2794 } 2795 int value = jp.getValue(); 2796 if ((value < 1) || (value > 100)) { 2797 value = 1; 2798 } 2799 snModel.setValue(value); 2800 lblPriority.setEnabled(jpSupported); 2801 spinPriority.setEnabled(jpSupported); 2802 2803 // setup JobName text field 2804 if (psCurrent.isAttributeCategorySupported(jnCategory)) { 2805 jnSupported = true; 2806 } 2807 JobName jn = (JobName)asCurrent.get(jnCategory); 2808 if (jn == null) { 2809 jn = (JobName)psCurrent.getDefaultAttributeValue(jnCategory); 2810 if (jn == null) { 2811 jn = new JobName("", Locale.getDefault()); 2812 } 2813 } 2814 tfJobName.setText(jn.getValue()); 2815 tfJobName.setEnabled(jnSupported); 2816 lblJobName.setEnabled(jnSupported); 2817 2818 // setup RequestingUserName text field 2819 if (!isAWT && psCurrent.isAttributeCategorySupported(unCategory)) { 2820 unSupported = true; 2821 } 2822 RequestingUserName un = (RequestingUserName)asCurrent.get(unCategory); 2823 if (un == null) { 2824 un = (RequestingUserName)psCurrent.getDefaultAttributeValue(unCategory); 2825 if (un == null) { 2826 un = new RequestingUserName("", Locale.getDefault()); 2827 } 2828 } 2829 tfUserName.setText(un.getValue()); 2830 tfUserName.setEnabled(unSupported); 2831 lblUserName.setEnabled(unSupported); 2832 } 2833 } 2834 2835 2836 2837 2838 /** 2839 * A special widget that groups a JRadioButton with an associated icon, 2840 * placed to the left of the radio button. 2841 */ 2842 @SuppressWarnings("serial") // Superclass is not serializable across versions 2843 private class IconRadioButton extends JPanel { 2844 2845 private JRadioButton rb; 2846 private JLabel lbl; 2847 2848 public IconRadioButton(String key, String img, boolean selected, 2849 ButtonGroup bg, ActionListener al) 2850 { 2851 super(new FlowLayout(FlowLayout.LEADING)); 2852 final URL imgURL = getImageResource(img); 2853 Icon icon = java.security.AccessController.doPrivileged( 2854 new java.security.PrivilegedAction<Icon>() { 2855 public Icon run() { 2856 Icon icon = new ImageIcon(imgURL); 2857 return icon; 2858 } 2859 }); 2860 lbl = new JLabel(icon); 2861 add(lbl); 2862 2863 rb = createRadioButton(key, al); 2864 rb.setSelected(selected); 2865 addToBG(rb, this, bg); 2866 } 2867 2868 public void addActionListener(ActionListener al) { 2869 rb.addActionListener(al); 2870 } 2871 2872 public boolean isSameAs(Object source) { 2873 return (rb == source); 2874 } 2875 2876 public void setEnabled(boolean enabled) { 2877 rb.setEnabled(enabled); 2878 lbl.setEnabled(enabled); 2879 } 2880 2881 public boolean isSelected() { 2882 return rb.isSelected(); 2883 } 2884 2885 public void setSelected(boolean selected) { 2886 rb.setSelected(selected); 2887 } 2888 } 2889 2890 /** 2891 * Similar in functionality to the default JFileChooser, except this 2892 * chooser will pop up a "Do you want to overwrite..." dialog if the 2893 * user selects a file that already exists. 2894 */ 2895 @SuppressWarnings("serial") // JDK implementation class 2896 private class ValidatingFileChooser extends JFileChooser { 2897 public void approveSelection() { 2898 File selected = getSelectedFile(); 2899 boolean exists; 2900 2901 try { 2902 exists = selected.exists(); 2903 } catch (SecurityException e) { 2904 exists = false; 2905 } 2906 2907 if (exists) { 2908 int val; 2909 val = JOptionPane.showConfirmDialog(this, 2910 getMsg("dialog.overwrite"), 2911 getMsg("dialog.owtitle"), 2912 JOptionPane.YES_NO_OPTION); 2913 if (val != JOptionPane.YES_OPTION) { 2914 return; 2915 } 2916 } 2917 2918 try { 2919 if (selected.createNewFile()) { 2920 selected.delete(); 2921 } 2922 } catch (IOException ioe) { 2923 JOptionPane.showMessageDialog(this, 2924 getMsg("dialog.writeerror")+" "+selected, 2925 getMsg("dialog.owtitle"), 2926 JOptionPane.WARNING_MESSAGE); 2927 return; 2928 } catch (SecurityException se) { 2929 //There is already file read/write access so at this point 2930 // only delete access is denied. Just ignore it because in 2931 // most cases the file created in createNewFile gets 2932 // overwritten anyway. 2933 } 2934 File pFile = selected.getParentFile(); 2935 if ((selected.exists() && 2936 (!selected.isFile() || !selected.canWrite())) || 2937 ((pFile != null) && 2938 (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { 2939 JOptionPane.showMessageDialog(this, 2940 getMsg("dialog.writeerror")+" "+selected, 2941 getMsg("dialog.owtitle"), 2942 JOptionPane.WARNING_MESSAGE); 2943 return; 2944 } 2945 2946 super.approveSelection(); 2947 } 2948 } 2949 }