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