| /* | |
| * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package sun.print; | |
| import java.awt.BorderLayout; | |
| import java.awt.Component; | |
| import java.awt.Container; | |
| import java.awt.Dialog; | |
| import java.awt.FlowLayout; | |
| import java.awt.Frame; | |
| import java.awt.GraphicsConfiguration; | |
| import java.awt.GridBagLayout; | |
| import java.awt.GridBagConstraints; | |
| import java.awt.Insets; | |
| import java.awt.Window; | |
| import java.awt.event.ActionEvent; | |
| import java.awt.event.ActionListener; | |
| import java.awt.event.FocusEvent; | |
| import java.awt.event.FocusListener; | |
| import java.awt.event.ItemEvent; | |
| import java.awt.event.ItemListener; | |
| import java.awt.event.WindowEvent; | |
| import java.awt.event.WindowAdapter; | |
| import java.awt.print.PrinterJob; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.net.URI; | |
| import java.net.URL; | |
| import java.text.DecimalFormat; | |
| import java.util.Locale; | |
| import java.util.ResourceBundle; | |
| import java.util.Vector; | |
| import javax.print.*; | |
| import javax.print.attribute.*; | |
| import javax.print.attribute.standard.*; | |
| import javax.swing.*; | |
| import javax.swing.border.EmptyBorder; | |
| import javax.swing.event.ChangeEvent; | |
| import javax.swing.event.ChangeListener; | |
| import javax.swing.event.PopupMenuEvent; | |
| import javax.swing.event.PopupMenuListener; | |
| import javax.swing.text.NumberFormatter; | |
| import sun.print.SunPageSelection; | |
| import java.awt.event.KeyEvent; | |
| import java.net.URISyntaxException; | |
| import java.lang.reflect.Field; | |
| import java.net.MalformedURLException; | |
| import sun.awt.OSInfo; | |
| /** | |
| * A class which implements a cross-platform print dialog. | |
| * | |
| * @author Chris Campbell | |
| */ | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| public class ServiceDialog extends JDialog implements ActionListener { | |
| /** | |
| * Waiting print status (user response pending). | |
| */ | |
| public static final int WAITING = 0; | |
| /** | |
| * Approve print status (user activated "Print" or "OK"). | |
| */ | |
| public static final int APPROVE = 1; | |
| /** | |
| * Cancel print status (user activated "Cancel"); | |
| */ | |
| public static final int CANCEL = 2; | |
| private static final String strBundle = "sun.print.resources.serviceui"; | |
| private static final Insets panelInsets = new Insets(6, 6, 6, 6); | |
| private static final Insets compInsets = new Insets(3, 6, 3, 6); | |
| private static ResourceBundle messageRB; | |
| private JTabbedPane tpTabs; | |
| private JButton btnCancel, btnApprove; | |
| private PrintService[] services; | |
| private int defaultServiceIndex; | |
| private PrintRequestAttributeSet asOriginal; | |
| private HashPrintRequestAttributeSet asCurrent; | |
| private PrintService psCurrent; | |
| private DocFlavor docFlavor; | |
| private int status; | |
| private ValidatingFileChooser jfc; | |
| private GeneralPanel pnlGeneral; | |
| private PageSetupPanel pnlPageSetup; | |
| private AppearancePanel pnlAppearance; | |
| private boolean isAWT = false; | |
| static { | |
| initResource(); | |
| } | |
| /** | |
| * Constructor for the "standard" print dialog (containing all relevant | |
| * tabs) | |
| */ | |
| public ServiceDialog(GraphicsConfiguration gc, | |
| int x, int y, | |
| PrintService[] services, | |
| int defaultServiceIndex, | |
| DocFlavor flavor, | |
| PrintRequestAttributeSet attributes, | |
| Window window) | |
| { | |
| super(window, getMsg("dialog.printtitle"), Dialog.DEFAULT_MODALITY_TYPE, gc); | |
| initPrintDialog(x, y, services, defaultServiceIndex, | |
| flavor, attributes); | |
| } | |
| /** | |
| * Initialize print dialog. | |
| */ | |
| void initPrintDialog(int x, int y, | |
| PrintService[] services, | |
| int defaultServiceIndex, | |
| DocFlavor flavor, | |
| PrintRequestAttributeSet attributes) | |
| { | |
| this.services = services; | |
| this.defaultServiceIndex = defaultServiceIndex; | |
| this.asOriginal = attributes; | |
| this.asCurrent = new HashPrintRequestAttributeSet(attributes); | |
| this.psCurrent = services[defaultServiceIndex]; | |
| this.docFlavor = flavor; | |
| SunPageSelection pages = | |
| (SunPageSelection)attributes.get(SunPageSelection.class); | |
| if (pages != null) { | |
| isAWT = true; | |
| } | |
| if (attributes.get(DialogOwner.class) != null) { | |
| DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class); | |
| /* When the ServiceDialog is constructed the caller of the | |
| * constructor checks for this attribute and if it specifies a | |
| * window then it will use that in the constructor instead of | |
| * inferring one from keyboard focus. | |
| * In this case the owner of the dialog is the same as that | |
| * specified in the attribute and we do not need to set the | |
| * on top property | |
| */ | |
| if ((getOwner() == null) || (owner.getOwner() != getOwner())) { | |
| setAlwaysOnTop(true); | |
| } | |
| } | |
| Container c = getContentPane(); | |
| c.setLayout(new BorderLayout()); | |
| tpTabs = new JTabbedPane(); | |
| tpTabs.setBorder(new EmptyBorder(5, 5, 5, 5)); | |
| String gkey = getMsg("tab.general"); | |
| int gmnemonic = getVKMnemonic("tab.general"); | |
| pnlGeneral = new GeneralPanel(); | |
| tpTabs.add(gkey, pnlGeneral); | |
| tpTabs.setMnemonicAt(0, gmnemonic); | |
| String pkey = getMsg("tab.pagesetup"); | |
| int pmnemonic = getVKMnemonic("tab.pagesetup"); | |
| pnlPageSetup = new PageSetupPanel(); | |
| tpTabs.add(pkey, pnlPageSetup); | |
| tpTabs.setMnemonicAt(1, pmnemonic); | |
| String akey = getMsg("tab.appearance"); | |
| int amnemonic = getVKMnemonic("tab.appearance"); | |
| pnlAppearance = new AppearancePanel(); | |
| tpTabs.add(akey, pnlAppearance); | |
| tpTabs.setMnemonicAt(2, amnemonic); | |
| c.add(tpTabs, BorderLayout.CENTER); | |
| updatePanels(); | |
| JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING)); | |
| btnApprove = createExitButton("button.print", this); | |
| pnlSouth.add(btnApprove); | |
| getRootPane().setDefaultButton(btnApprove); | |
| btnCancel = createExitButton("button.cancel", this); | |
| handleEscKey(btnCancel); | |
| pnlSouth.add(btnCancel); | |
| c.add(pnlSouth, BorderLayout.SOUTH); | |
| addWindowListener(new WindowAdapter() { | |
| public void windowClosing(WindowEvent event) { | |
| dispose(CANCEL); | |
| } | |
| }); | |
| getAccessibleContext().setAccessibleDescription(getMsg("dialog.printtitle")); | |
| setResizable(false); | |
| setLocation(x, y); | |
| pack(); | |
| } | |
| /** | |
| * Constructor for the solitary "page setup" dialog | |
| */ | |
| public ServiceDialog(GraphicsConfiguration gc, | |
| int x, int y, | |
| PrintService ps, | |
| DocFlavor flavor, | |
| PrintRequestAttributeSet attributes, | |
| Window window) | |
| { | |
| super(window, getMsg("dialog.pstitle"), Dialog.DEFAULT_MODALITY_TYPE, gc); | |
| initPageDialog(x, y, ps, flavor, attributes); | |
| } | |
| /** | |
| * Initialize "page setup" dialog | |
| */ | |
| void initPageDialog(int x, int y, | |
| PrintService ps, | |
| DocFlavor flavor, | |
| PrintRequestAttributeSet attributes) | |
| { | |
| this.psCurrent = ps; | |
| this.docFlavor = flavor; | |
| this.asOriginal = attributes; | |
| this.asCurrent = new HashPrintRequestAttributeSet(attributes); | |
| if (attributes.get(DialogOwner.class) != null) { | |
| /* See comments in same block in initPrintDialog */ | |
| DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class); | |
| if ((getOwner() == null) || (owner.getOwner() != getOwner())) { | |
| setAlwaysOnTop(true); | |
| } | |
| } | |
| Container c = getContentPane(); | |
| c.setLayout(new BorderLayout()); | |
| pnlPageSetup = new PageSetupPanel(); | |
| c.add(pnlPageSetup, BorderLayout.CENTER); | |
| pnlPageSetup.updateInfo(); | |
| JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING)); | |
| btnApprove = createExitButton("button.ok", this); | |
| pnlSouth.add(btnApprove); | |
| getRootPane().setDefaultButton(btnApprove); | |
| btnCancel = createExitButton("button.cancel", this); | |
| handleEscKey(btnCancel); | |
| pnlSouth.add(btnCancel); | |
| c.add(pnlSouth, BorderLayout.SOUTH); | |
| addWindowListener(new WindowAdapter() { | |
| public void windowClosing(WindowEvent event) { | |
| dispose(CANCEL); | |
| } | |
| }); | |
| getAccessibleContext().setAccessibleDescription(getMsg("dialog.pstitle")); | |
| setResizable(false); | |
| setLocation(x, y); | |
| pack(); | |
| } | |
| /** | |
| * Performs Cancel when Esc key is pressed. | |
| */ | |
| private void handleEscKey(JButton btnCancel) { | |
| Action cancelKeyAction = new AbstractAction() { | |
| public void actionPerformed(ActionEvent e) { | |
| dispose(CANCEL); | |
| } | |
| }; | |
| KeyStroke cancelKeyStroke = | |
| KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE, 0); | |
| InputMap inputMap = | |
| btnCancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); | |
| ActionMap actionMap = btnCancel.getActionMap(); | |
| if (inputMap != null && actionMap != null) { | |
| inputMap.put(cancelKeyStroke, "cancel"); | |
| actionMap.put("cancel", cancelKeyAction); | |
| } | |
| } | |
| /** | |
| * Returns the current status of the dialog (whether the user has selected | |
| * the "Print" or "Cancel" button) | |
| */ | |
| public int getStatus() { | |
| return status; | |
| } | |
| /** | |
| * Returns an AttributeSet based on whether or not the user cancelled the | |
| * dialog. If the user selected "Print" we return their new selections, | |
| * otherwise we return the attributes that were passed in initially. | |
| */ | |
| public PrintRequestAttributeSet getAttributes() { | |
| if (status == APPROVE) { | |
| return asCurrent; | |
| } else { | |
| return asOriginal; | |
| } | |
| } | |
| /** | |
| * Returns a PrintService based on whether or not the user cancelled the | |
| * dialog. If the user selected "Print" we return the user's selection | |
| * for the PrintService, otherwise we return null. | |
| */ | |
| public PrintService getPrintService() { | |
| if (status == APPROVE) { | |
| return psCurrent; | |
| } else { | |
| return null; | |
| } | |
| } | |
| /** | |
| * Sets the current status flag for the dialog and disposes it (thus | |
| * returning control of the parent frame back to the user) | |
| */ | |
| public void dispose(int status) { | |
| this.status = status; | |
| super.dispose(); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| boolean approved = false; | |
| if (source == btnApprove) { | |
| approved = true; | |
| if (pnlGeneral != null) { | |
| if (pnlGeneral.isPrintToFileRequested()) { | |
| approved = showFileChooser(); | |
| } else { | |
| asCurrent.remove(Destination.class); | |
| } | |
| } | |
| } | |
| dispose(approved ? APPROVE : CANCEL); | |
| } | |
| /** | |
| * Displays a JFileChooser that allows the user to select the destination | |
| * for "Print To File" | |
| */ | |
| private boolean showFileChooser() { | |
| Class<Destination> dstCategory = Destination.class; | |
| Destination dst = (Destination)asCurrent.get(dstCategory); | |
| if (dst == null) { | |
| dst = (Destination)asOriginal.get(dstCategory); | |
| if (dst == null) { | |
| dst = (Destination)psCurrent.getDefaultAttributeValue(dstCategory); | |
| // "dst" should not be null. The following code | |
| // is only added to safeguard against a possible | |
| // buggy implementation of a PrintService having a | |
| // null default Destination. | |
| if (dst == null) { | |
| try { | |
| dst = new Destination(new URI("file:out.prn")); | |
| } catch (URISyntaxException e) { | |
| } | |
| } | |
| } | |
| } | |
| File fileDest; | |
| if (dst != null) { | |
| try { | |
| fileDest = new File(dst.getURI()); | |
| } catch (Exception e) { | |
| // all manner of runtime exceptions possible | |
| fileDest = new File("out.prn"); | |
| } | |
| } else { | |
| fileDest = new File("out.prn"); | |
| } | |
| ValidatingFileChooser jfc = new ValidatingFileChooser(); | |
| jfc.setApproveButtonText(getMsg("button.ok")); | |
| jfc.setDialogTitle(getMsg("dialog.printtofile")); | |
| jfc.setDialogType(JFileChooser.SAVE_DIALOG); | |
| jfc.setSelectedFile(fileDest); | |
| int returnVal = jfc.showDialog(this, null); | |
| if (returnVal == JFileChooser.APPROVE_OPTION) { | |
| fileDest = jfc.getSelectedFile(); | |
| try { | |
| asCurrent.add(new Destination(fileDest.toURI())); | |
| } catch (Exception e) { | |
| asCurrent.remove(dstCategory); | |
| } | |
| } else { | |
| asCurrent.remove(dstCategory); | |
| } | |
| return (returnVal == JFileChooser.APPROVE_OPTION); | |
| } | |
| /** | |
| * Updates each of the top level panels | |
| */ | |
| private void updatePanels() { | |
| pnlGeneral.updateInfo(); | |
| pnlPageSetup.updateInfo(); | |
| pnlAppearance.updateInfo(); | |
| } | |
| /** | |
| * Initialize ResourceBundle | |
| */ | |
| public static void initResource() { | |
| try { | |
| messageRB = ResourceBundle.getBundle(strBundle); | |
| } catch (java.util.MissingResourceException e) { | |
| throw new Error("Fatal: Resource for ServiceUI " + | |
| "is missing"); | |
| } | |
| } | |
| /** | |
| * Returns message string from resource | |
| */ | |
| public static String getMsg(String key) { | |
| try { | |
| return removeMnemonics(messageRB.getString(key)); | |
| } catch (java.util.MissingResourceException e) { | |
| throw new Error("Fatal: Resource for ServiceUI is broken; " + | |
| "there is no " + key + " key in resource"); | |
| } | |
| } | |
| private static String removeMnemonics(String s) { | |
| int i = s.indexOf('&'); | |
| int len = s.length(); | |
| if (i < 0 || i == (len - 1)) { | |
| return s; | |
| } | |
| int j = s.indexOf('&', i+1); | |
| if (j == i+1) { | |
| if (j+1 == len) { | |
| return s.substring(0, i+1); // string ends with && | |
| } else { | |
| return s.substring(0, i+1) + removeMnemonics(s.substring(j+1)); | |
| } | |
| } | |
| // ok first & not double && | |
| if (i == 0) { | |
| return removeMnemonics(s.substring(1)); | |
| } else { | |
| return (s.substring(0, i) + removeMnemonics(s.substring(i+1))); | |
| } | |
| } | |
| /** | |
| * Returns mnemonic character from resource | |
| */ | |
| private static char getMnemonic(String key) { | |
| String str = messageRB.getString(key).replace("&&", ""); | |
| int index = str.indexOf('&'); | |
| if (0 <= index && index < str.length() - 1) { | |
| char c = str.charAt(index + 1); | |
| return Character.toUpperCase(c); | |
| } else { | |
| return (char)0; | |
| } | |
| } | |
| /** | |
| * Returns the mnemonic as a KeyEvent.VK constant from the resource. | |
| */ | |
| static Class<?> _keyEventClazz = null; | |
| private static int getVKMnemonic(String key) { | |
| String s = String.valueOf(getMnemonic(key)); | |
| if ( s == null || s.length() != 1) { | |
| return 0; | |
| } | |
| String vkString = "VK_" + s.toUpperCase(); | |
| try { | |
| if (_keyEventClazz == null) { | |
| _keyEventClazz= Class.forName("java.awt.event.KeyEvent", | |
| true, (ServiceDialog.class).getClassLoader()); | |
| } | |
| Field field = _keyEventClazz.getDeclaredField(vkString); | |
| int value = field.getInt(null); | |
| return value; | |
| } catch (Exception e) { | |
| } | |
| return 0; | |
| } | |
| /** | |
| * Returns URL for image resource | |
| */ | |
| private static URL getImageResource(final String key) { | |
| URL url = ServiceDialog.class.getResource("resources/" + key); | |
| if (url == null) { | |
| throw new Error("Fatal: Resource for ServiceUI is broken; " + | |
| "there is no " + key + " key in resource"); | |
| } | |
| return url; | |
| } | |
| /** | |
| * Creates a new JButton and sets its text, mnemonic, and ActionListener | |
| */ | |
| private static JButton createButton(String key, ActionListener al) { | |
| JButton btn = new JButton(getMsg(key)); | |
| btn.setMnemonic(getMnemonic(key)); | |
| btn.addActionListener(al); | |
| return btn; | |
| } | |
| /** | |
| * Creates a new JButton and sets its text, and ActionListener | |
| */ | |
| private static JButton createExitButton(String key, ActionListener al) { | |
| String str = getMsg(key); | |
| JButton btn = new JButton(str); | |
| btn.addActionListener(al); | |
| btn.getAccessibleContext().setAccessibleDescription(str); | |
| return btn; | |
| } | |
| /** | |
| * Creates a new JCheckBox and sets its text, mnemonic, and ActionListener | |
| */ | |
| private static JCheckBox createCheckBox(String key, ActionListener al) { | |
| JCheckBox cb = new JCheckBox(getMsg(key)); | |
| cb.setMnemonic(getMnemonic(key)); | |
| cb.addActionListener(al); | |
| return cb; | |
| } | |
| /** | |
| * Creates a new JRadioButton and sets its text, mnemonic, | |
| * and ActionListener | |
| */ | |
| private static JRadioButton createRadioButton(String key, | |
| ActionListener al) | |
| { | |
| JRadioButton rb = new JRadioButton(getMsg(key)); | |
| rb.setMnemonic(getMnemonic(key)); | |
| rb.addActionListener(al); | |
| return rb; | |
| } | |
| /** | |
| * Creates a pop-up dialog for "no print service" | |
| */ | |
| public static void showNoPrintService(GraphicsConfiguration gc) | |
| { | |
| Frame dlgFrame = new Frame(gc); | |
| JOptionPane.showMessageDialog(dlgFrame, | |
| getMsg("dialog.noprintermsg")); | |
| dlgFrame.dispose(); | |
| } | |
| /** | |
| * Sets the constraints for the GridBagLayout and adds the Component | |
| * to the given Container | |
| */ | |
| private static void addToGB(Component comp, Container cont, | |
| GridBagLayout gridbag, | |
| GridBagConstraints constraints) | |
| { | |
| gridbag.setConstraints(comp, constraints); | |
| cont.add(comp); | |
| } | |
| /** | |
| * Adds the AbstractButton to both the given ButtonGroup and Container | |
| */ | |
| private static void addToBG(AbstractButton button, Container cont, | |
| ButtonGroup bg) | |
| { | |
| bg.add(button); | |
| cont.add(button); | |
| } | |
| /** | |
| * The "General" tab. Includes the controls for PrintService, | |
| * PageRange, and Copies/Collate. | |
| */ | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class GeneralPanel extends JPanel { | |
| private PrintServicePanel pnlPrintService; | |
| private PrintRangePanel pnlPrintRange; | |
| private CopiesPanel pnlCopies; | |
| public GeneralPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = panelInsets; | |
| c.weightx = 1.0; | |
| c.weighty = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlPrintService = new PrintServicePanel(); | |
| addToGB(pnlPrintService, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| pnlPrintRange = new PrintRangePanel(); | |
| addToGB(pnlPrintRange, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlCopies = new CopiesPanel(); | |
| addToGB(pnlCopies, this, gridbag, c); | |
| } | |
| public boolean isPrintToFileRequested() { | |
| return (pnlPrintService.isPrintToFileSelected()); | |
| } | |
| public void updateInfo() { | |
| pnlPrintService.updateInfo(); | |
| pnlPrintRange.updateInfo(); | |
| pnlCopies.updateInfo(); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class PrintServicePanel extends JPanel | |
| implements ActionListener, ItemListener, PopupMenuListener | |
| { | |
| private final String strTitle = getMsg("border.printservice"); | |
| private JButton btnProperties; | |
| private JCheckBox cbPrintToFile; | |
| private JComboBox<String> cbName; | |
| private JLabel lblType, lblStatus, lblInfo; | |
| private ServiceUIFactory uiFactory; | |
| private boolean changedService = false; | |
| public PrintServicePanel() { | |
| super(); | |
| uiFactory = psCurrent.getServiceUIFactory(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| String[] psnames = new String[services.length]; | |
| for (int i = 0; i < psnames.length; i++) { | |
| psnames[i] = services[i].getName(); | |
| } | |
| cbName = new JComboBox<>(psnames); | |
| cbName.setSelectedIndex(defaultServiceIndex); | |
| cbName.addItemListener(this); | |
| cbName.addPopupMenuListener(this); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.weightx = 0.0; | |
| JLabel lblName = new JLabel(getMsg("label.psname"), JLabel.TRAILING); | |
| lblName.setDisplayedMnemonic(getMnemonic("label.psname")); | |
| lblName.setLabelFor(cbName); | |
| addToGB(lblName, this, gridbag, c); | |
| c.weightx = 1.0; | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| addToGB(cbName, this, gridbag, c); | |
| c.weightx = 0.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| btnProperties = createButton("button.properties", this); | |
| addToGB(btnProperties, this, gridbag, c); | |
| c.weighty = 1.0; | |
| lblStatus = addLabel(getMsg("label.status"), gridbag, c); | |
| lblStatus.setLabelFor(null); | |
| lblType = addLabel(getMsg("label.pstype"), gridbag, c); | |
| lblType.setLabelFor(null); | |
| c.gridwidth = 1; | |
| addToGB(new JLabel(getMsg("label.info"), JLabel.TRAILING), | |
| this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| lblInfo = new JLabel(); | |
| lblInfo.setLabelFor(null); | |
| addToGB(lblInfo, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| cbPrintToFile = createCheckBox("checkbox.printtofile", this); | |
| addToGB(cbPrintToFile, this, gridbag, c); | |
| } | |
| public boolean isPrintToFileSelected() { | |
| return cbPrintToFile.isSelected(); | |
| } | |
| private JLabel addLabel(String text, | |
| GridBagLayout gridbag, GridBagConstraints c) | |
| { | |
| c.gridwidth = 1; | |
| addToGB(new JLabel(text, JLabel.TRAILING), this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| JLabel label = new JLabel(); | |
| addToGB(label, this, gridbag, c); | |
| return label; | |
| } | |
| @SuppressWarnings("deprecation") | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| if (source == btnProperties) { | |
| if (uiFactory != null) { | |
| JDialog dialog = (JDialog)uiFactory.getUI( | |
| ServiceUIFactory.MAIN_UIROLE, | |
| ServiceUIFactory.JDIALOG_UI); | |
| if (dialog != null) { | |
| dialog.show(); | |
| } else { | |
| DocumentPropertiesUI docPropertiesUI = null; | |
| try { | |
| docPropertiesUI = | |
| (DocumentPropertiesUI)uiFactory.getUI | |
| (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE, | |
| DocumentPropertiesUI.DOCPROPERTIESCLASSNAME); | |
| } catch (Exception ex) { | |
| } | |
| if (docPropertiesUI != null) { | |
| PrinterJobWrapper wrapper = (PrinterJobWrapper) | |
| asCurrent.get(PrinterJobWrapper.class); | |
| if (wrapper == null) { | |
| return; // should not happen, defensive only. | |
| } | |
| PrinterJob job = wrapper.getPrinterJob(); | |
| if (job == null) { | |
| return; // should not happen, defensive only. | |
| } | |
| PrintRequestAttributeSet newAttrs = | |
| docPropertiesUI.showDocumentProperties | |
| (job, ServiceDialog.this, psCurrent, asCurrent); | |
| if (newAttrs != null) { | |
| asCurrent.addAll(newAttrs); | |
| updatePanels(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| public void itemStateChanged(ItemEvent e) { | |
| if (e.getStateChange() == ItemEvent.SELECTED) { | |
| int index = cbName.getSelectedIndex(); | |
| if ((index >= 0) && (index < services.length)) { | |
| if (!services[index].equals(psCurrent)) { | |
| psCurrent = services[index]; | |
| uiFactory = psCurrent.getServiceUIFactory(); | |
| changedService = true; | |
| Destination dest = | |
| (Destination)asOriginal.get(Destination.class); | |
| // to preserve the state of Print To File | |
| if ((dest != null || isPrintToFileSelected()) | |
| && psCurrent.isAttributeCategorySupported( | |
| Destination.class)) { | |
| if (dest != null) { | |
| asCurrent.add(dest); | |
| } else { | |
| dest = (Destination)psCurrent. | |
| getDefaultAttributeValue(Destination.class); | |
| // "dest" should not be null. The following code | |
| // is only added to safeguard against a possible | |
| // buggy implementation of a PrintService having a | |
| // null default Destination. | |
| if (dest == null) { | |
| try { | |
| dest = | |
| new Destination(new URI("file:out.prn")); | |
| } catch (URISyntaxException ue) { | |
| } | |
| } | |
| if (dest != null) { | |
| asCurrent.add(dest); | |
| } | |
| } | |
| } else { | |
| asCurrent.remove(Destination.class); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| public void popupMenuWillBecomeVisible(PopupMenuEvent e) { | |
| changedService = false; | |
| } | |
| public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { | |
| if (changedService) { | |
| changedService = false; | |
| updatePanels(); | |
| } | |
| } | |
| public void popupMenuCanceled(PopupMenuEvent e) { | |
| } | |
| /** | |
| * We disable the "Print To File" checkbox if this returns false | |
| */ | |
| private boolean allowedToPrintToFile() { | |
| return true; | |
| } | |
| public void updateInfo() { | |
| Class<Destination> dstCategory = Destination.class; | |
| boolean dstSupported = false; | |
| boolean dstSelected = false; | |
| // setup Destination (print-to-file) widgets | |
| Destination dst = (Destination)asCurrent.get(dstCategory); | |
| if (dst != null) { | |
| try { | |
| dst.getURI().toURL(); | |
| if (psCurrent.isAttributeValueSupported(dst, docFlavor, | |
| asCurrent)) { | |
| dstSupported = true; | |
| dstSelected = true; | |
| } | |
| } catch (MalformedURLException ex) { | |
| dstSupported = true; | |
| } | |
| } else { | |
| if (psCurrent.isAttributeCategorySupported(dstCategory)) { | |
| dstSupported = true; | |
| } | |
| } | |
| cbPrintToFile.setEnabled(dstSupported); | |
| cbPrintToFile.setSelected(dstSelected && dstSupported); | |
| // setup PrintService information widgets | |
| Attribute type = psCurrent.getAttribute(PrinterMakeAndModel.class); | |
| if (type != null) { | |
| lblType.setText(type.toString()); | |
| } | |
| Attribute status = | |
| psCurrent.getAttribute(PrinterIsAcceptingJobs.class); | |
| if (status != null) { | |
| lblStatus.setText(getMsg(status.toString())); | |
| } | |
| Attribute info = psCurrent.getAttribute(PrinterInfo.class); | |
| if (info != null) { | |
| lblInfo.setText(info.toString()); | |
| } | |
| PrinterJob job = null; | |
| PrinterJobWrapper wrapper = (PrinterJobWrapper) | |
| asCurrent.get(PrinterJobWrapper.class); | |
| if (wrapper != null) { | |
| job = wrapper.getPrinterJob(); | |
| } | |
| btnProperties.setEnabled(uiFactory != null && job != null); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class PrintRangePanel extends JPanel | |
| implements ActionListener, FocusListener | |
| { | |
| private final String strTitle = getMsg("border.printrange"); | |
| private final PageRanges prAll = new PageRanges(1, Integer.MAX_VALUE); | |
| private JRadioButton rbAll, rbPages, rbSelect; | |
| private JFormattedTextField tfRangeFrom, tfRangeTo; | |
| private JLabel lblRangeTo; | |
| private boolean prSupported; | |
| private boolean prPgRngSupported; | |
| public PrintRangePanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| ButtonGroup bg = new ButtonGroup(); | |
| JPanel pnlTop = new JPanel(new FlowLayout(FlowLayout.LEADING)); | |
| rbAll = createRadioButton("radiobutton.rangeall", this); | |
| rbAll.setSelected(true); | |
| bg.add(rbAll); | |
| pnlTop.add(rbAll); | |
| addToGB(pnlTop, this, gridbag, c); | |
| // Selection never seemed to work so I'm commenting this part. | |
| /* | |
| if (isAWT) { | |
| JPanel pnlMiddle = | |
| new JPanel(new FlowLayout(FlowLayout.LEADING)); | |
| rbSelect = | |
| createRadioButton("radiobutton.selection", this); | |
| bg.add(rbSelect); | |
| pnlMiddle.add(rbSelect); | |
| addToGB(pnlMiddle, this, gridbag, c); | |
| } | |
| */ | |
| JPanel pnlBottom = new JPanel(new FlowLayout(FlowLayout.LEADING)); | |
| rbPages = createRadioButton("radiobutton.rangepages", this); | |
| bg.add(rbPages); | |
| pnlBottom.add(rbPages); | |
| DecimalFormat format = new DecimalFormat("####0"); | |
| format.setMinimumFractionDigits(0); | |
| format.setMaximumFractionDigits(0); | |
| format.setMinimumIntegerDigits(0); | |
| format.setMaximumIntegerDigits(5); | |
| format.setParseIntegerOnly(true); | |
| format.setDecimalSeparatorAlwaysShown(false); | |
| NumberFormatter nf = new NumberFormatter(format); | |
| nf.setMinimum(1); | |
| nf.setMaximum(Integer.MAX_VALUE); | |
| nf.setAllowsInvalid(true); | |
| nf.setCommitsOnValidEdit(true); | |
| tfRangeFrom = new JFormattedTextField(nf); | |
| tfRangeFrom.setColumns(4); | |
| tfRangeFrom.setEnabled(false); | |
| tfRangeFrom.addActionListener(this); | |
| tfRangeFrom.addFocusListener(this); | |
| tfRangeFrom.setFocusLostBehavior( | |
| JFormattedTextField.PERSIST); | |
| tfRangeFrom.getAccessibleContext().setAccessibleName( | |
| getMsg("radiobutton.rangepages")); | |
| pnlBottom.add(tfRangeFrom); | |
| lblRangeTo = new JLabel(getMsg("label.rangeto")); | |
| lblRangeTo.setEnabled(false); | |
| pnlBottom.add(lblRangeTo); | |
| NumberFormatter nfto; | |
| try { | |
| nfto = (NumberFormatter)nf.clone(); | |
| } catch (CloneNotSupportedException e) { | |
| nfto = new NumberFormatter(); | |
| } | |
| tfRangeTo = new JFormattedTextField(nfto); | |
| tfRangeTo.setColumns(4); | |
| tfRangeTo.setEnabled(false); | |
| tfRangeTo.addFocusListener(this); | |
| tfRangeTo.getAccessibleContext().setAccessibleName( | |
| getMsg("label.rangeto")); | |
| pnlBottom.add(tfRangeTo); | |
| addToGB(pnlBottom, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| SunPageSelection select = SunPageSelection.ALL; | |
| setupRangeWidgets(); | |
| if (source == rbAll) { | |
| asCurrent.add(prAll); | |
| } else if (source == rbSelect) { | |
| select = SunPageSelection.SELECTION; | |
| } else if (source == rbPages || | |
| source == tfRangeFrom || | |
| source == tfRangeTo) { | |
| updateRangeAttribute(); | |
| select = SunPageSelection.RANGE; | |
| } | |
| if (isAWT) { | |
| asCurrent.add(select); | |
| } | |
| } | |
| public void focusLost(FocusEvent e) { | |
| Object source = e.getSource(); | |
| if ((source == tfRangeFrom) || (source == tfRangeTo)) { | |
| updateRangeAttribute(); | |
| } | |
| } | |
| public void focusGained(FocusEvent e) {} | |
| private void setupRangeWidgets() { | |
| boolean rangeEnabled = (rbPages.isSelected() && prPgRngSupported); | |
| tfRangeFrom.setEnabled(rangeEnabled); | |
| tfRangeTo.setEnabled(rangeEnabled); | |
| lblRangeTo.setEnabled(rangeEnabled); | |
| } | |
| private void updateRangeAttribute() { | |
| String strFrom = tfRangeFrom.getText(); | |
| String strTo = tfRangeTo.getText(); | |
| int min; | |
| int max; | |
| try { | |
| min = Integer.parseInt(strFrom); | |
| } catch (NumberFormatException e) { | |
| min = 1; | |
| } | |
| try { | |
| max = Integer.parseInt(strTo); | |
| } catch (NumberFormatException e) { | |
| max = min; | |
| } | |
| if (min < 1) { | |
| min = 1; | |
| tfRangeFrom.setValue(1); | |
| } | |
| if (max < min) { | |
| max = min; | |
| tfRangeTo.setValue(min); | |
| } | |
| PageRanges pr = new PageRanges(min, max); | |
| asCurrent.add(pr); | |
| } | |
| public void updateInfo() { | |
| Class<PageRanges> prCategory = PageRanges.class; | |
| prSupported = false; | |
| if (psCurrent.isAttributeCategorySupported(prCategory) || | |
| isAWT) { | |
| prSupported = true; | |
| prPgRngSupported = psCurrent.isAttributeValueSupported(prAll, | |
| docFlavor, | |
| asCurrent); | |
| } | |
| SunPageSelection select = SunPageSelection.ALL; | |
| int min = 1; | |
| int max = 1; | |
| PageRanges pr = (PageRanges)asCurrent.get(prCategory); | |
| if (pr != null) { | |
| if (!pr.equals(prAll)) { | |
| select = SunPageSelection.RANGE; | |
| int[][] members = pr.getMembers(); | |
| if ((members.length > 0) && | |
| (members[0].length > 1)) { | |
| min = members[0][0]; | |
| max = members[0][1]; | |
| } | |
| } | |
| } | |
| if (isAWT) { | |
| select = (SunPageSelection)asCurrent.get( | |
| SunPageSelection.class); | |
| } | |
| if (select == SunPageSelection.ALL) { | |
| rbAll.setSelected(true); | |
| } else if (select == SunPageSelection.SELECTION) { | |
| // Comment this for now - rbSelect is not initialized | |
| // because Selection button is not added. | |
| // See PrintRangePanel above. | |
| //rbSelect.setSelected(true); | |
| } else { // RANGE | |
| rbPages.setSelected(true); | |
| } | |
| tfRangeFrom.setValue(min); | |
| tfRangeTo.setValue(max); | |
| rbAll.setEnabled(prSupported); | |
| rbPages.setEnabled(prPgRngSupported); | |
| setupRangeWidgets(); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class CopiesPanel extends JPanel | |
| implements ActionListener, ChangeListener | |
| { | |
| private final String strTitle = getMsg("border.copies"); | |
| private SpinnerNumberModel snModel; | |
| private JSpinner spinCopies; | |
| private JLabel lblCopies; | |
| private JCheckBox cbCollate; | |
| private boolean scSupported; | |
| public CopiesPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.HORIZONTAL; | |
| c.insets = compInsets; | |
| lblCopies = new JLabel(getMsg("label.numcopies"), JLabel.TRAILING); | |
| lblCopies.setDisplayedMnemonic(getMnemonic("label.numcopies")); | |
| lblCopies.getAccessibleContext().setAccessibleName( | |
| getMsg("label.numcopies")); | |
| addToGB(lblCopies, this, gridbag, c); | |
| snModel = new SpinnerNumberModel(1, 1, 999, 1); | |
| spinCopies = new JSpinner(snModel); | |
| lblCopies.setLabelFor(spinCopies); | |
| // REMIND | |
| ((JSpinner.NumberEditor)spinCopies.getEditor()).getTextField().setColumns(3); | |
| spinCopies.addChangeListener(this); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(spinCopies, this, gridbag, c); | |
| cbCollate = createCheckBox("checkbox.collate", this); | |
| cbCollate.setEnabled(false); | |
| addToGB(cbCollate, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| if (cbCollate.isSelected()) { | |
| asCurrent.add(SheetCollate.COLLATED); | |
| } else { | |
| asCurrent.add(SheetCollate.UNCOLLATED); | |
| } | |
| } | |
| public void stateChanged(ChangeEvent e) { | |
| updateCollateCB(); | |
| asCurrent.add(new Copies(snModel.getNumber().intValue())); | |
| } | |
| private void updateCollateCB() { | |
| int num = snModel.getNumber().intValue(); | |
| if (isAWT) { | |
| cbCollate.setEnabled(true); | |
| } else { | |
| cbCollate.setEnabled((num > 1) && scSupported); | |
| } | |
| } | |
| public void updateInfo() { | |
| Class<Copies> cpCategory = Copies.class; | |
| Class<SheetCollate> scCategory = SheetCollate.class; | |
| boolean cpSupported = false; | |
| scSupported = false; | |
| // setup Copies spinner | |
| if (psCurrent.isAttributeCategorySupported(cpCategory)) { | |
| cpSupported = true; | |
| } | |
| CopiesSupported cs = | |
| (CopiesSupported)psCurrent.getSupportedAttributeValues( | |
| cpCategory, null, null); | |
| if (cs == null) { | |
| cs = new CopiesSupported(1, 999); | |
| } | |
| Copies cp = (Copies)asCurrent.get(cpCategory); | |
| if (cp == null) { | |
| cp = (Copies)psCurrent.getDefaultAttributeValue(cpCategory); | |
| if (cp == null) { | |
| cp = new Copies(1); | |
| } | |
| } | |
| spinCopies.setEnabled(cpSupported); | |
| lblCopies.setEnabled(cpSupported); | |
| int[][] members = cs.getMembers(); | |
| int min, max; | |
| if ((members.length > 0) && (members[0].length > 0)) { | |
| min = members[0][0]; | |
| max = members[0][1]; | |
| } else { | |
| min = 1; | |
| max = Integer.MAX_VALUE; | |
| } | |
| snModel.setMinimum(min); | |
| snModel.setMaximum(max); | |
| int value = cp.getValue(); | |
| if ((value < min) || (value > max)) { | |
| value = min; | |
| } | |
| snModel.setValue(value); | |
| // setup Collate checkbox | |
| if (psCurrent.isAttributeCategorySupported(scCategory)) { | |
| scSupported = true; | |
| } | |
| SheetCollate sc = (SheetCollate)asCurrent.get(scCategory); | |
| if (sc == null) { | |
| sc = (SheetCollate)psCurrent.getDefaultAttributeValue(scCategory); | |
| if (sc == null) { | |
| sc = SheetCollate.UNCOLLATED; | |
| } | |
| if (sc != null && | |
| !psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { | |
| scSupported = false; | |
| } | |
| } else { | |
| if (!psCurrent.isAttributeValueSupported(sc, docFlavor, asCurrent)) { | |
| scSupported = false; | |
| } | |
| } | |
| cbCollate.setSelected(sc == SheetCollate.COLLATED && scSupported); | |
| updateCollateCB(); | |
| } | |
| } | |
| /** | |
| * The "Page Setup" tab. Includes the controls for MediaSource/MediaTray, | |
| * OrientationRequested, and Sides. | |
| */ | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class PageSetupPanel extends JPanel { | |
| private MediaPanel pnlMedia; | |
| private OrientationPanel pnlOrientation; | |
| private MarginsPanel pnlMargins; | |
| public PageSetupPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = panelInsets; | |
| c.weightx = 1.0; | |
| c.weighty = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlMedia = new MediaPanel(); | |
| addToGB(pnlMedia, this, gridbag, c); | |
| pnlOrientation = new OrientationPanel(); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| addToGB(pnlOrientation, this, gridbag, c); | |
| pnlMargins = new MarginsPanel(); | |
| pnlOrientation.addOrientationListener(pnlMargins); | |
| pnlMedia.addMediaListener(pnlMargins); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(pnlMargins, this, gridbag, c); | |
| } | |
| public void updateInfo() { | |
| pnlMedia.updateInfo(); | |
| pnlOrientation.updateInfo(); | |
| pnlMargins.updateInfo(); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class MarginsPanel extends JPanel | |
| implements ActionListener, FocusListener { | |
| private final String strTitle = getMsg("border.margins"); | |
| private JFormattedTextField leftMargin, rightMargin, | |
| topMargin, bottomMargin; | |
| private JLabel lblLeft, lblRight, lblTop, lblBottom; | |
| private int units = MediaPrintableArea.MM; | |
| // storage for the last margin values calculated, -ve is uninitialised | |
| private float lmVal = -1f,rmVal = -1f, tmVal = -1f, bmVal = -1f; | |
| // storage for margins as objects mapped into orientation for display | |
| private Float lmObj,rmObj,tmObj,bmObj; | |
| public MarginsPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| c.fill = GridBagConstraints.HORIZONTAL; | |
| c.weightx = 1.0; | |
| c.weighty = 0.0; | |
| c.insets = compInsets; | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| String unitsKey = "label.millimetres"; | |
| String defaultCountry = Locale.getDefault().getCountry(); | |
| if (defaultCountry != null && | |
| (defaultCountry.isEmpty() || | |
| defaultCountry.equals(Locale.US.getCountry()) || | |
| defaultCountry.equals(Locale.CANADA.getCountry()))) { | |
| unitsKey = "label.inches"; | |
| units = MediaPrintableArea.INCH; | |
| } | |
| String unitsMsg = getMsg(unitsKey); | |
| DecimalFormat format; | |
| if (units == MediaPrintableArea.MM) { | |
| format = new DecimalFormat("###.##"); | |
| format.setMaximumIntegerDigits(3); | |
| } else { | |
| format = new DecimalFormat("##.##"); | |
| format.setMaximumIntegerDigits(2); | |
| } | |
| format.setMinimumFractionDigits(1); | |
| format.setMaximumFractionDigits(2); | |
| format.setMinimumIntegerDigits(1); | |
| format.setParseIntegerOnly(false); | |
| format.setDecimalSeparatorAlwaysShown(true); | |
| NumberFormatter nf = new NumberFormatter(format); | |
| nf.setMinimum(Float.valueOf(0.0f)); | |
| nf.setMaximum(Float.valueOf(999.0f)); | |
| nf.setAllowsInvalid(true); | |
| nf.setCommitsOnValidEdit(true); | |
| leftMargin = new JFormattedTextField(nf); | |
| leftMargin.addFocusListener(this); | |
| leftMargin.addActionListener(this); | |
| leftMargin.getAccessibleContext().setAccessibleName( | |
| getMsg("label.leftmargin")); | |
| rightMargin = new JFormattedTextField(nf); | |
| rightMargin.addFocusListener(this); | |
| rightMargin.addActionListener(this); | |
| rightMargin.getAccessibleContext().setAccessibleName( | |
| getMsg("label.rightmargin")); | |
| topMargin = new JFormattedTextField(nf); | |
| topMargin.addFocusListener(this); | |
| topMargin.addActionListener(this); | |
| topMargin.getAccessibleContext().setAccessibleName( | |
| getMsg("label.topmargin")); | |
| bottomMargin = new JFormattedTextField(nf); | |
| bottomMargin.addFocusListener(this); | |
| bottomMargin.addActionListener(this); | |
| bottomMargin.getAccessibleContext().setAccessibleName( | |
| getMsg("label.bottommargin")); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| lblLeft = new JLabel(getMsg("label.leftmargin") + " " + unitsMsg, | |
| JLabel.LEADING); | |
| lblLeft.setDisplayedMnemonic(getMnemonic("label.leftmargin")); | |
| lblLeft.setLabelFor(leftMargin); | |
| addToGB(lblLeft, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| lblRight = new JLabel(getMsg("label.rightmargin") + " " + unitsMsg, | |
| JLabel.LEADING); | |
| lblRight.setDisplayedMnemonic(getMnemonic("label.rightmargin")); | |
| lblRight.setLabelFor(rightMargin); | |
| addToGB(lblRight, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| addToGB(leftMargin, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(rightMargin, this, gridbag, c); | |
| // add an invisible spacing component. | |
| addToGB(new JPanel(), this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| lblTop = new JLabel(getMsg("label.topmargin") + " " + unitsMsg, | |
| JLabel.LEADING); | |
| lblTop.setDisplayedMnemonic(getMnemonic("label.topmargin")); | |
| lblTop.setLabelFor(topMargin); | |
| addToGB(lblTop, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| lblBottom = new JLabel(getMsg("label.bottommargin") + | |
| " " + unitsMsg, JLabel.LEADING); | |
| lblBottom.setDisplayedMnemonic(getMnemonic("label.bottommargin")); | |
| lblBottom.setLabelFor(bottomMargin); | |
| addToGB(lblBottom, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| addToGB(topMargin, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(bottomMargin, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| updateMargins(source); | |
| } | |
| public void focusLost(FocusEvent e) { | |
| Object source = e.getSource(); | |
| updateMargins(source); | |
| } | |
| public void focusGained(FocusEvent e) {} | |
| /* Get the numbers, use to create a MPA. | |
| * If its valid, accept it and update the attribute set. | |
| * If its not valid, then reject it and call updateInfo() | |
| * to re-establish the previous entries. | |
| */ | |
| public void updateMargins(Object source) { | |
| if (!(source instanceof JFormattedTextField)) { | |
| return; | |
| } else { | |
| JFormattedTextField tf = (JFormattedTextField)source; | |
| Float val = (Float)tf.getValue(); | |
| if (val == null) { | |
| return; | |
| } | |
| if (tf == leftMargin && val.equals(lmObj)) { | |
| return; | |
| } | |
| if (tf == rightMargin && val.equals(rmObj)) { | |
| return; | |
| } | |
| if (tf == topMargin && val.equals(tmObj)) { | |
| return; | |
| } | |
| if (tf == bottomMargin && val.equals(bmObj)) { | |
| return; | |
| } | |
| } | |
| Float lmTmpObj = (Float)leftMargin.getValue(); | |
| Float rmTmpObj = (Float)rightMargin.getValue(); | |
| Float tmTmpObj = (Float)topMargin.getValue(); | |
| Float bmTmpObj = (Float)bottomMargin.getValue(); | |
| float lm = lmTmpObj.floatValue(); | |
| float rm = rmTmpObj.floatValue(); | |
| float tm = tmTmpObj.floatValue(); | |
| float bm = bmTmpObj.floatValue(); | |
| /* adjust for orientation */ | |
| Class<OrientationRequested> orCategory = OrientationRequested.class; | |
| OrientationRequested or = | |
| (OrientationRequested)asCurrent.get(orCategory); | |
| if (or == null) { | |
| or = (OrientationRequested) | |
| psCurrent.getDefaultAttributeValue(orCategory); | |
| } | |
| float tmp; | |
| if (or == OrientationRequested.REVERSE_PORTRAIT) { | |
| tmp = lm; lm = rm; rm = tmp; | |
| tmp = tm; tm = bm; bm = tmp; | |
| } else if (or == OrientationRequested.LANDSCAPE) { | |
| tmp = lm; | |
| lm = tm; | |
| tm = rm; | |
| rm = bm; | |
| bm = tmp; | |
| } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { | |
| tmp = lm; | |
| lm = bm; | |
| bm = rm; | |
| rm = tm; | |
| tm = tmp; | |
| } | |
| MediaPrintableArea mpa; | |
| if ((mpa = validateMargins(lm, rm, tm, bm)) != null) { | |
| asCurrent.add(mpa); | |
| lmVal = lm; | |
| rmVal = rm; | |
| tmVal = tm; | |
| bmVal = bm; | |
| lmObj = lmTmpObj; | |
| rmObj = rmTmpObj; | |
| tmObj = tmTmpObj; | |
| bmObj = bmTmpObj; | |
| } else { | |
| if (lmObj == null || rmObj == null || | |
| tmObj == null || bmObj == null) { | |
| return; | |
| } else { | |
| leftMargin.setValue(lmObj); | |
| rightMargin.setValue(rmObj); | |
| topMargin.setValue(tmObj); | |
| bottomMargin.setValue(bmObj); | |
| } | |
| } | |
| } | |
| /* | |
| * This method either accepts the values and creates a new | |
| * MediaPrintableArea, or does nothing. | |
| * It should not attempt to create a printable area from anything | |
| * other than the exact values passed in. | |
| * But REMIND/TBD: it would be user friendly to replace margins the | |
| * user entered but are out of bounds with the minimum. | |
| * At that point this method will need to take responsibility for | |
| * updating the "stored" values and the UI. | |
| */ | |
| private MediaPrintableArea validateMargins(float lm, float rm, | |
| float tm, float bm) { | |
| Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; | |
| MediaPrintableArea mpa; | |
| MediaPrintableArea mpaMax = null; | |
| MediaSize mediaSize = null; | |
| Media media = (Media)asCurrent.get(Media.class); | |
| if (!(media instanceof MediaSizeName)) { | |
| media = (Media)psCurrent.getDefaultAttributeValue(Media.class); | |
| } | |
| if (media instanceof MediaSizeName msn) { | |
| mediaSize = MediaSize.getMediaSizeForName(msn); | |
| } | |
| if (mediaSize == null) { | |
| mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); | |
| } | |
| if (media != null) { | |
| PrintRequestAttributeSet tmpASet = | |
| new HashPrintRequestAttributeSet(asCurrent); | |
| tmpASet.add(media); | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(mpaCategory, | |
| docFlavor, | |
| tmpASet); | |
| if (values instanceof MediaPrintableArea[] && | |
| ((MediaPrintableArea[])values).length > 0) { | |
| mpaMax = ((MediaPrintableArea[])values)[0]; | |
| } | |
| } | |
| if (mpaMax == null) { | |
| mpaMax = new MediaPrintableArea(0f, 0f, | |
| mediaSize.getX(units), | |
| mediaSize.getY(units), | |
| units); | |
| } | |
| float wid = mediaSize.getX(units); | |
| float hgt = mediaSize.getY(units); | |
| float pax = lm; | |
| float pay = tm; | |
| float par = rm; | |
| float pab = bm; | |
| float paw = wid - lm - rm; | |
| float pah = hgt - tm - bm; | |
| if (paw <= 0f || pah <= 0f || pax < 0f || pay < 0f || | |
| par <= 0f || pab <= 0f || | |
| pax < mpaMax.getX(units) || paw > mpaMax.getWidth(units) || | |
| pay < mpaMax.getY(units) || pah > mpaMax.getHeight(units)) { | |
| return null; | |
| } else { | |
| return new MediaPrintableArea(lm, tm, paw, pah, units); | |
| } | |
| } | |
| /* This is complex as a MediaPrintableArea is valid only within | |
| * a particular context of media size. | |
| * So we need a MediaSize as well as a MediaPrintableArea. | |
| * MediaSize can be obtained from MediaSizeName. | |
| * If the application specifies a MediaPrintableArea, we accept it | |
| * to the extent its valid for the Media they specify. If they | |
| * don't specify a Media, then the default is assumed. | |
| * | |
| * If an application doesn't define a MediaPrintableArea, we need to | |
| * create a suitable one, this is created using the specified (or | |
| * default) Media and default 1 inch margins. This is validated | |
| * against the paper in case this is too large for tiny media. | |
| */ | |
| public void updateInfo() { | |
| if (isAWT) { | |
| leftMargin.setEnabled(false); | |
| rightMargin.setEnabled(false); | |
| topMargin.setEnabled(false); | |
| bottomMargin.setEnabled(false); | |
| lblLeft.setEnabled(false); | |
| lblRight.setEnabled(false); | |
| lblTop.setEnabled(false); | |
| lblBottom.setEnabled(false); | |
| return; | |
| } | |
| Class<MediaPrintableArea> mpaCategory = MediaPrintableArea.class; | |
| MediaPrintableArea mpa = | |
| (MediaPrintableArea)asCurrent.get(mpaCategory); | |
| MediaPrintableArea mpaMax = null; | |
| MediaSize mediaSize = null; | |
| Media media = (Media)asCurrent.get(Media.class); | |
| if (!(media instanceof MediaSizeName)) { | |
| media = (Media)psCurrent.getDefaultAttributeValue(Media.class); | |
| } | |
| if (media instanceof MediaSizeName msn) { | |
| mediaSize = MediaSize.getMediaSizeForName(msn); | |
| } | |
| if (mediaSize == null) { | |
| mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH); | |
| } | |
| if (media != null) { | |
| PrintRequestAttributeSet tmpASet = | |
| new HashPrintRequestAttributeSet(asCurrent); | |
| tmpASet.add(media); | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(mpaCategory, | |
| docFlavor, | |
| tmpASet); | |
| if (values instanceof MediaPrintableArea[] && | |
| ((MediaPrintableArea[])values).length > 0) { | |
| mpaMax = ((MediaPrintableArea[])values)[0]; | |
| } else if (values instanceof MediaPrintableArea) { | |
| mpaMax = (MediaPrintableArea)values; | |
| } | |
| } | |
| if (mpaMax == null) { | |
| mpaMax = new MediaPrintableArea(0f, 0f, | |
| mediaSize.getX(units), | |
| mediaSize.getY(units), | |
| units); | |
| } | |
| /* | |
| * At this point we now know as best we can :- | |
| * - the media size | |
| * - the maximum corresponding printable area | |
| * - the media printable area specified by the client, if any. | |
| * The next step is to create a default MPA if none was specified. | |
| * 1" margins are used unless they are disproportionately | |
| * large compared to the size of the media. | |
| */ | |
| float wid = mediaSize.getX(MediaPrintableArea.INCH); | |
| float hgt = mediaSize.getY(MediaPrintableArea.INCH); | |
| float maxMarginRatio = 5f; | |
| float xMgn, yMgn; | |
| if (wid > maxMarginRatio) { | |
| xMgn = 1f; | |
| } else { | |
| xMgn = wid / maxMarginRatio; | |
| } | |
| if (hgt > maxMarginRatio) { | |
| yMgn = 1f; | |
| } else { | |
| yMgn = hgt / maxMarginRatio; | |
| } | |
| if (mpa == null) { | |
| mpa = new MediaPrintableArea(xMgn, yMgn, | |
| wid-(2*xMgn), hgt-(2*yMgn), | |
| MediaPrintableArea.INCH); | |
| asCurrent.add(mpa); | |
| } | |
| float pax = mpa.getX(units); | |
| float pay = mpa.getY(units); | |
| float paw = mpa.getWidth(units); | |
| float pah = mpa.getHeight(units); | |
| float paxMax = mpaMax.getX(units); | |
| float payMax = mpaMax.getY(units); | |
| float pawMax = mpaMax.getWidth(units); | |
| float pahMax = mpaMax.getHeight(units); | |
| boolean invalid = false; | |
| // If the paper is set to something which is too small to | |
| // accommodate a specified printable area, perhaps carried | |
| // over from a larger paper, the adjustment that needs to be | |
| // performed should seem the most natural from a user's viewpoint. | |
| // Since the user is specifying margins, then we are biased | |
| // towards keeping the margins as close to what is specified as | |
| // possible, shrinking or growing the printable area. | |
| // But the API uses printable area, so you need to know the | |
| // media size in which the margins were previously interpreted, | |
| // or at least have a record of the margins. | |
| // In the case that this is the creation of this UI we do not | |
| // have this record, so we are somewhat reliant on the client | |
| // to supply a reasonable default | |
| wid = mediaSize.getX(units); | |
| hgt = mediaSize.getY(units); | |
| if (lmVal >= 0f) { | |
| invalid = true; | |
| if (lmVal + rmVal > wid) { | |
| // margins impossible, but maintain P.A if can | |
| if (paw > pawMax) { | |
| paw = pawMax; | |
| } | |
| // try to centre the printable area. | |
| pax = (wid - paw)/2f; | |
| } else { | |
| pax = (lmVal >= paxMax) ? lmVal : paxMax; | |
| paw = wid - pax - rmVal; | |
| } | |
| if (tmVal + bmVal > hgt) { | |
| if (pah > pahMax) { | |
| pah = pahMax; | |
| } | |
| pay = (hgt - pah)/2f; | |
| } else { | |
| pay = (tmVal >= payMax) ? tmVal : payMax; | |
| pah = hgt - pay - bmVal; | |
| } | |
| } | |
| if (pax < paxMax) { | |
| invalid = true; | |
| pax = paxMax; | |
| } | |
| if (pay < payMax) { | |
| invalid = true; | |
| pay = payMax; | |
| } | |
| if (paw > pawMax) { | |
| invalid = true; | |
| paw = pawMax; | |
| } | |
| if (pah > pahMax) { | |
| invalid = true; | |
| pah = pahMax; | |
| } | |
| if ((pax + paw > paxMax + pawMax) || (paw <= 0f)) { | |
| invalid = true; | |
| pax = paxMax; | |
| paw = pawMax; | |
| } | |
| if ((pay + pah > payMax + pahMax) || (pah <= 0f)) { | |
| invalid = true; | |
| pay = payMax; | |
| pah = pahMax; | |
| } | |
| if (invalid) { | |
| mpa = new MediaPrintableArea(pax, pay, paw, pah, units); | |
| asCurrent.add(mpa); | |
| } | |
| /* We now have a valid printable area. | |
| * Turn it into margins, using the mediaSize | |
| */ | |
| lmVal = pax; | |
| tmVal = pay; | |
| rmVal = mediaSize.getX(units) - pax - paw; | |
| bmVal = mediaSize.getY(units) - pay - pah; | |
| lmObj = lmVal; | |
| rmObj = rmVal; | |
| tmObj = tmVal; | |
| bmObj = bmVal; | |
| /* Now we know the values to use, we need to assign them | |
| * to the fields appropriate for the orientation. | |
| * Note: if orientation changes this method must be called. | |
| */ | |
| Class<OrientationRequested> orCategory = OrientationRequested.class; | |
| OrientationRequested or = | |
| (OrientationRequested)asCurrent.get(orCategory); | |
| if (or == null) { | |
| or = (OrientationRequested) | |
| psCurrent.getDefaultAttributeValue(orCategory); | |
| } | |
| Float tmp; | |
| if (or == OrientationRequested.REVERSE_PORTRAIT) { | |
| tmp = lmObj; lmObj = rmObj; rmObj = tmp; | |
| tmp = tmObj; tmObj = bmObj; bmObj = tmp; | |
| } else if (or == OrientationRequested.LANDSCAPE) { | |
| tmp = lmObj; | |
| lmObj = bmObj; | |
| bmObj = rmObj; | |
| rmObj = tmObj; | |
| tmObj = tmp; | |
| } else if (or == OrientationRequested.REVERSE_LANDSCAPE) { | |
| tmp = lmObj; | |
| lmObj = tmObj; | |
| tmObj = rmObj; | |
| rmObj = bmObj; | |
| bmObj = tmp; | |
| } | |
| leftMargin.setValue(lmObj); | |
| rightMargin.setValue(rmObj); | |
| topMargin.setValue(tmObj); | |
| bottomMargin.setValue(bmObj); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class MediaPanel extends JPanel implements ItemListener { | |
| private final String strTitle = getMsg("border.media"); | |
| private JLabel lblSize, lblSource; | |
| private JComboBox<Object> cbSize, cbSource; | |
| private Vector<MediaSizeName> sizes = new Vector<>(); | |
| private Vector<MediaTray> sources = new Vector<>(); | |
| private MarginsPanel pnlMargins = null; | |
| public MediaPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| cbSize = new JComboBox<>(); | |
| cbSource = new JComboBox<>(); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.weighty = 1.0; | |
| c.weightx = 0.0; | |
| lblSize = new JLabel(getMsg("label.size"), JLabel.TRAILING); | |
| lblSize.setDisplayedMnemonic(getMnemonic("label.size")); | |
| lblSize.setLabelFor(cbSize); | |
| addToGB(lblSize, this, gridbag, c); | |
| c.weightx = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(cbSize, this, gridbag, c); | |
| c.weightx = 0.0; | |
| c.gridwidth = 1; | |
| lblSource = new JLabel(getMsg("label.source"), JLabel.TRAILING); | |
| lblSource.setDisplayedMnemonic(getMnemonic("label.source")); | |
| lblSource.setLabelFor(cbSource); | |
| addToGB(lblSource, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(cbSource, this, gridbag, c); | |
| } | |
| private String getMediaName(String key) { | |
| try { | |
| // replace characters that would be invalid in | |
| // a resource key with valid characters | |
| String newkey = key.replace(' ', '-'); | |
| newkey = newkey.replace('#', 'n'); | |
| return messageRB.getString(newkey); | |
| } catch (java.util.MissingResourceException e) { | |
| return key; | |
| } | |
| } | |
| public void itemStateChanged(ItemEvent e) { | |
| Object source = e.getSource(); | |
| if (e.getStateChange() == ItemEvent.SELECTED) { | |
| if (source == cbSize) { | |
| int index = cbSize.getSelectedIndex(); | |
| if ((index >= 0) && (index < sizes.size())) { | |
| if ((cbSource.getItemCount() > 1) && | |
| (cbSource.getSelectedIndex() >= 1)) | |
| { | |
| int src = cbSource.getSelectedIndex() - 1; | |
| MediaTray mt = sources.get(src); | |
| asCurrent.add(new SunAlternateMedia(mt)); | |
| } | |
| asCurrent.add(sizes.get(index)); | |
| } | |
| } else if (source == cbSource) { | |
| int index = cbSource.getSelectedIndex(); | |
| if ((index >= 1) && (index < (sources.size() + 1))) { | |
| asCurrent.remove(SunAlternateMedia.class); | |
| MediaTray newTray = sources.get(index - 1); | |
| Media m = (Media)asCurrent.get(Media.class); | |
| if (m == null || m instanceof MediaTray) { | |
| asCurrent.add(newTray); | |
| } else if (m instanceof MediaSizeName) { | |
| MediaSizeName msn = (MediaSizeName)m; | |
| Media def = (Media)psCurrent.getDefaultAttributeValue(Media.class); | |
| if (def instanceof MediaSizeName && def.equals(msn)) { | |
| asCurrent.add(newTray); | |
| } else { | |
| /* Non-default paper size, so need to store tray | |
| * as SunAlternateMedia | |
| */ | |
| asCurrent.add(new SunAlternateMedia(newTray)); | |
| } | |
| } | |
| } else if (index == 0) { | |
| asCurrent.remove(SunAlternateMedia.class); | |
| if (cbSize.getItemCount() > 0) { | |
| int size = cbSize.getSelectedIndex(); | |
| asCurrent.add(sizes.get(size)); | |
| } | |
| } | |
| } | |
| // orientation affects display of margins. | |
| if (pnlMargins != null) { | |
| pnlMargins.updateInfo(); | |
| } | |
| } | |
| } | |
| /* this is ad hoc to keep things simple */ | |
| public void addMediaListener(MarginsPanel pnl) { | |
| pnlMargins = pnl; | |
| } | |
| public void updateInfo() { | |
| Class<Media> mdCategory = Media.class; | |
| Class<SunAlternateMedia> amCategory = SunAlternateMedia.class; | |
| boolean mediaSupported = false; | |
| cbSize.removeItemListener(this); | |
| cbSize.removeAllItems(); | |
| cbSource.removeItemListener(this); | |
| cbSource.removeAllItems(); | |
| cbSource.addItem(getMediaName("auto-select")); | |
| sizes.clear(); | |
| sources.clear(); | |
| if (psCurrent.isAttributeCategorySupported(mdCategory)) { | |
| mediaSupported = true; | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(mdCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof Media[]) { | |
| Media[] media = (Media[])values; | |
| for (int i = 0; i < media.length; i++) { | |
| Media medium = media[i]; | |
| if (medium instanceof MediaSizeName) { | |
| sizes.add((MediaSizeName)medium); | |
| cbSize.addItem(getMediaName(medium.toString())); | |
| } else if (medium instanceof MediaTray) { | |
| sources.add((MediaTray)medium); | |
| cbSource.addItem(getMediaName(medium.toString())); | |
| } | |
| } | |
| } | |
| } | |
| boolean msSupported = (mediaSupported && (sizes.size() > 0)); | |
| lblSize.setEnabled(msSupported); | |
| cbSize.setEnabled(msSupported); | |
| if (isAWT) { | |
| cbSource.setEnabled(false); | |
| lblSource.setEnabled(false); | |
| } else { | |
| cbSource.setEnabled(mediaSupported); | |
| } | |
| if (mediaSupported) { | |
| Media medium = (Media)asCurrent.get(mdCategory); | |
| // initialize size selection to default | |
| Media defMedia = (Media)psCurrent.getDefaultAttributeValue(mdCategory); | |
| if (defMedia instanceof MediaSizeName) { | |
| cbSize.setSelectedIndex(sizes.size() > 0 ? sizes.indexOf(defMedia) : -1); | |
| } | |
| if (medium == null || | |
| !psCurrent.isAttributeValueSupported(medium, | |
| docFlavor, asCurrent)) { | |
| medium = defMedia; | |
| if (medium == null) { | |
| if (sizes.size() > 0) { | |
| medium = (Media)sizes.get(0); | |
| } | |
| } | |
| if (medium != null) { | |
| asCurrent.add(medium); | |
| } | |
| } | |
| if (medium != null) { | |
| if (medium instanceof MediaSizeName) { | |
| MediaSizeName ms = (MediaSizeName)medium; | |
| cbSize.setSelectedIndex(sizes.indexOf(ms)); | |
| } else if (medium instanceof MediaTray) { | |
| MediaTray mt = (MediaTray)medium; | |
| cbSource.setSelectedIndex(sources.indexOf(mt) + 1); | |
| } | |
| } else { | |
| cbSize.setSelectedIndex(sizes.size() > 0 ? 0 : -1); | |
| cbSource.setSelectedIndex(0); | |
| } | |
| SunAlternateMedia alt = (SunAlternateMedia)asCurrent.get(amCategory); | |
| if (alt != null) { | |
| Media md = alt.getMedia(); | |
| if (md instanceof MediaTray) { | |
| MediaTray mt = (MediaTray)md; | |
| cbSource.setSelectedIndex(sources.indexOf(mt) + 1); | |
| } | |
| } | |
| int selIndex = cbSize.getSelectedIndex(); | |
| if ((selIndex >= 0) && (selIndex < sizes.size())) { | |
| asCurrent.add(sizes.get(selIndex)); | |
| } | |
| selIndex = cbSource.getSelectedIndex(); | |
| if ((selIndex >= 1) && (selIndex < (sources.size()+1))) { | |
| MediaTray mt = sources.get(selIndex-1); | |
| if (medium instanceof MediaTray) { | |
| asCurrent.add(mt); | |
| } else { | |
| asCurrent.add(new SunAlternateMedia(mt)); | |
| } | |
| } | |
| } | |
| cbSize.addItemListener(this); | |
| cbSource.addItemListener(this); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class OrientationPanel extends JPanel | |
| implements ActionListener | |
| { | |
| private final String strTitle = getMsg("border.orientation"); | |
| private IconRadioButton rbPortrait, rbLandscape, | |
| rbRevPortrait, rbRevLandscape; | |
| private MarginsPanel pnlMargins = null; | |
| public OrientationPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.weighty = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| ButtonGroup bg = new ButtonGroup(); | |
| rbPortrait = new IconRadioButton("radiobutton.portrait", | |
| "orientPortrait.png", true, | |
| bg, this); | |
| rbPortrait.addActionListener(this); | |
| addToGB(rbPortrait, this, gridbag, c); | |
| rbLandscape = new IconRadioButton("radiobutton.landscape", | |
| "orientLandscape.png", false, | |
| bg, this); | |
| rbLandscape.addActionListener(this); | |
| addToGB(rbLandscape, this, gridbag, c); | |
| rbRevPortrait = new IconRadioButton("radiobutton.revportrait", | |
| "orientRevPortrait.png", false, | |
| bg, this); | |
| rbRevPortrait.addActionListener(this); | |
| addToGB(rbRevPortrait, this, gridbag, c); | |
| rbRevLandscape = new IconRadioButton("radiobutton.revlandscape", | |
| "orientRevLandscape.png", false, | |
| bg, this); | |
| rbRevLandscape.addActionListener(this); | |
| addToGB(rbRevLandscape, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| if (rbPortrait.isSameAs(source)) { | |
| asCurrent.add(OrientationRequested.PORTRAIT); | |
| } else if (rbLandscape.isSameAs(source)) { | |
| asCurrent.add(OrientationRequested.LANDSCAPE); | |
| } else if (rbRevPortrait.isSameAs(source)) { | |
| asCurrent.add(OrientationRequested.REVERSE_PORTRAIT); | |
| } else if (rbRevLandscape.isSameAs(source)) { | |
| asCurrent.add(OrientationRequested.REVERSE_LANDSCAPE); | |
| } | |
| // orientation affects display of margins. | |
| if (pnlMargins != null) { | |
| pnlMargins.updateInfo(); | |
| } | |
| } | |
| /* This is ad hoc to keep things simple */ | |
| void addOrientationListener(MarginsPanel pnl) { | |
| pnlMargins = pnl; | |
| } | |
| public void updateInfo() { | |
| Class<OrientationRequested> orCategory = OrientationRequested.class; | |
| boolean pSupported = false; | |
| boolean lSupported = false; | |
| boolean rpSupported = false; | |
| boolean rlSupported = false; | |
| if (isAWT) { | |
| pSupported = true; | |
| lSupported = true; | |
| } else | |
| if (psCurrent.isAttributeCategorySupported(orCategory)) { | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(orCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof OrientationRequested[]) { | |
| OrientationRequested[] ovalues = | |
| (OrientationRequested[])values; | |
| for (int i = 0; i < ovalues.length; i++) { | |
| OrientationRequested value = ovalues[i]; | |
| if (value == OrientationRequested.PORTRAIT) { | |
| pSupported = true; | |
| } else if (value == OrientationRequested.LANDSCAPE) { | |
| lSupported = true; | |
| } else if (value == OrientationRequested.REVERSE_PORTRAIT) { | |
| rpSupported = true; | |
| } else if (value == OrientationRequested.REVERSE_LANDSCAPE) { | |
| rlSupported = true; | |
| } | |
| } | |
| } | |
| } | |
| rbPortrait.setEnabled(pSupported); | |
| rbLandscape.setEnabled(lSupported); | |
| rbRevPortrait.setEnabled(rpSupported); | |
| rbRevLandscape.setEnabled(rlSupported); | |
| OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory); | |
| if (or == null || | |
| !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { | |
| or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory); | |
| // need to validate if default is not supported | |
| if ((or != null) && | |
| !psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) { | |
| or = null; | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(orCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof OrientationRequested[]) { | |
| OrientationRequested[] orValues = | |
| (OrientationRequested[])values; | |
| if (orValues.length > 1) { | |
| // get the first in the list | |
| or = orValues[0]; | |
| } | |
| } | |
| } | |
| if (or == null) { | |
| or = OrientationRequested.PORTRAIT; | |
| } | |
| asCurrent.add(or); | |
| } | |
| if (or == OrientationRequested.PORTRAIT) { | |
| rbPortrait.setSelected(true); | |
| } else if (or == OrientationRequested.LANDSCAPE) { | |
| rbLandscape.setSelected(true); | |
| } else if (or == OrientationRequested.REVERSE_PORTRAIT) { | |
| rbRevPortrait.setSelected(true); | |
| } else { // if (or == OrientationRequested.REVERSE_LANDSCAPE) | |
| rbRevLandscape.setSelected(true); | |
| } | |
| } | |
| } | |
| /** | |
| * The "Appearance" tab. Includes the controls for Chromaticity, | |
| * PrintQuality, JobPriority, JobName, and other related job attributes. | |
| */ | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class AppearancePanel extends JPanel { | |
| private ChromaticityPanel pnlChromaticity; | |
| private QualityPanel pnlQuality; | |
| private JobAttributesPanel pnlJobAttributes; | |
| private SidesPanel pnlSides; | |
| private OutputPanel pnlOutput; | |
| public AppearancePanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = panelInsets; | |
| c.weightx = 1.0; | |
| c.weighty = 1.0; | |
| c.gridwidth = GridBagConstraints.RELATIVE; | |
| pnlChromaticity = new ChromaticityPanel(); | |
| addToGB(pnlChromaticity, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlQuality = new QualityPanel(); | |
| addToGB(pnlQuality, this, gridbag, c); | |
| c.gridwidth = 1; | |
| pnlSides = new SidesPanel(); | |
| addToGB(pnlSides, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlJobAttributes = new JobAttributesPanel(); | |
| addToGB(pnlJobAttributes, this, gridbag, c); | |
| if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlOutput = new OutputPanel(); | |
| addToGB(pnlOutput, this, gridbag, c); | |
| } | |
| } | |
| public void updateInfo() { | |
| pnlChromaticity.updateInfo(); | |
| pnlQuality.updateInfo(); | |
| pnlSides.updateInfo(); | |
| pnlJobAttributes.updateInfo(); | |
| if (pnlOutput != null) { | |
| pnlOutput.updateInfo(); | |
| } | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class ChromaticityPanel extends JPanel | |
| implements ActionListener | |
| { | |
| private final String strTitle = getMsg("border.chromaticity"); | |
| private JRadioButton rbMonochrome, rbColor; | |
| public ChromaticityPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| c.weighty = 1.0; | |
| ButtonGroup bg = new ButtonGroup(); | |
| rbMonochrome = createRadioButton("radiobutton.monochrome", this); | |
| rbMonochrome.setSelected(true); | |
| bg.add(rbMonochrome); | |
| addToGB(rbMonochrome, this, gridbag, c); | |
| rbColor = createRadioButton("radiobutton.color", this); | |
| bg.add(rbColor); | |
| addToGB(rbColor, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| // REMIND: use isSameAs if we move to a IconRB in the future | |
| if (source == rbMonochrome) { | |
| asCurrent.add(Chromaticity.MONOCHROME); | |
| } else if (source == rbColor) { | |
| asCurrent.add(Chromaticity.COLOR); | |
| } | |
| } | |
| public void updateInfo() { | |
| Class<Chromaticity> chCategory = Chromaticity.class; | |
| boolean monoSupported = false; | |
| boolean colorSupported = false; | |
| if (isAWT) { | |
| monoSupported = true; | |
| colorSupported = true; | |
| } else | |
| if (psCurrent.isAttributeCategorySupported(chCategory)) { | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(chCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof Chromaticity[]) { | |
| Chromaticity[] cvalues = (Chromaticity[])values; | |
| for (int i = 0; i < cvalues.length; i++) { | |
| Chromaticity value = cvalues[i]; | |
| if (value == Chromaticity.MONOCHROME) { | |
| monoSupported = true; | |
| } else if (value == Chromaticity.COLOR) { | |
| colorSupported = true; | |
| } | |
| } | |
| } | |
| } | |
| rbMonochrome.setEnabled(monoSupported); | |
| rbColor.setEnabled(colorSupported); | |
| Chromaticity ch = (Chromaticity)asCurrent.get(chCategory); | |
| if (ch == null) { | |
| ch = (Chromaticity)psCurrent.getDefaultAttributeValue(chCategory); | |
| if (ch == null) { | |
| ch = Chromaticity.MONOCHROME; | |
| } | |
| } | |
| if (ch == Chromaticity.MONOCHROME) { | |
| rbMonochrome.setSelected(true); | |
| } else { // if (ch == Chromaticity.COLOR) | |
| rbColor.setSelected(true); | |
| } | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class QualityPanel extends JPanel | |
| implements ActionListener | |
| { | |
| private final String strTitle = getMsg("border.quality"); | |
| private JRadioButton rbDraft, rbNormal, rbHigh; | |
| public QualityPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| c.weighty = 1.0; | |
| ButtonGroup bg = new ButtonGroup(); | |
| rbDraft = createRadioButton("radiobutton.draftq", this); | |
| bg.add(rbDraft); | |
| addToGB(rbDraft, this, gridbag, c); | |
| rbNormal = createRadioButton("radiobutton.normalq", this); | |
| rbNormal.setSelected(true); | |
| bg.add(rbNormal); | |
| addToGB(rbNormal, this, gridbag, c); | |
| rbHigh = createRadioButton("radiobutton.highq", this); | |
| bg.add(rbHigh); | |
| addToGB(rbHigh, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| if (source == rbDraft) { | |
| asCurrent.add(PrintQuality.DRAFT); | |
| } else if (source == rbNormal) { | |
| asCurrent.add(PrintQuality.NORMAL); | |
| } else if (source == rbHigh) { | |
| asCurrent.add(PrintQuality.HIGH); | |
| } | |
| } | |
| public void updateInfo() { | |
| Class<PrintQuality> pqCategory = PrintQuality.class; | |
| boolean draftSupported = false; | |
| boolean normalSupported = false; | |
| boolean highSupported = false; | |
| if (isAWT) { | |
| draftSupported = true; | |
| normalSupported = true; | |
| highSupported = true; | |
| } else | |
| if (psCurrent.isAttributeCategorySupported(pqCategory)) { | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(pqCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof PrintQuality[]) { | |
| PrintQuality[] qvalues = (PrintQuality[])values; | |
| for (int i = 0; i < qvalues.length; i++) { | |
| PrintQuality value = qvalues[i]; | |
| if (value == PrintQuality.DRAFT) { | |
| draftSupported = true; | |
| } else if (value == PrintQuality.NORMAL) { | |
| normalSupported = true; | |
| } else if (value == PrintQuality.HIGH) { | |
| highSupported = true; | |
| } | |
| } | |
| } | |
| } | |
| rbDraft.setEnabled(draftSupported); | |
| rbNormal.setEnabled(normalSupported); | |
| rbHigh.setEnabled(highSupported); | |
| PrintQuality pq = (PrintQuality)asCurrent.get(pqCategory); | |
| if (pq == null) { | |
| pq = (PrintQuality)psCurrent.getDefaultAttributeValue(pqCategory); | |
| if (pq == null) { | |
| pq = PrintQuality.NORMAL; | |
| } | |
| } | |
| if (pq == PrintQuality.DRAFT) { | |
| rbDraft.setSelected(true); | |
| } else if (pq == PrintQuality.NORMAL) { | |
| rbNormal.setSelected(true); | |
| } else { // if (pq == PrintQuality.HIGH) | |
| rbHigh.setSelected(true); | |
| } | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class SidesPanel extends JPanel | |
| implements ActionListener | |
| { | |
| private final String strTitle = getMsg("border.sides"); | |
| private IconRadioButton rbOneSide, rbTumble, rbDuplex; | |
| public SidesPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.weighty = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| ButtonGroup bg = new ButtonGroup(); | |
| rbOneSide = new IconRadioButton("radiobutton.oneside", | |
| "oneside.png", true, | |
| bg, this); | |
| rbOneSide.addActionListener(this); | |
| addToGB(rbOneSide, this, gridbag, c); | |
| rbTumble = new IconRadioButton("radiobutton.tumble", | |
| "tumble.png", false, | |
| bg, this); | |
| rbTumble.addActionListener(this); | |
| addToGB(rbTumble, this, gridbag, c); | |
| rbDuplex = new IconRadioButton("radiobutton.duplex", | |
| "duplex.png", false, | |
| bg, this); | |
| rbDuplex.addActionListener(this); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(rbDuplex, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| Object source = e.getSource(); | |
| if (rbOneSide.isSameAs(source)) { | |
| asCurrent.add(Sides.ONE_SIDED); | |
| } else if (rbTumble.isSameAs(source)) { | |
| asCurrent.add(Sides.TUMBLE); | |
| } else if (rbDuplex.isSameAs(source)) { | |
| asCurrent.add(Sides.DUPLEX); | |
| } | |
| } | |
| public void updateInfo() { | |
| Class<Sides> sdCategory = Sides.class; | |
| boolean osSupported = false; | |
| boolean tSupported = false; | |
| boolean dSupported = false; | |
| if (psCurrent.isAttributeCategorySupported(sdCategory)) { | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(sdCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof Sides[]) { | |
| Sides[] svalues = (Sides[])values; | |
| for (int i = 0; i < svalues.length; i++) { | |
| Sides value = svalues[i]; | |
| if (value == Sides.ONE_SIDED) { | |
| osSupported = true; | |
| } else if (value == Sides.TUMBLE) { | |
| tSupported = true; | |
| } else if (value == Sides.DUPLEX) { | |
| dSupported = true; | |
| } | |
| } | |
| } | |
| } | |
| rbOneSide.setEnabled(osSupported); | |
| rbTumble.setEnabled(tSupported); | |
| rbDuplex.setEnabled(dSupported); | |
| Sides sd = (Sides)asCurrent.get(sdCategory); | |
| if (sd == null) { | |
| sd = (Sides)psCurrent.getDefaultAttributeValue(sdCategory); | |
| if (sd == null) { | |
| sd = Sides.ONE_SIDED; | |
| } | |
| } | |
| if (sd == Sides.ONE_SIDED) { | |
| rbOneSide.setSelected(true); | |
| } else if (sd == Sides.TUMBLE) { | |
| rbTumble.setSelected(true); | |
| } else { // if (sd == Sides.DUPLEX) | |
| rbDuplex.setSelected(true); | |
| } | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class JobAttributesPanel extends JPanel | |
| implements ActionListener, ChangeListener, FocusListener | |
| { | |
| private final String strTitle = getMsg("border.jobattributes"); | |
| private JLabel lblPriority, lblJobName, lblUserName; | |
| private JSpinner spinPriority; | |
| private SpinnerNumberModel snModel; | |
| private JCheckBox cbJobSheets; | |
| private JTextField tfJobName, tfUserName; | |
| public JobAttributesPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| c.fill = GridBagConstraints.NONE; | |
| c.insets = compInsets; | |
| c.weighty = 1.0; | |
| cbJobSheets = createCheckBox("checkbox.jobsheets", this); | |
| c.anchor = GridBagConstraints.LINE_START; | |
| addToGB(cbJobSheets, this, gridbag, c); | |
| JPanel pnlTop = new JPanel(); | |
| lblPriority = new JLabel(getMsg("label.priority"), JLabel.TRAILING); | |
| lblPriority.setDisplayedMnemonic(getMnemonic("label.priority")); | |
| pnlTop.add(lblPriority); | |
| snModel = new SpinnerNumberModel(1, 1, 100, 1); | |
| spinPriority = new JSpinner(snModel); | |
| lblPriority.setLabelFor(spinPriority); | |
| // REMIND | |
| ((JSpinner.NumberEditor)spinPriority.getEditor()).getTextField().setColumns(3); | |
| spinPriority.addChangeListener(this); | |
| pnlTop.add(spinPriority); | |
| c.anchor = GridBagConstraints.LINE_END; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| pnlTop.getAccessibleContext().setAccessibleName( | |
| getMsg("label.priority")); | |
| addToGB(pnlTop, this, gridbag, c); | |
| c.fill = GridBagConstraints.HORIZONTAL; | |
| c.anchor = GridBagConstraints.CENTER; | |
| c.weightx = 0.0; | |
| c.gridwidth = 1; | |
| char jmnemonic = getMnemonic("label.jobname"); | |
| lblJobName = new JLabel(getMsg("label.jobname"), JLabel.TRAILING); | |
| lblJobName.setDisplayedMnemonic(jmnemonic); | |
| addToGB(lblJobName, this, gridbag, c); | |
| c.weightx = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| tfJobName = new JTextField(); | |
| lblJobName.setLabelFor(tfJobName); | |
| tfJobName.addFocusListener(this); | |
| tfJobName.setFocusAccelerator(jmnemonic); | |
| tfJobName.getAccessibleContext().setAccessibleName( | |
| getMsg("label.jobname")); | |
| addToGB(tfJobName, this, gridbag, c); | |
| c.weightx = 0.0; | |
| c.gridwidth = 1; | |
| char umnemonic = getMnemonic("label.username"); | |
| lblUserName = new JLabel(getMsg("label.username"), JLabel.TRAILING); | |
| lblUserName.setDisplayedMnemonic(umnemonic); | |
| addToGB(lblUserName, this, gridbag, c); | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| tfUserName = new JTextField(); | |
| lblUserName.setLabelFor(tfUserName); | |
| tfUserName.addFocusListener(this); | |
| tfUserName.setFocusAccelerator(umnemonic); | |
| tfUserName.getAccessibleContext().setAccessibleName( | |
| getMsg("label.username")); | |
| addToGB(tfUserName, this, gridbag, c); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| if (cbJobSheets.isSelected()) { | |
| asCurrent.add(JobSheets.STANDARD); | |
| } else { | |
| asCurrent.add(JobSheets.NONE); | |
| } | |
| } | |
| public void stateChanged(ChangeEvent e) { | |
| asCurrent.add(new JobPriority(snModel.getNumber().intValue())); | |
| } | |
| public void focusLost(FocusEvent e) { | |
| Object source = e.getSource(); | |
| if (source == tfJobName) { | |
| asCurrent.add(new JobName(tfJobName.getText(), | |
| Locale.getDefault())); | |
| } else if (source == tfUserName) { | |
| asCurrent.add(new RequestingUserName(tfUserName.getText(), | |
| Locale.getDefault())); | |
| } | |
| } | |
| public void focusGained(FocusEvent e) {} | |
| public void updateInfo() { | |
| Class<JobSheets> jsCategory = JobSheets.class; | |
| Class<JobPriority> jpCategory = JobPriority.class; | |
| Class<JobName> jnCategory = JobName.class; | |
| Class<RequestingUserName> unCategory = RequestingUserName.class; | |
| boolean jsSupported = false; | |
| boolean jpSupported = false; | |
| boolean jnSupported = false; | |
| boolean unSupported = false; | |
| // setup JobSheets checkbox | |
| if (psCurrent.isAttributeCategorySupported(jsCategory)) { | |
| jsSupported = true; | |
| } | |
| JobSheets js = (JobSheets)asCurrent.get(jsCategory); | |
| if (js == null) { | |
| js = (JobSheets)psCurrent.getDefaultAttributeValue(jsCategory); | |
| if (js == null) { | |
| js = JobSheets.STANDARD; | |
| } | |
| } | |
| cbJobSheets.setSelected(js != JobSheets.NONE && jsSupported); | |
| cbJobSheets.setEnabled(jsSupported); | |
| // setup JobPriority spinner | |
| if (!isAWT && psCurrent.isAttributeCategorySupported(jpCategory)) { | |
| jpSupported = true; | |
| } | |
| JobPriority jp = (JobPriority)asCurrent.get(jpCategory); | |
| if (jp == null) { | |
| jp = (JobPriority)psCurrent.getDefaultAttributeValue(jpCategory); | |
| if (jp == null) { | |
| jp = new JobPriority(1); | |
| } | |
| } | |
| int value = jp.getValue(); | |
| if ((value < 1) || (value > 100)) { | |
| value = 1; | |
| } | |
| snModel.setValue(value); | |
| lblPriority.setEnabled(jpSupported); | |
| spinPriority.setEnabled(jpSupported); | |
| // setup JobName text field | |
| if (psCurrent.isAttributeCategorySupported(jnCategory)) { | |
| jnSupported = true; | |
| } | |
| JobName jn = (JobName)asCurrent.get(jnCategory); | |
| if (jn == null) { | |
| jn = (JobName)psCurrent.getDefaultAttributeValue(jnCategory); | |
| if (jn == null) { | |
| jn = new JobName("", Locale.getDefault()); | |
| } | |
| } | |
| tfJobName.setText(jn.getValue()); | |
| tfJobName.setEnabled(jnSupported); | |
| lblJobName.setEnabled(jnSupported); | |
| // setup RequestingUserName text field | |
| if (!isAWT && psCurrent.isAttributeCategorySupported(unCategory)) { | |
| unSupported = true; | |
| } | |
| RequestingUserName un = (RequestingUserName)asCurrent.get(unCategory); | |
| if (un == null) { | |
| un = (RequestingUserName)psCurrent.getDefaultAttributeValue(unCategory); | |
| if (un == null) { | |
| un = new RequestingUserName("", Locale.getDefault()); | |
| } | |
| } | |
| tfUserName.setText(un.getValue()); | |
| tfUserName.setEnabled(unSupported); | |
| lblUserName.setEnabled(unSupported); | |
| } | |
| } | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private class OutputPanel extends JPanel implements ItemListener { | |
| private final String strTitle = getMsg("border.output"); | |
| private JLabel lblOutput; | |
| private JComboBox<Object> cbOutput; | |
| private Vector<OutputBin> outputs = new Vector<>(); | |
| public OutputPanel() { | |
| super(); | |
| GridBagLayout gridbag = new GridBagLayout(); | |
| GridBagConstraints c = new GridBagConstraints(); | |
| setLayout(gridbag); | |
| setBorder(BorderFactory.createTitledBorder(strTitle)); | |
| cbOutput = new JComboBox<>(); | |
| c.fill = GridBagConstraints.BOTH; | |
| c.insets = compInsets; | |
| c.weighty = 1.0; | |
| c.weightx = 0.0; | |
| lblOutput = new JLabel(getMsg("label.outputbins"), JLabel.TRAILING); | |
| lblOutput.setDisplayedMnemonic(getMnemonic("label.outputbins")); | |
| lblOutput.setLabelFor(cbOutput); | |
| addToGB(lblOutput, this, gridbag, c); | |
| c.weightx = 1.0; | |
| c.gridwidth = GridBagConstraints.REMAINDER; | |
| addToGB(cbOutput, this, gridbag, c); | |
| } | |
| public void itemStateChanged(ItemEvent e) { | |
| Object source = e.getSource(); | |
| if (e.getStateChange() == ItemEvent.SELECTED) { | |
| if (source == cbOutput) { | |
| int index = cbOutput.getSelectedIndex(); | |
| if ((index >= 0) && (index < outputs.size())) { | |
| asCurrent.add(outputs.get(index)); | |
| } else if (index == cbOutput.getItemCount() - 1) { | |
| asCurrent.remove(OutputBin.class); | |
| } | |
| } | |
| } | |
| } | |
| public void updateInfo() { | |
| Class<OutputBin> obCategory = OutputBin.class; | |
| cbOutput.removeItemListener(this); | |
| cbOutput.removeAllItems(); | |
| outputs.clear(); | |
| boolean outputEnabled = false; | |
| if (psCurrent.isAttributeCategorySupported(obCategory)) { | |
| Object values = | |
| psCurrent.getSupportedAttributeValues(obCategory, | |
| docFlavor, | |
| asCurrent); | |
| if (values instanceof OutputBin[]) { | |
| OutputBin[] outputBins = (OutputBin[])values; | |
| for (OutputBin outputBin: outputBins) { | |
| outputs.add(outputBin); | |
| cbOutput.addItem(outputBin.toString()); | |
| } | |
| cbOutput.addItem(""); | |
| cbOutput.setSelectedIndex(cbOutput.getItemCount() - 1); | |
| OutputBin current = (OutputBin) asCurrent.get(obCategory); | |
| if (current != null) { | |
| for (int i = 0; i < outputs.size(); i++) { | |
| if (current.equals(outputs.get(i))) { | |
| cbOutput.setSelectedIndex(i); | |
| break; | |
| } | |
| } | |
| } else if (outputBins.length == 1) { | |
| cbOutput.setSelectedIndex(0); | |
| } | |
| outputEnabled = outputBins.length > 1; | |
| } | |
| } | |
| cbOutput.setEnabled(outputEnabled); | |
| lblOutput.setEnabled(outputEnabled); | |
| if (outputEnabled) { | |
| cbOutput.addItemListener(this); | |
| } | |
| } | |
| } | |
| /** | |
| * A special widget that groups a JRadioButton with an associated icon, | |
| * placed to the left of the radio button. | |
| */ | |
| @SuppressWarnings("serial") // Superclass is not serializable across versions | |
| private static class IconRadioButton extends JPanel { | |
| private JRadioButton rb; | |
| private JLabel lbl; | |
| public IconRadioButton(String key, String img, boolean selected, | |
| ButtonGroup bg, ActionListener al) | |
| { | |
| super(new FlowLayout(FlowLayout.LEADING)); | |
| final URL imgURL = getImageResource(img); | |
| Icon icon = new ImageIcon(imgURL); | |
| lbl = new JLabel(icon); | |
| add(lbl); | |
| rb = createRadioButton(key, al); | |
| rb.setSelected(selected); | |
| addToBG(rb, this, bg); | |
| } | |
| public void addActionListener(ActionListener al) { | |
| rb.addActionListener(al); | |
| } | |
| public boolean isSameAs(Object source) { | |
| return (rb == source); | |
| } | |
| public void setEnabled(boolean enabled) { | |
| rb.setEnabled(enabled); | |
| lbl.setEnabled(enabled); | |
| } | |
| public boolean isSelected() { | |
| return rb.isSelected(); | |
| } | |
| public void setSelected(boolean selected) { | |
| rb.setSelected(selected); | |
| } | |
| } | |
| /** | |
| * Similar in functionality to the default JFileChooser, except this | |
| * chooser will pop up a "Do you want to overwrite..." dialog if the | |
| * user selects a file that already exists. | |
| */ | |
| @SuppressWarnings("serial") // JDK implementation class | |
| private static class ValidatingFileChooser extends JFileChooser { | |
| public void approveSelection() { | |
| File selected = getSelectedFile(); | |
| boolean exists = selected.exists(); | |
| if (exists) { | |
| int val; | |
| val = JOptionPane.showConfirmDialog(this, | |
| getMsg("dialog.overwrite"), | |
| getMsg("dialog.owtitle"), | |
| JOptionPane.YES_NO_OPTION); | |
| if (val != JOptionPane.YES_OPTION) { | |
| return; | |
| } | |
| } | |
| try { | |
| if (selected.createNewFile()) { | |
| selected.delete(); | |
| } | |
| } catch (IOException ioe) { | |
| JOptionPane.showMessageDialog(this, | |
| getMsg("dialog.writeerror")+" "+selected, | |
| getMsg("dialog.owtitle"), | |
| JOptionPane.WARNING_MESSAGE); | |
| return; | |
| } | |
| File pFile = selected.getParentFile(); | |
| if ((selected.exists() && | |
| (!selected.isFile() || !selected.canWrite())) || | |
| ((pFile != null) && | |
| (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { | |
| JOptionPane.showMessageDialog(this, | |
| getMsg("dialog.writeerror")+" "+selected, | |
| getMsg("dialog.owtitle"), | |
| JOptionPane.WARNING_MESSAGE); | |
| return; | |
| } | |
| super.approveSelection(); | |
| } | |
| } | |
| } |