Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/print/ServiceDialog.java
38829 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.print;2627import java.awt.BorderLayout;28import java.awt.Color;29import java.awt.Component;30import java.awt.Container;31import java.awt.Dialog;32import java.awt.FlowLayout;33import java.awt.Frame;34import java.awt.GraphicsConfiguration;35import java.awt.GridBagLayout;36import java.awt.GridBagConstraints;37import java.awt.GridLayout;38import java.awt.Insets;39import java.awt.Toolkit;40import java.awt.event.ActionEvent;41import java.awt.event.ActionListener;42import java.awt.event.FocusEvent;43import java.awt.event.FocusListener;44import java.awt.event.ItemEvent;45import java.awt.event.ItemListener;46import java.awt.event.WindowEvent;47import java.awt.event.WindowAdapter;48import java.awt.print.PrinterJob;49import java.io.File;50import java.io.FilePermission;51import java.io.IOException;52import java.net.URI;53import java.net.URL;54import java.text.DecimalFormat;55import java.util.Locale;56import java.util.ResourceBundle;57import java.util.Vector;58import javax.print.*;59import javax.print.attribute.*;60import javax.print.attribute.standard.*;61import javax.swing.*;62import javax.swing.border.Border;63import javax.swing.border.EmptyBorder;64import javax.swing.border.TitledBorder;65import javax.swing.event.ChangeEvent;66import javax.swing.event.ChangeListener;67import javax.swing.event.DocumentEvent;68import javax.swing.event.DocumentListener;69import javax.swing.event.PopupMenuEvent;70import javax.swing.event.PopupMenuListener;71import javax.swing.text.NumberFormatter;72import sun.print.SunPageSelection;73import java.awt.event.KeyEvent;74import java.net.URISyntaxException;75import java.lang.reflect.Field;767778/**79* A class which implements a cross-platform print dialog.80*81* @author Chris Campbell82*/83public class ServiceDialog extends JDialog implements ActionListener {8485/**86* Waiting print status (user response pending).87*/88public final static int WAITING = 0;8990/**91* Approve print status (user activated "Print" or "OK").92*/93public final static int APPROVE = 1;9495/**96* Cancel print status (user activated "Cancel");97*/98public final static int CANCEL = 2;99100private static final String strBundle = "sun.print.resources.serviceui";101private static final Insets panelInsets = new Insets(6, 6, 6, 6);102private static final Insets compInsets = new Insets(3, 6, 3, 6);103104private static ResourceBundle messageRB;105private JTabbedPane tpTabs;106private JButton btnCancel, btnApprove;107private PrintService[] services;108private int defaultServiceIndex;109private PrintRequestAttributeSet asOriginal;110private HashPrintRequestAttributeSet asCurrent;111private PrintService psCurrent;112private DocFlavor docFlavor;113private int status;114115private ValidatingFileChooser jfc;116117private GeneralPanel pnlGeneral;118private PageSetupPanel pnlPageSetup;119private AppearancePanel pnlAppearance;120121private boolean isAWT = false;122static {123initResource();124}125126127/**128* Constructor for the "standard" print dialog (containing all relevant129* tabs)130*/131public ServiceDialog(GraphicsConfiguration gc,132int x, int y,133PrintService[] services,134int defaultServiceIndex,135DocFlavor flavor,136PrintRequestAttributeSet attributes,137Dialog dialog)138{139super(dialog, getMsg("dialog.printtitle"), true, gc);140initPrintDialog(x, y, services, defaultServiceIndex,141flavor, attributes);142}143144145146/**147* Constructor for the "standard" print dialog (containing all relevant148* tabs)149*/150public ServiceDialog(GraphicsConfiguration gc,151int x, int y,152PrintService[] services,153int defaultServiceIndex,154DocFlavor flavor,155PrintRequestAttributeSet attributes,156Frame frame)157{158super(frame, getMsg("dialog.printtitle"), true, gc);159initPrintDialog(x, y, services, defaultServiceIndex,160flavor, attributes);161}162163164/**165* Initialize print dialog.166*/167void initPrintDialog(int x, int y,168PrintService[] services,169int defaultServiceIndex,170DocFlavor flavor,171PrintRequestAttributeSet attributes)172{173this.services = services;174this.defaultServiceIndex = defaultServiceIndex;175this.asOriginal = attributes;176this.asCurrent = new HashPrintRequestAttributeSet(attributes);177this.psCurrent = services[defaultServiceIndex];178this.docFlavor = flavor;179SunPageSelection pages =180(SunPageSelection)attributes.get(SunPageSelection.class);181if (pages != null) {182isAWT = true;183}184185if (attributes.get(DialogOnTop.class) != null) {186setAlwaysOnTop(true);187}188Container c = getContentPane();189c.setLayout(new BorderLayout());190191tpTabs = new JTabbedPane();192tpTabs.setBorder(new EmptyBorder(5, 5, 5, 5));193194String gkey = getMsg("tab.general");195int gmnemonic = getVKMnemonic("tab.general");196pnlGeneral = new GeneralPanel();197tpTabs.add(gkey, pnlGeneral);198tpTabs.setMnemonicAt(0, gmnemonic);199200String pkey = getMsg("tab.pagesetup");201int pmnemonic = getVKMnemonic("tab.pagesetup");202pnlPageSetup = new PageSetupPanel();203tpTabs.add(pkey, pnlPageSetup);204tpTabs.setMnemonicAt(1, pmnemonic);205206String akey = getMsg("tab.appearance");207int amnemonic = getVKMnemonic("tab.appearance");208pnlAppearance = new AppearancePanel();209tpTabs.add(akey, pnlAppearance);210tpTabs.setMnemonicAt(2, amnemonic);211212c.add(tpTabs, BorderLayout.CENTER);213214updatePanels();215216JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING));217btnApprove = createExitButton("button.print", this);218pnlSouth.add(btnApprove);219getRootPane().setDefaultButton(btnApprove);220btnCancel = createExitButton("button.cancel", this);221handleEscKey(btnCancel);222pnlSouth.add(btnCancel);223c.add(pnlSouth, BorderLayout.SOUTH);224225addWindowListener(new WindowAdapter() {226public void windowClosing(WindowEvent event) {227dispose(CANCEL);228}229});230231getAccessibleContext().setAccessibleDescription(getMsg("dialog.printtitle"));232setResizable(false);233setLocation(x, y);234pack();235}236237/**238* Constructor for the solitary "page setup" dialog239*/240public ServiceDialog(GraphicsConfiguration gc,241int x, int y,242PrintService ps,243DocFlavor flavor,244PrintRequestAttributeSet attributes,245Dialog dialog)246{247super(dialog, getMsg("dialog.pstitle"), true, gc);248initPageDialog(x, y, ps, flavor, attributes);249}250251/**252* Constructor for the solitary "page setup" dialog253*/254public ServiceDialog(GraphicsConfiguration gc,255int x, int y,256PrintService ps,257DocFlavor flavor,258PrintRequestAttributeSet attributes,259Frame frame)260{261super(frame, getMsg("dialog.pstitle"), true, gc);262initPageDialog(x, y, ps, flavor, attributes);263}264265266/**267* Initialize "page setup" dialog268*/269void initPageDialog(int x, int y,270PrintService ps,271DocFlavor flavor,272PrintRequestAttributeSet attributes)273{274this.psCurrent = ps;275this.docFlavor = flavor;276this.asOriginal = attributes;277this.asCurrent = new HashPrintRequestAttributeSet(attributes);278279if (attributes.get(DialogOnTop.class) != null) {280setAlwaysOnTop(true);281}282283Container c = getContentPane();284c.setLayout(new BorderLayout());285286pnlPageSetup = new PageSetupPanel();287c.add(pnlPageSetup, BorderLayout.CENTER);288289pnlPageSetup.updateInfo();290291JPanel pnlSouth = new JPanel(new FlowLayout(FlowLayout.TRAILING));292btnApprove = createExitButton("button.ok", this);293pnlSouth.add(btnApprove);294getRootPane().setDefaultButton(btnApprove);295btnCancel = createExitButton("button.cancel", this);296handleEscKey(btnCancel);297pnlSouth.add(btnCancel);298c.add(pnlSouth, BorderLayout.SOUTH);299300addWindowListener(new WindowAdapter() {301public void windowClosing(WindowEvent event) {302dispose(CANCEL);303}304});305306getAccessibleContext().setAccessibleDescription(getMsg("dialog.pstitle"));307setResizable(false);308setLocation(x, y);309pack();310}311312/**313* Performs Cancel when Esc key is pressed.314*/315private void handleEscKey(JButton btnCancel) {316Action cancelKeyAction = new AbstractAction() {317public void actionPerformed(ActionEvent e) {318dispose(CANCEL);319}320};321KeyStroke cancelKeyStroke =322KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE, 0);323InputMap inputMap =324btnCancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);325ActionMap actionMap = btnCancel.getActionMap();326327if (inputMap != null && actionMap != null) {328inputMap.put(cancelKeyStroke, "cancel");329actionMap.put("cancel", cancelKeyAction);330}331}332333334/**335* Returns the current status of the dialog (whether the user has selected336* the "Print" or "Cancel" button)337*/338public int getStatus() {339return status;340}341342/**343* Returns an AttributeSet based on whether or not the user cancelled the344* dialog. If the user selected "Print" we return their new selections,345* otherwise we return the attributes that were passed in initially.346*/347public PrintRequestAttributeSet getAttributes() {348if (status == APPROVE) {349return asCurrent;350} else {351return asOriginal;352}353}354355/**356* Returns a PrintService based on whether or not the user cancelled the357* dialog. If the user selected "Print" we return the user's selection358* for the PrintService, otherwise we return null.359*/360public PrintService getPrintService() {361if (status == APPROVE) {362return psCurrent;363} else {364return null;365}366}367368/**369* Sets the current status flag for the dialog and disposes it (thus370* returning control of the parent frame back to the user)371*/372public void dispose(int status) {373this.status = status;374375super.dispose();376}377378public void actionPerformed(ActionEvent e) {379Object source = e.getSource();380boolean approved = false;381382if (source == btnApprove) {383approved = true;384385if (pnlGeneral != null) {386if (pnlGeneral.isPrintToFileRequested()) {387approved = showFileChooser();388} else {389asCurrent.remove(Destination.class);390}391}392}393394dispose(approved ? APPROVE : CANCEL);395}396397/**398* Displays a JFileChooser that allows the user to select the destination399* for "Print To File"400*/401private boolean showFileChooser() {402Class dstCategory = Destination.class;403404Destination dst = (Destination)asCurrent.get(dstCategory);405if (dst == null) {406dst = (Destination)asOriginal.get(dstCategory);407if (dst == null) {408dst = (Destination)psCurrent.getDefaultAttributeValue(dstCategory);409// "dst" should not be null. The following code410// is only added to safeguard against a possible411// buggy implementation of a PrintService having a412// null default Destination.413if (dst == null) {414try {415dst = new Destination(new URI("file:out.prn"));416} catch (URISyntaxException e) {417}418}419}420}421422File fileDest;423if (dst != null) {424try {425fileDest = new File(dst.getURI());426} catch (Exception e) {427// all manner of runtime exceptions possible428fileDest = new File("out.prn");429}430} else {431fileDest = new File("out.prn");432}433434ValidatingFileChooser jfc = new ValidatingFileChooser();435jfc.setApproveButtonText(getMsg("button.ok"));436jfc.setDialogTitle(getMsg("dialog.printtofile"));437jfc.setDialogType(JFileChooser.SAVE_DIALOG);438jfc.setSelectedFile(fileDest);439440int returnVal = jfc.showDialog(this, null);441if (returnVal == JFileChooser.APPROVE_OPTION) {442fileDest = jfc.getSelectedFile();443444try {445asCurrent.add(new Destination(fileDest.toURI()));446} catch (Exception e) {447asCurrent.remove(dstCategory);448}449} else {450asCurrent.remove(dstCategory);451}452453return (returnVal == JFileChooser.APPROVE_OPTION);454}455456/**457* Updates each of the top level panels458*/459private void updatePanels() {460pnlGeneral.updateInfo();461pnlPageSetup.updateInfo();462pnlAppearance.updateInfo();463}464465/**466* Initialize ResourceBundle467*/468public static void initResource() {469java.security.AccessController.doPrivileged(470new java.security.PrivilegedAction() {471public Object run() {472try {473messageRB = ResourceBundle.getBundle(strBundle);474return null;475} catch (java.util.MissingResourceException e) {476throw new Error("Fatal: Resource for ServiceUI " +477"is missing");478}479}480}481);482}483484/**485* Returns message string from resource486*/487public static String getMsg(String key) {488try {489return removeMnemonics(messageRB.getString(key));490} catch (java.util.MissingResourceException e) {491throw new Error("Fatal: Resource for ServiceUI is broken; " +492"there is no " + key + " key in resource");493}494}495496private static String removeMnemonics(String s) {497int i = s.indexOf('&');498int len = s.length();499if (i < 0 || i == (len - 1)) {500return s;501}502int j = s.indexOf('&', i+1);503if (j == i+1) {504if (j+1 == len) {505return s.substring(0, i+1); // string ends with &&506} else {507return s.substring(0, i+1) + removeMnemonics(s.substring(j+1));508}509}510// ok first & not double &&511if (i == 0) {512return removeMnemonics(s.substring(1));513} else {514return (s.substring(0, i) + removeMnemonics(s.substring(i+1)));515}516}517518519/**520* Returns mnemonic character from resource521*/522private static char getMnemonic(String key) {523String str = messageRB.getString(key).replace("&&", "");524int index = str.indexOf('&');525if (0 <= index && index < str.length() - 1) {526char c = str.charAt(index + 1);527return Character.toUpperCase(c);528} else {529return (char)0;530}531}532533/**534* Returns the mnemonic as a KeyEvent.VK constant from the resource.535*/536static Class _keyEventClazz = null;537private static int getVKMnemonic(String key) {538String s = String.valueOf(getMnemonic(key));539if ( s == null || s.length() != 1) {540return 0;541}542String vkString = "VK_" + s.toUpperCase();543544try {545if (_keyEventClazz == null) {546_keyEventClazz= Class.forName("java.awt.event.KeyEvent",547true, (ServiceDialog.class).getClassLoader());548}549Field field = _keyEventClazz.getDeclaredField(vkString);550int value = field.getInt(null);551return value;552} catch (Exception e) {553}554return 0;555}556557/**558* Returns URL for image resource559*/560private static URL getImageResource(final String key) {561URL url = (URL)java.security.AccessController.doPrivileged(562new java.security.PrivilegedAction() {563public Object run() {564URL url = ServiceDialog.class.getResource(565"resources/" + key);566return url;567}568});569570if (url == null) {571throw new Error("Fatal: Resource for ServiceUI is broken; " +572"there is no " + key + " key in resource");573}574575return url;576}577578/**579* Creates a new JButton and sets its text, mnemonic, and ActionListener580*/581private static JButton createButton(String key, ActionListener al) {582JButton btn = new JButton(getMsg(key));583btn.setMnemonic(getMnemonic(key));584btn.addActionListener(al);585586return btn;587}588589/**590* Creates a new JButton and sets its text, and ActionListener591*/592private static JButton createExitButton(String key, ActionListener al) {593String str = getMsg(key);594JButton btn = new JButton(str);595btn.addActionListener(al);596btn.getAccessibleContext().setAccessibleDescription(str);597return btn;598}599600/**601* Creates a new JCheckBox and sets its text, mnemonic, and ActionListener602*/603private static JCheckBox createCheckBox(String key, ActionListener al) {604JCheckBox cb = new JCheckBox(getMsg(key));605cb.setMnemonic(getMnemonic(key));606cb.addActionListener(al);607608return cb;609}610611/**612* Creates a new JRadioButton and sets its text, mnemonic,613* and ActionListener614*/615private static JRadioButton createRadioButton(String key,616ActionListener al)617{618JRadioButton rb = new JRadioButton(getMsg(key));619rb.setMnemonic(getMnemonic(key));620rb.addActionListener(al);621622return rb;623}624625/**626* Creates a pop-up dialog for "no print service"627*/628public static void showNoPrintService(GraphicsConfiguration gc)629{630Frame dlgFrame = new Frame(gc);631JOptionPane.showMessageDialog(dlgFrame,632getMsg("dialog.noprintermsg"));633dlgFrame.dispose();634}635636/**637* Sets the constraints for the GridBagLayout and adds the Component638* to the given Container639*/640private static void addToGB(Component comp, Container cont,641GridBagLayout gridbag,642GridBagConstraints constraints)643{644gridbag.setConstraints(comp, constraints);645cont.add(comp);646}647648/**649* Adds the AbstractButton to both the given ButtonGroup and Container650*/651private static void addToBG(AbstractButton button, Container cont,652ButtonGroup bg)653{654bg.add(button);655cont.add(button);656}657658659660661/**662* The "General" tab. Includes the controls for PrintService,663* PageRange, and Copies/Collate.664*/665private class GeneralPanel extends JPanel {666667private PrintServicePanel pnlPrintService;668private PrintRangePanel pnlPrintRange;669private CopiesPanel pnlCopies;670671public GeneralPanel() {672super();673674GridBagLayout gridbag = new GridBagLayout();675GridBagConstraints c = new GridBagConstraints();676677setLayout(gridbag);678679c.fill = GridBagConstraints.BOTH;680c.insets = panelInsets;681c.weightx = 1.0;682c.weighty = 1.0;683684c.gridwidth = GridBagConstraints.REMAINDER;685pnlPrintService = new PrintServicePanel();686addToGB(pnlPrintService, this, gridbag, c);687688c.gridwidth = GridBagConstraints.RELATIVE;689pnlPrintRange = new PrintRangePanel();690addToGB(pnlPrintRange, this, gridbag, c);691692c.gridwidth = GridBagConstraints.REMAINDER;693pnlCopies = new CopiesPanel();694addToGB(pnlCopies, this, gridbag, c);695}696697public boolean isPrintToFileRequested() {698return (pnlPrintService.isPrintToFileSelected());699}700701public void updateInfo() {702pnlPrintService.updateInfo();703pnlPrintRange.updateInfo();704pnlCopies.updateInfo();705}706}707708private class PrintServicePanel extends JPanel709implements ActionListener, ItemListener, PopupMenuListener710{711private final String strTitle = getMsg("border.printservice");712private FilePermission printToFilePermission;713private JButton btnProperties;714private JCheckBox cbPrintToFile;715private JComboBox cbName;716private JLabel lblType, lblStatus, lblInfo;717private ServiceUIFactory uiFactory;718private boolean changedService = false;719private boolean filePermission;720721public PrintServicePanel() {722super();723724uiFactory = psCurrent.getServiceUIFactory();725726GridBagLayout gridbag = new GridBagLayout();727GridBagConstraints c = new GridBagConstraints();728729setLayout(gridbag);730setBorder(BorderFactory.createTitledBorder(strTitle));731732String[] psnames = new String[services.length];733for (int i = 0; i < psnames.length; i++) {734psnames[i] = services[i].getName();735}736cbName = new JComboBox(psnames);737cbName.setSelectedIndex(defaultServiceIndex);738cbName.addItemListener(this);739cbName.addPopupMenuListener(this);740741c.fill = GridBagConstraints.BOTH;742c.insets = compInsets;743744c.weightx = 0.0;745JLabel lblName = new JLabel(getMsg("label.psname"), JLabel.TRAILING);746lblName.setDisplayedMnemonic(getMnemonic("label.psname"));747lblName.setLabelFor(cbName);748addToGB(lblName, this, gridbag, c);749c.weightx = 1.0;750c.gridwidth = GridBagConstraints.RELATIVE;751addToGB(cbName, this, gridbag, c);752c.weightx = 0.0;753c.gridwidth = GridBagConstraints.REMAINDER;754btnProperties = createButton("button.properties", this);755addToGB(btnProperties, this, gridbag, c);756757c.weighty = 1.0;758lblStatus = addLabel(getMsg("label.status"), gridbag, c);759lblStatus.setLabelFor(null);760761lblType = addLabel(getMsg("label.pstype"), gridbag, c);762lblType.setLabelFor(null);763764c.gridwidth = 1;765addToGB(new JLabel(getMsg("label.info"), JLabel.TRAILING),766this, gridbag, c);767c.gridwidth = GridBagConstraints.RELATIVE;768lblInfo = new JLabel();769lblInfo.setLabelFor(null);770771addToGB(lblInfo, this, gridbag, c);772773c.gridwidth = GridBagConstraints.REMAINDER;774cbPrintToFile = createCheckBox("checkbox.printtofile", this);775addToGB(cbPrintToFile, this, gridbag, c);776777filePermission = allowedToPrintToFile();778}779780public boolean isPrintToFileSelected() {781return cbPrintToFile.isSelected();782}783784private JLabel addLabel(String text,785GridBagLayout gridbag, GridBagConstraints c)786{787c.gridwidth = 1;788addToGB(new JLabel(text, JLabel.TRAILING), this, gridbag, c);789790c.gridwidth = GridBagConstraints.REMAINDER;791JLabel label = new JLabel();792addToGB(label, this, gridbag, c);793794return label;795}796797public void actionPerformed(ActionEvent e) {798Object source = e.getSource();799800if (source == btnProperties) {801if (uiFactory != null) {802JDialog dialog = (JDialog)uiFactory.getUI(803ServiceUIFactory.MAIN_UIROLE,804ServiceUIFactory.JDIALOG_UI);805806if (dialog != null) {807dialog.show();808} else {809DocumentPropertiesUI docPropertiesUI = null;810try {811docPropertiesUI =812(DocumentPropertiesUI)uiFactory.getUI813(DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE,814DocumentPropertiesUI.DOCPROPERTIESCLASSNAME);815} catch (Exception ex) {816}817if (docPropertiesUI != null) {818PrinterJobWrapper wrapper = (PrinterJobWrapper)819asCurrent.get(PrinterJobWrapper.class);820if (wrapper == null) {821return; // should not happen, defensive only.822}823PrinterJob job = wrapper.getPrinterJob();824if (job == null) {825return; // should not happen, defensive only.826}827PrintRequestAttributeSet newAttrs =828docPropertiesUI.showDocumentProperties829(job, ServiceDialog.this, psCurrent, asCurrent);830if (newAttrs != null) {831asCurrent.addAll(newAttrs);832updatePanels();833}834}835}836}837}838}839840public void itemStateChanged(ItemEvent e) {841if (e.getStateChange() == ItemEvent.SELECTED) {842int index = cbName.getSelectedIndex();843844if ((index >= 0) && (index < services.length)) {845if (!services[index].equals(psCurrent)) {846psCurrent = services[index];847uiFactory = psCurrent.getServiceUIFactory();848changedService = true;849850Destination dest =851(Destination)asOriginal.get(Destination.class);852// to preserve the state of Print To File853if ((dest != null || isPrintToFileSelected())854&& psCurrent.isAttributeCategorySupported(855Destination.class)) {856857if (dest != null) {858asCurrent.add(dest);859} else {860dest = (Destination)psCurrent.861getDefaultAttributeValue(Destination.class);862// "dest" should not be null. The following code863// is only added to safeguard against a possible864// buggy implementation of a PrintService having a865// null default Destination.866if (dest == null) {867try {868dest =869new Destination(new URI("file:out.prn"));870} catch (URISyntaxException ue) {871}872}873874if (dest != null) {875asCurrent.add(dest);876}877}878} else {879asCurrent.remove(Destination.class);880}881}882}883}884}885886public void popupMenuWillBecomeVisible(PopupMenuEvent e) {887changedService = false;888}889890public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {891if (changedService) {892changedService = false;893updatePanels();894}895}896897public void popupMenuCanceled(PopupMenuEvent e) {898}899900/**901* We disable the "Print To File" checkbox if this returns false902*/903private boolean allowedToPrintToFile() {904try {905throwPrintToFile();906return true;907} catch (SecurityException e) {908return false;909}910}911912/**913* Break this out as it may be useful when we allow API to914* specify printing to a file. In that case its probably right915* to throw a SecurityException if the permission is not granted.916*/917private void throwPrintToFile() {918SecurityManager security = System.getSecurityManager();919if (security != null) {920if (printToFilePermission == null) {921printToFilePermission =922new FilePermission("<<ALL FILES>>", "read,write");923}924security.checkPermission(printToFilePermission);925}926}927928public void updateInfo() {929Class dstCategory = Destination.class;930boolean dstSupported = false;931boolean dstSelected = false;932boolean dstAllowed = filePermission ?933allowedToPrintToFile() : false;934935// setup Destination (print-to-file) widgets936if (psCurrent.isAttributeCategorySupported(dstCategory)) {937dstSupported = true;938}939Destination dst = (Destination)asCurrent.get(dstCategory);940if (dst != null) {941dstSelected = true;942}943cbPrintToFile.setEnabled(dstSupported && dstAllowed);944cbPrintToFile.setSelected(dstSelected && dstAllowed945&& dstSupported);946947// setup PrintService information widgets948Attribute type = psCurrent.getAttribute(PrinterMakeAndModel.class);949if (type != null) {950lblType.setText(type.toString());951}952Attribute status =953psCurrent.getAttribute(PrinterIsAcceptingJobs.class);954if (status != null) {955lblStatus.setText(getMsg(status.toString()));956}957Attribute info = psCurrent.getAttribute(PrinterInfo.class);958if (info != null) {959lblInfo.setText(info.toString());960}961btnProperties.setEnabled(uiFactory != null);962}963}964965private class PrintRangePanel extends JPanel966implements ActionListener, FocusListener967{968private final String strTitle = getMsg("border.printrange");969private final PageRanges prAll = new PageRanges(1, Integer.MAX_VALUE);970private JRadioButton rbAll, rbPages, rbSelect;971private JFormattedTextField tfRangeFrom, tfRangeTo;972private JLabel lblRangeTo;973private boolean prSupported;974975public PrintRangePanel() {976super();977978GridBagLayout gridbag = new GridBagLayout();979GridBagConstraints c = new GridBagConstraints();980981setLayout(gridbag);982setBorder(BorderFactory.createTitledBorder(strTitle));983984c.fill = GridBagConstraints.BOTH;985c.insets = compInsets;986c.gridwidth = GridBagConstraints.REMAINDER;987988ButtonGroup bg = new ButtonGroup();989JPanel pnlTop = new JPanel(new FlowLayout(FlowLayout.LEADING));990rbAll = createRadioButton("radiobutton.rangeall", this);991rbAll.setSelected(true);992bg.add(rbAll);993pnlTop.add(rbAll);994addToGB(pnlTop, this, gridbag, c);995996// Selection never seemed to work so I'm commenting this part.997/*998if (isAWT) {999JPanel pnlMiddle =1000new JPanel(new FlowLayout(FlowLayout.LEADING));1001rbSelect =1002createRadioButton("radiobutton.selection", this);1003bg.add(rbSelect);1004pnlMiddle.add(rbSelect);1005addToGB(pnlMiddle, this, gridbag, c);1006}1007*/10081009JPanel pnlBottom = new JPanel(new FlowLayout(FlowLayout.LEADING));1010rbPages = createRadioButton("radiobutton.rangepages", this);1011bg.add(rbPages);1012pnlBottom.add(rbPages);1013DecimalFormat format = new DecimalFormat("####0");1014format.setMinimumFractionDigits(0);1015format.setMaximumFractionDigits(0);1016format.setMinimumIntegerDigits(0);1017format.setMaximumIntegerDigits(5);1018format.setParseIntegerOnly(true);1019format.setDecimalSeparatorAlwaysShown(false);1020NumberFormatter nf = new NumberFormatter(format);1021nf.setMinimum(new Integer(1));1022nf.setMaximum(new Integer(Integer.MAX_VALUE));1023nf.setAllowsInvalid(true);1024nf.setCommitsOnValidEdit(true);1025tfRangeFrom = new JFormattedTextField(nf);1026tfRangeFrom.setColumns(4);1027tfRangeFrom.setEnabled(false);1028tfRangeFrom.addActionListener(this);1029tfRangeFrom.addFocusListener(this);1030tfRangeFrom.setFocusLostBehavior(1031JFormattedTextField.PERSIST);1032tfRangeFrom.getAccessibleContext().setAccessibleName(1033getMsg("radiobutton.rangepages"));1034pnlBottom.add(tfRangeFrom);1035lblRangeTo = new JLabel(getMsg("label.rangeto"));1036lblRangeTo.setEnabled(false);1037pnlBottom.add(lblRangeTo);1038NumberFormatter nfto;1039try {1040nfto = (NumberFormatter)nf.clone();1041} catch (CloneNotSupportedException e) {1042nfto = new NumberFormatter();1043}1044tfRangeTo = new JFormattedTextField(nfto);1045tfRangeTo.setColumns(4);1046tfRangeTo.setEnabled(false);1047tfRangeTo.addFocusListener(this);1048tfRangeTo.getAccessibleContext().setAccessibleName(1049getMsg("label.rangeto"));1050pnlBottom.add(tfRangeTo);1051addToGB(pnlBottom, this, gridbag, c);1052}10531054public void actionPerformed(ActionEvent e) {1055Object source = e.getSource();1056SunPageSelection select = SunPageSelection.ALL;10571058setupRangeWidgets();10591060if (source == rbAll) {1061asCurrent.add(prAll);1062} else if (source == rbSelect) {1063select = SunPageSelection.SELECTION;1064} else if (source == rbPages ||1065source == tfRangeFrom ||1066source == tfRangeTo) {1067updateRangeAttribute();1068select = SunPageSelection.RANGE;1069}10701071if (isAWT) {1072asCurrent.add(select);1073}1074}10751076public void focusLost(FocusEvent e) {1077Object source = e.getSource();10781079if ((source == tfRangeFrom) || (source == tfRangeTo)) {1080updateRangeAttribute();1081}1082}10831084public void focusGained(FocusEvent e) {}10851086private void setupRangeWidgets() {1087boolean rangeEnabled = (rbPages.isSelected() && prSupported);1088tfRangeFrom.setEnabled(rangeEnabled);1089tfRangeTo.setEnabled(rangeEnabled);1090lblRangeTo.setEnabled(rangeEnabled);1091}10921093private void updateRangeAttribute() {1094String strFrom = tfRangeFrom.getText();1095String strTo = tfRangeTo.getText();10961097int min;1098int max;10991100try {1101min = Integer.parseInt(strFrom);1102} catch (NumberFormatException e) {1103min = 1;1104}11051106try {1107max = Integer.parseInt(strTo);1108} catch (NumberFormatException e) {1109max = min;1110}11111112if (min < 1) {1113min = 1;1114tfRangeFrom.setValue(new Integer(1));1115}11161117if (max < min) {1118max = min;1119tfRangeTo.setValue(new Integer(min));1120}11211122PageRanges pr = new PageRanges(min, max);1123asCurrent.add(pr);1124}11251126public void updateInfo() {1127Class prCategory = PageRanges.class;1128prSupported = false;11291130if (psCurrent.isAttributeCategorySupported(prCategory) ||1131isAWT) {1132prSupported = true;1133}11341135SunPageSelection select = SunPageSelection.ALL;1136int min = 1;1137int max = 1;11381139PageRanges pr = (PageRanges)asCurrent.get(prCategory);1140if (pr != null) {1141if (!pr.equals(prAll)) {1142select = SunPageSelection.RANGE;11431144int[][] members = pr.getMembers();1145if ((members.length > 0) &&1146(members[0].length > 1)) {1147min = members[0][0];1148max = members[0][1];1149}1150}1151}11521153if (isAWT) {1154select = (SunPageSelection)asCurrent.get(1155SunPageSelection.class);1156}11571158if (select == SunPageSelection.ALL) {1159rbAll.setSelected(true);1160} else if (select == SunPageSelection.SELECTION) {1161// Comment this for now - rbSelect is not initialized1162// because Selection button is not added.1163// See PrintRangePanel above.11641165//rbSelect.setSelected(true);1166} else { // RANGE1167rbPages.setSelected(true);1168}1169tfRangeFrom.setValue(new Integer(min));1170tfRangeTo.setValue(new Integer(max));1171rbAll.setEnabled(prSupported);1172rbPages.setEnabled(prSupported);1173setupRangeWidgets();1174}1175}11761177private class CopiesPanel extends JPanel1178implements ActionListener, ChangeListener1179{1180private final String strTitle = getMsg("border.copies");1181private SpinnerNumberModel snModel;1182private JSpinner spinCopies;1183private JLabel lblCopies;1184private JCheckBox cbCollate;1185private boolean scSupported;11861187public CopiesPanel() {1188super();11891190GridBagLayout gridbag = new GridBagLayout();1191GridBagConstraints c = new GridBagConstraints();11921193setLayout(gridbag);1194setBorder(BorderFactory.createTitledBorder(strTitle));11951196c.fill = GridBagConstraints.HORIZONTAL;1197c.insets = compInsets;11981199lblCopies = new JLabel(getMsg("label.numcopies"), JLabel.TRAILING);1200lblCopies.setDisplayedMnemonic(getMnemonic("label.numcopies"));1201lblCopies.getAccessibleContext().setAccessibleName(1202getMsg("label.numcopies"));1203addToGB(lblCopies, this, gridbag, c);12041205snModel = new SpinnerNumberModel(1, 1, 999, 1);1206spinCopies = new JSpinner(snModel);1207lblCopies.setLabelFor(spinCopies);1208// REMIND1209((JSpinner.NumberEditor)spinCopies.getEditor()).getTextField().setColumns(3);1210spinCopies.addChangeListener(this);1211c.gridwidth = GridBagConstraints.REMAINDER;1212addToGB(spinCopies, this, gridbag, c);12131214cbCollate = createCheckBox("checkbox.collate", this);1215cbCollate.setEnabled(false);1216addToGB(cbCollate, this, gridbag, c);1217}12181219public void actionPerformed(ActionEvent e) {1220if (cbCollate.isSelected()) {1221asCurrent.add(SheetCollate.COLLATED);1222} else {1223asCurrent.add(SheetCollate.UNCOLLATED);1224}1225}12261227public void stateChanged(ChangeEvent e) {1228updateCollateCB();12291230asCurrent.add(new Copies(snModel.getNumber().intValue()));1231}12321233private void updateCollateCB() {1234int num = snModel.getNumber().intValue();1235if (isAWT) {1236cbCollate.setEnabled(true);1237} else {1238cbCollate.setEnabled((num > 1) && scSupported);1239}1240}12411242public void updateInfo() {1243Class cpCategory = Copies.class;1244Class csCategory = CopiesSupported.class;1245Class scCategory = SheetCollate.class;1246boolean cpSupported = false;1247scSupported = false;12481249// setup Copies spinner1250if (psCurrent.isAttributeCategorySupported(cpCategory)) {1251cpSupported = true;1252}1253CopiesSupported cs =1254(CopiesSupported)psCurrent.getSupportedAttributeValues(1255cpCategory, null, null);1256if (cs == null) {1257cs = new CopiesSupported(1, 999);1258}1259Copies cp = (Copies)asCurrent.get(cpCategory);1260if (cp == null) {1261cp = (Copies)psCurrent.getDefaultAttributeValue(cpCategory);1262if (cp == null) {1263cp = new Copies(1);1264}1265}1266spinCopies.setEnabled(cpSupported);1267lblCopies.setEnabled(cpSupported);12681269int[][] members = cs.getMembers();1270int min, max;1271if ((members.length > 0) && (members[0].length > 0)) {1272min = members[0][0];1273max = members[0][1];1274} else {1275min = 1;1276max = Integer.MAX_VALUE;1277}1278snModel.setMinimum(new Integer(min));1279snModel.setMaximum(new Integer(max));12801281int value = cp.getValue();1282if ((value < min) || (value > max)) {1283value = min;1284}1285snModel.setValue(new Integer(value));12861287// setup Collate checkbox1288if (psCurrent.isAttributeCategorySupported(scCategory)) {1289scSupported = true;1290}1291SheetCollate sc = (SheetCollate)asCurrent.get(scCategory);1292if (sc == null) {1293sc = (SheetCollate)psCurrent.getDefaultAttributeValue(scCategory);1294if (sc == null) {1295sc = SheetCollate.UNCOLLATED;1296}1297}1298cbCollate.setSelected(sc == SheetCollate.COLLATED);1299updateCollateCB();1300}1301}13021303130413051306/**1307* The "Page Setup" tab. Includes the controls for MediaSource/MediaTray,1308* OrientationRequested, and Sides.1309*/1310private class PageSetupPanel extends JPanel {13111312private MediaPanel pnlMedia;1313private OrientationPanel pnlOrientation;1314private MarginsPanel pnlMargins;13151316public PageSetupPanel() {1317super();13181319GridBagLayout gridbag = new GridBagLayout();1320GridBagConstraints c = new GridBagConstraints();13211322setLayout(gridbag);13231324c.fill = GridBagConstraints.BOTH;1325c.insets = panelInsets;1326c.weightx = 1.0;1327c.weighty = 1.0;13281329c.gridwidth = GridBagConstraints.REMAINDER;1330pnlMedia = new MediaPanel();1331addToGB(pnlMedia, this, gridbag, c);13321333pnlOrientation = new OrientationPanel();1334c.gridwidth = GridBagConstraints.RELATIVE;1335addToGB(pnlOrientation, this, gridbag, c);13361337pnlMargins = new MarginsPanel();1338pnlOrientation.addOrientationListener(pnlMargins);1339pnlMedia.addMediaListener(pnlMargins);1340c.gridwidth = GridBagConstraints.REMAINDER;1341addToGB(pnlMargins, this, gridbag, c);1342}13431344public void updateInfo() {1345pnlMedia.updateInfo();1346pnlOrientation.updateInfo();1347pnlMargins.updateInfo();1348}1349}13501351private class MarginsPanel extends JPanel1352implements ActionListener, FocusListener {13531354private final String strTitle = getMsg("border.margins");1355private JFormattedTextField leftMargin, rightMargin,1356topMargin, bottomMargin;1357private JLabel lblLeft, lblRight, lblTop, lblBottom;1358private int units = MediaPrintableArea.MM;1359// storage for the last margin values calculated, -ve is uninitialised1360private float lmVal = -1f,rmVal = -1f, tmVal = -1f, bmVal = -1f;1361// storage for margins as objects mapped into orientation for display1362private Float lmObj,rmObj,tmObj,bmObj;13631364public MarginsPanel() {1365super();13661367GridBagLayout gridbag = new GridBagLayout();1368GridBagConstraints c = new GridBagConstraints();1369c.fill = GridBagConstraints.HORIZONTAL;1370c.weightx = 1.0;1371c.weighty = 0.0;1372c.insets = compInsets;13731374setLayout(gridbag);1375setBorder(BorderFactory.createTitledBorder(strTitle));13761377String unitsKey = "label.millimetres";1378String defaultCountry = Locale.getDefault().getCountry();1379if (defaultCountry != null &&1380(defaultCountry.equals("") ||1381defaultCountry.equals(Locale.US.getCountry()) ||1382defaultCountry.equals(Locale.CANADA.getCountry()))) {1383unitsKey = "label.inches";1384units = MediaPrintableArea.INCH;1385}1386String unitsMsg = getMsg(unitsKey);13871388DecimalFormat format;1389if (units == MediaPrintableArea.MM) {1390format = new DecimalFormat("###.##");1391format.setMaximumIntegerDigits(3);1392} else {1393format = new DecimalFormat("##.##");1394format.setMaximumIntegerDigits(2);1395}13961397format.setMinimumFractionDigits(1);1398format.setMaximumFractionDigits(2);1399format.setMinimumIntegerDigits(1);1400format.setParseIntegerOnly(false);1401format.setDecimalSeparatorAlwaysShown(true);1402NumberFormatter nf = new NumberFormatter(format);1403nf.setMinimum(new Float(0.0f));1404nf.setMaximum(new Float(999.0f));1405nf.setAllowsInvalid(true);1406nf.setCommitsOnValidEdit(true);14071408leftMargin = new JFormattedTextField(nf);1409leftMargin.addFocusListener(this);1410leftMargin.addActionListener(this);1411leftMargin.getAccessibleContext().setAccessibleName(1412getMsg("label.leftmargin"));1413rightMargin = new JFormattedTextField(nf);1414rightMargin.addFocusListener(this);1415rightMargin.addActionListener(this);1416rightMargin.getAccessibleContext().setAccessibleName(1417getMsg("label.rightmargin"));1418topMargin = new JFormattedTextField(nf);1419topMargin.addFocusListener(this);1420topMargin.addActionListener(this);1421topMargin.getAccessibleContext().setAccessibleName(1422getMsg("label.topmargin"));1423topMargin = new JFormattedTextField(nf);1424bottomMargin = new JFormattedTextField(nf);1425bottomMargin.addFocusListener(this);1426bottomMargin.addActionListener(this);1427bottomMargin.getAccessibleContext().setAccessibleName(1428getMsg("label.bottommargin"));1429topMargin = new JFormattedTextField(nf);1430c.gridwidth = GridBagConstraints.RELATIVE;1431lblLeft = new JLabel(getMsg("label.leftmargin") + " " + unitsMsg,1432JLabel.LEADING);1433lblLeft.setDisplayedMnemonic(getMnemonic("label.leftmargin"));1434lblLeft.setLabelFor(leftMargin);1435addToGB(lblLeft, this, gridbag, c);14361437c.gridwidth = GridBagConstraints.REMAINDER;1438lblRight = new JLabel(getMsg("label.rightmargin") + " " + unitsMsg,1439JLabel.LEADING);1440lblRight.setDisplayedMnemonic(getMnemonic("label.rightmargin"));1441lblRight.setLabelFor(rightMargin);1442addToGB(lblRight, this, gridbag, c);14431444c.gridwidth = GridBagConstraints.RELATIVE;1445addToGB(leftMargin, this, gridbag, c);14461447c.gridwidth = GridBagConstraints.REMAINDER;1448addToGB(rightMargin, this, gridbag, c);14491450// add an invisible spacing component.1451addToGB(new JPanel(), this, gridbag, c);14521453c.gridwidth = GridBagConstraints.RELATIVE;1454lblTop = new JLabel(getMsg("label.topmargin") + " " + unitsMsg,1455JLabel.LEADING);1456lblTop.setDisplayedMnemonic(getMnemonic("label.topmargin"));1457lblTop.setLabelFor(topMargin);1458addToGB(lblTop, this, gridbag, c);14591460c.gridwidth = GridBagConstraints.REMAINDER;1461lblBottom = new JLabel(getMsg("label.bottommargin") +1462" " + unitsMsg, JLabel.LEADING);1463lblBottom.setDisplayedMnemonic(getMnemonic("label.bottommargin"));1464lblBottom.setLabelFor(bottomMargin);1465addToGB(lblBottom, this, gridbag, c);14661467c.gridwidth = GridBagConstraints.RELATIVE;1468addToGB(topMargin, this, gridbag, c);14691470c.gridwidth = GridBagConstraints.REMAINDER;1471addToGB(bottomMargin, this, gridbag, c);14721473}14741475public void actionPerformed(ActionEvent e) {1476Object source = e.getSource();1477updateMargins(source);1478}14791480public void focusLost(FocusEvent e) {1481Object source = e.getSource();1482updateMargins(source);1483}14841485public void focusGained(FocusEvent e) {}14861487/* Get the numbers, use to create a MPA.1488* If its valid, accept it and update the attribute set.1489* If its not valid, then reject it and call updateInfo()1490* to re-establish the previous entries.1491*/1492public void updateMargins(Object source) {1493if (!(source instanceof JFormattedTextField)) {1494return;1495} else {1496JFormattedTextField tf = (JFormattedTextField)source;1497Float val = (Float)tf.getValue();1498if (val == null) {1499return;1500}1501if (tf == leftMargin && val.equals(lmObj)) {1502return;1503}1504if (tf == rightMargin && val.equals(rmObj)) {1505return;1506}1507if (tf == topMargin && val.equals(tmObj)) {1508return;1509}1510if (tf == bottomMargin && val.equals(bmObj)) {1511return;1512}1513}15141515Float lmTmpObj = (Float)leftMargin.getValue();1516Float rmTmpObj = (Float)rightMargin.getValue();1517Float tmTmpObj = (Float)topMargin.getValue();1518Float bmTmpObj = (Float)bottomMargin.getValue();15191520float lm = lmTmpObj.floatValue();1521float rm = rmTmpObj.floatValue();1522float tm = tmTmpObj.floatValue();1523float bm = bmTmpObj.floatValue();15241525/* adjust for orientation */1526Class orCategory = OrientationRequested.class;1527OrientationRequested or =1528(OrientationRequested)asCurrent.get(orCategory);15291530if (or == null) {1531or = (OrientationRequested)1532psCurrent.getDefaultAttributeValue(orCategory);1533}15341535float tmp;1536if (or == OrientationRequested.REVERSE_PORTRAIT) {1537tmp = lm; lm = rm; rm = tmp;1538tmp = tm; tm = bm; bm = tmp;1539} else if (or == OrientationRequested.LANDSCAPE) {1540tmp = lm;1541lm = tm;1542tm = rm;1543rm = bm;1544bm = tmp;1545} else if (or == OrientationRequested.REVERSE_LANDSCAPE) {1546tmp = lm;1547lm = bm;1548bm = rm;1549rm = tm;1550tm = tmp;1551}1552MediaPrintableArea mpa;1553if ((mpa = validateMargins(lm, rm, tm, bm)) != null) {1554asCurrent.add(mpa);1555lmVal = lm;1556rmVal = rm;1557tmVal = tm;1558bmVal = bm;1559lmObj = lmTmpObj;1560rmObj = rmTmpObj;1561tmObj = tmTmpObj;1562bmObj = bmTmpObj;1563} else {1564if (lmObj == null || rmObj == null ||1565tmObj == null || rmObj == null) {1566return;1567} else {1568leftMargin.setValue(lmObj);1569rightMargin.setValue(rmObj);1570topMargin.setValue(tmObj);1571bottomMargin.setValue(bmObj);15721573}1574}1575}15761577/*1578* This method either accepts the values and creates a new1579* MediaPrintableArea, or does nothing.1580* It should not attempt to create a printable area from anything1581* other than the exact values passed in.1582* But REMIND/TBD: it would be user friendly to replace margins the1583* user entered but are out of bounds with the minimum.1584* At that point this method will need to take responsibility for1585* updating the "stored" values and the UI.1586*/1587private MediaPrintableArea validateMargins(float lm, float rm,1588float tm, float bm) {15891590Class mpaCategory = MediaPrintableArea.class;1591MediaPrintableArea mpa;1592MediaPrintableArea mpaMax = null;1593MediaSize mediaSize = null;15941595Media media = (Media)asCurrent.get(Media.class);1596if (media == null || !(media instanceof MediaSizeName)) {1597media = (Media)psCurrent.getDefaultAttributeValue(Media.class);1598}1599if (media != null && (media instanceof MediaSizeName)) {1600MediaSizeName msn = (MediaSizeName)media;1601mediaSize = MediaSize.getMediaSizeForName(msn);1602}1603if (mediaSize == null) {1604mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH);1605}16061607if (media != null) {1608PrintRequestAttributeSet tmpASet =1609new HashPrintRequestAttributeSet(asCurrent);1610tmpASet.add(media);16111612Object values =1613psCurrent.getSupportedAttributeValues(mpaCategory,1614docFlavor,1615tmpASet);1616if (values instanceof MediaPrintableArea[] &&1617((MediaPrintableArea[])values).length > 0) {1618mpaMax = ((MediaPrintableArea[])values)[0];16191620}1621}1622if (mpaMax == null) {1623mpaMax = new MediaPrintableArea(0f, 0f,1624mediaSize.getX(units),1625mediaSize.getY(units),1626units);1627}16281629float wid = mediaSize.getX(units);1630float hgt = mediaSize.getY(units);1631float pax = lm;1632float pay = tm;1633float paw = wid - lm - rm;1634float pah = hgt - tm - bm;16351636if (paw <= 0f || pah <= 0f || pax < 0f || pay < 0f ||1637pax < mpaMax.getX(units) || paw > mpaMax.getWidth(units) ||1638pay < mpaMax.getY(units) || pah > mpaMax.getHeight(units)) {1639return null;1640} else {1641return new MediaPrintableArea(lm, tm, paw, pah, units);1642}1643}16441645/* This is complex as a MediaPrintableArea is valid only within1646* a particular context of media size.1647* So we need a MediaSize as well as a MediaPrintableArea.1648* MediaSize can be obtained from MediaSizeName.1649* If the application specifies a MediaPrintableArea, we accept it1650* to the extent its valid for the Media they specify. If they1651* don't specify a Media, then the default is assumed.1652*1653* If an application doesn't define a MediaPrintableArea, we need to1654* create a suitable one, this is created using the specified (or1655* default) Media and default 1 inch margins. This is validated1656* against the paper in case this is too large for tiny media.1657*/1658public void updateInfo() {16591660if (isAWT) {1661leftMargin.setEnabled(false);1662rightMargin.setEnabled(false);1663topMargin.setEnabled(false);1664bottomMargin.setEnabled(false);1665lblLeft.setEnabled(false);1666lblRight.setEnabled(false);1667lblTop.setEnabled(false);1668lblBottom.setEnabled(false);1669return;1670}16711672Class mpaCategory = MediaPrintableArea.class;1673MediaPrintableArea mpa =1674(MediaPrintableArea)asCurrent.get(mpaCategory);1675MediaPrintableArea mpaMax = null;1676MediaSize mediaSize = null;16771678Media media = (Media)asCurrent.get(Media.class);1679if (media == null || !(media instanceof MediaSizeName)) {1680media = (Media)psCurrent.getDefaultAttributeValue(Media.class);1681}1682if (media != null && (media instanceof MediaSizeName)) {1683MediaSizeName msn = (MediaSizeName)media;1684mediaSize = MediaSize.getMediaSizeForName(msn);1685}1686if (mediaSize == null) {1687mediaSize = new MediaSize(8.5f, 11f, Size2DSyntax.INCH);1688}16891690if (media != null) {1691PrintRequestAttributeSet tmpASet =1692new HashPrintRequestAttributeSet(asCurrent);1693tmpASet.add(media);16941695Object values =1696psCurrent.getSupportedAttributeValues(mpaCategory,1697docFlavor,1698tmpASet);1699if (values instanceof MediaPrintableArea[] &&1700((MediaPrintableArea[])values).length > 0) {1701mpaMax = ((MediaPrintableArea[])values)[0];17021703} else if (values instanceof MediaPrintableArea) {1704mpaMax = (MediaPrintableArea)values;1705}1706}1707if (mpaMax == null) {1708mpaMax = new MediaPrintableArea(0f, 0f,1709mediaSize.getX(units),1710mediaSize.getY(units),1711units);1712}17131714/*1715* At this point we now know as best we can :-1716* - the media size1717* - the maximum corresponding printable area1718* - the media printable area specified by the client, if any.1719* The next step is to create a default MPA if none was specified.1720* 1" margins are used unless they are disproportionately1721* large compared to the size of the media.1722*/17231724float wid = mediaSize.getX(MediaPrintableArea.INCH);1725float hgt = mediaSize.getY(MediaPrintableArea.INCH);1726float maxMarginRatio = 5f;1727float xMgn, yMgn;1728if (wid > maxMarginRatio) {1729xMgn = 1f;1730} else {1731xMgn = wid / maxMarginRatio;1732}1733if (hgt > maxMarginRatio) {1734yMgn = 1f;1735} else {1736yMgn = hgt / maxMarginRatio;1737}17381739if (mpa == null) {1740mpa = new MediaPrintableArea(xMgn, yMgn,1741wid-(2*xMgn), hgt-(2*yMgn),1742MediaPrintableArea.INCH);1743asCurrent.add(mpa);1744}1745float pax = mpa.getX(units);1746float pay = mpa.getY(units);1747float paw = mpa.getWidth(units);1748float pah = mpa.getHeight(units);1749float paxMax = mpaMax.getX(units);1750float payMax = mpaMax.getY(units);1751float pawMax = mpaMax.getWidth(units);1752float pahMax = mpaMax.getHeight(units);175317541755boolean invalid = false;17561757// If the paper is set to something which is too small to1758// accommodate a specified printable area, perhaps carried1759// over from a larger paper, the adjustment that needs to be1760// performed should seem the most natural from a user's viewpoint.1761// Since the user is specifying margins, then we are biased1762// towards keeping the margins as close to what is specified as1763// possible, shrinking or growing the printable area.1764// But the API uses printable area, so you need to know the1765// media size in which the margins were previously interpreted,1766// or at least have a record of the margins.1767// In the case that this is the creation of this UI we do not1768// have this record, so we are somewhat reliant on the client1769// to supply a reasonable default1770wid = mediaSize.getX(units);1771hgt = mediaSize.getY(units);1772if (lmVal >= 0f) {1773invalid = true;17741775if (lmVal + rmVal > wid) {1776// margins impossible, but maintain P.A if can1777if (paw > pawMax) {1778paw = pawMax;1779}1780// try to centre the printable area.1781pax = (wid - paw)/2f;1782} else {1783pax = (lmVal >= paxMax) ? lmVal : paxMax;1784paw = wid - pax - rmVal;1785}1786if (tmVal + bmVal > hgt) {1787if (pah > pahMax) {1788pah = pahMax;1789}1790pay = (hgt - pah)/2f;1791} else {1792pay = (tmVal >= payMax) ? tmVal : payMax;1793pah = hgt - pay - bmVal;1794}1795}1796if (pax < paxMax) {1797invalid = true;1798pax = paxMax;1799}1800if (pay < payMax) {1801invalid = true;1802pay = payMax;1803}1804if (paw > pawMax) {1805invalid = true;1806paw = pawMax;1807}1808if (pah > pahMax) {1809invalid = true;1810pah = pahMax;1811}18121813if ((pax + paw > paxMax + pawMax) || (paw <= 0f)) {1814invalid = true;1815pax = paxMax;1816paw = pawMax;1817}1818if ((pay + pah > payMax + pahMax) || (pah <= 0f)) {1819invalid = true;1820pay = payMax;1821pah = pahMax;1822}18231824if (invalid) {1825mpa = new MediaPrintableArea(pax, pay, paw, pah, units);1826asCurrent.add(mpa);1827}18281829/* We now have a valid printable area.1830* Turn it into margins, using the mediaSize1831*/1832lmVal = pax;1833tmVal = pay;1834rmVal = mediaSize.getX(units) - pax - paw;1835bmVal = mediaSize.getY(units) - pay - pah;18361837lmObj = new Float(lmVal);1838rmObj = new Float(rmVal);1839tmObj = new Float(tmVal);1840bmObj = new Float(bmVal);18411842/* Now we know the values to use, we need to assign them1843* to the fields appropriate for the orientation.1844* Note: if orientation changes this method must be called.1845*/1846Class orCategory = OrientationRequested.class;1847OrientationRequested or =1848(OrientationRequested)asCurrent.get(orCategory);18491850if (or == null) {1851or = (OrientationRequested)1852psCurrent.getDefaultAttributeValue(orCategory);1853}18541855Float tmp;18561857if (or == OrientationRequested.REVERSE_PORTRAIT) {1858tmp = lmObj; lmObj = rmObj; rmObj = tmp;1859tmp = tmObj; tmObj = bmObj; bmObj = tmp;1860} else if (or == OrientationRequested.LANDSCAPE) {1861tmp = lmObj;1862lmObj = bmObj;1863bmObj = rmObj;1864rmObj = tmObj;1865tmObj = tmp;1866} else if (or == OrientationRequested.REVERSE_LANDSCAPE) {1867tmp = lmObj;1868lmObj = tmObj;1869tmObj = rmObj;1870rmObj = bmObj;1871bmObj = tmp;1872}18731874leftMargin.setValue(lmObj);1875rightMargin.setValue(rmObj);1876topMargin.setValue(tmObj);1877bottomMargin.setValue(bmObj);1878}1879}18801881private class MediaPanel extends JPanel implements ItemListener {18821883private final String strTitle = getMsg("border.media");1884private JLabel lblSize, lblSource;1885private JComboBox cbSize, cbSource;1886private Vector sizes = new Vector();1887private Vector sources = new Vector();1888private MarginsPanel pnlMargins = null;18891890public MediaPanel() {1891super();18921893GridBagLayout gridbag = new GridBagLayout();1894GridBagConstraints c = new GridBagConstraints();18951896setLayout(gridbag);1897setBorder(BorderFactory.createTitledBorder(strTitle));18981899cbSize = new JComboBox();1900cbSource = new JComboBox();19011902c.fill = GridBagConstraints.BOTH;1903c.insets = compInsets;1904c.weighty = 1.0;19051906c.weightx = 0.0;1907lblSize = new JLabel(getMsg("label.size"), JLabel.TRAILING);1908lblSize.setDisplayedMnemonic(getMnemonic("label.size"));1909lblSize.setLabelFor(cbSize);1910addToGB(lblSize, this, gridbag, c);1911c.weightx = 1.0;1912c.gridwidth = GridBagConstraints.REMAINDER;1913addToGB(cbSize, this, gridbag, c);19141915c.weightx = 0.0;1916c.gridwidth = 1;1917lblSource = new JLabel(getMsg("label.source"), JLabel.TRAILING);1918lblSource.setDisplayedMnemonic(getMnemonic("label.source"));1919lblSource.setLabelFor(cbSource);1920addToGB(lblSource, this, gridbag, c);1921c.gridwidth = GridBagConstraints.REMAINDER;1922addToGB(cbSource, this, gridbag, c);1923}19241925private String getMediaName(String key) {1926try {1927// replace characters that would be invalid in1928// a resource key with valid characters1929String newkey = key.replace(' ', '-');1930newkey = newkey.replace('#', 'n');19311932return messageRB.getString(newkey);1933} catch (java.util.MissingResourceException e) {1934return key;1935}1936}19371938public void itemStateChanged(ItemEvent e) {1939Object source = e.getSource();19401941if (e.getStateChange() == ItemEvent.SELECTED) {1942if (source == cbSize) {1943int index = cbSize.getSelectedIndex();19441945if ((index >= 0) && (index < sizes.size())) {1946if ((cbSource.getItemCount() > 1) &&1947(cbSource.getSelectedIndex() >= 1))1948{1949int src = cbSource.getSelectedIndex() - 1;1950MediaTray mt = (MediaTray)sources.get(src);1951asCurrent.add(new SunAlternateMedia(mt));1952}1953asCurrent.add((MediaSizeName)sizes.get(index));1954}1955} else if (source == cbSource) {1956int index = cbSource.getSelectedIndex();19571958if ((index >= 1) && (index < (sources.size() + 1))) {1959asCurrent.remove(SunAlternateMedia.class);1960MediaTray newTray = (MediaTray)sources.get(index - 1);1961Media m = (Media)asCurrent.get(Media.class);1962if (m == null || m instanceof MediaTray) {1963asCurrent.add(newTray);1964} else if (m instanceof MediaSizeName) {1965MediaSizeName msn = (MediaSizeName)m;1966Media def = (Media)psCurrent.getDefaultAttributeValue(Media.class);1967if (def instanceof MediaSizeName && def.equals(msn)) {1968asCurrent.add(newTray);1969} else {1970/* Non-default paper size, so need to store tray1971* as SunAlternateMedia1972*/1973asCurrent.add(new SunAlternateMedia(newTray));1974}1975}1976} else if (index == 0) {1977asCurrent.remove(SunAlternateMedia.class);1978if (cbSize.getItemCount() > 0) {1979int size = cbSize.getSelectedIndex();1980asCurrent.add((MediaSizeName)sizes.get(size));1981}1982}1983}1984// orientation affects display of margins.1985if (pnlMargins != null) {1986pnlMargins.updateInfo();1987}1988}1989}199019911992/* this is ad hoc to keep things simple */1993public void addMediaListener(MarginsPanel pnl) {1994pnlMargins = pnl;1995}1996public void updateInfo() {1997Class mdCategory = Media.class;1998Class amCategory = SunAlternateMedia.class;1999boolean mediaSupported = false;20002001cbSize.removeItemListener(this);2002cbSize.removeAllItems();2003cbSource.removeItemListener(this);2004cbSource.removeAllItems();2005cbSource.addItem(getMediaName("auto-select"));20062007sizes.clear();2008sources.clear();20092010if (psCurrent.isAttributeCategorySupported(mdCategory)) {2011mediaSupported = true;20122013Object values =2014psCurrent.getSupportedAttributeValues(mdCategory,2015docFlavor,2016asCurrent);20172018if (values instanceof Media[]) {2019Media[] media = (Media[])values;20202021for (int i = 0; i < media.length; i++) {2022Media medium = media[i];20232024if (medium instanceof MediaSizeName) {2025sizes.add(medium);2026cbSize.addItem(getMediaName(medium.toString()));2027} else if (medium instanceof MediaTray) {2028sources.add(medium);2029cbSource.addItem(getMediaName(medium.toString()));2030}2031}2032}2033}20342035boolean msSupported = (mediaSupported && (sizes.size() > 0));2036lblSize.setEnabled(msSupported);2037cbSize.setEnabled(msSupported);20382039if (isAWT) {2040cbSource.setEnabled(false);2041lblSource.setEnabled(false);2042} else {2043cbSource.setEnabled(mediaSupported);2044}20452046if (mediaSupported) {20472048Media medium = (Media)asCurrent.get(mdCategory);20492050// initialize size selection to default2051Media defMedia = (Media)psCurrent.getDefaultAttributeValue(mdCategory);2052if (defMedia instanceof MediaSizeName) {2053cbSize.setSelectedIndex(sizes.size() > 0 ? sizes.indexOf(defMedia) : -1);2054}20552056if (medium == null ||2057!psCurrent.isAttributeValueSupported(medium,2058docFlavor, asCurrent)) {20592060medium = defMedia;20612062if (medium == null) {2063if (sizes.size() > 0) {2064medium = (Media)sizes.get(0);2065}2066}2067if (medium != null) {2068asCurrent.add(medium);2069}2070}2071if (medium != null) {2072if (medium instanceof MediaSizeName) {2073MediaSizeName ms = (MediaSizeName)medium;2074cbSize.setSelectedIndex(sizes.indexOf(ms));2075} else if (medium instanceof MediaTray) {2076MediaTray mt = (MediaTray)medium;2077cbSource.setSelectedIndex(sources.indexOf(mt) + 1);2078}2079} else {2080cbSize.setSelectedIndex(sizes.size() > 0 ? 0 : -1);2081cbSource.setSelectedIndex(0);2082}20832084SunAlternateMedia alt = (SunAlternateMedia)asCurrent.get(amCategory);2085if (alt != null) {2086Media md = alt.getMedia();2087if (md instanceof MediaTray) {2088MediaTray mt = (MediaTray)md;2089cbSource.setSelectedIndex(sources.indexOf(mt) + 1);2090}2091}20922093int selIndex = cbSize.getSelectedIndex();2094if ((selIndex >= 0) && (selIndex < sizes.size())) {2095asCurrent.add((MediaSizeName)sizes.get(selIndex));2096}20972098selIndex = cbSource.getSelectedIndex();2099if ((selIndex >= 1) && (selIndex < (sources.size()+1))) {2100MediaTray mt = (MediaTray)sources.get(selIndex-1);2101if (medium instanceof MediaTray) {2102asCurrent.add(mt);2103} else {2104asCurrent.add(new SunAlternateMedia(mt));2105}2106}210721082109}2110cbSize.addItemListener(this);2111cbSource.addItemListener(this);2112}2113}21142115private class OrientationPanel extends JPanel2116implements ActionListener2117{2118private final String strTitle = getMsg("border.orientation");2119private IconRadioButton rbPortrait, rbLandscape,2120rbRevPortrait, rbRevLandscape;2121private MarginsPanel pnlMargins = null;21222123public OrientationPanel() {2124super();21252126GridBagLayout gridbag = new GridBagLayout();2127GridBagConstraints c = new GridBagConstraints();21282129setLayout(gridbag);2130setBorder(BorderFactory.createTitledBorder(strTitle));21312132c.fill = GridBagConstraints.BOTH;2133c.insets = compInsets;2134c.weighty = 1.0;2135c.gridwidth = GridBagConstraints.REMAINDER;21362137ButtonGroup bg = new ButtonGroup();2138rbPortrait = new IconRadioButton("radiobutton.portrait",2139"orientPortrait.png", true,2140bg, this);2141rbPortrait.addActionListener(this);2142addToGB(rbPortrait, this, gridbag, c);2143rbLandscape = new IconRadioButton("radiobutton.landscape",2144"orientLandscape.png", false,2145bg, this);2146rbLandscape.addActionListener(this);2147addToGB(rbLandscape, this, gridbag, c);2148rbRevPortrait = new IconRadioButton("radiobutton.revportrait",2149"orientRevPortrait.png", false,2150bg, this);2151rbRevPortrait.addActionListener(this);2152addToGB(rbRevPortrait, this, gridbag, c);2153rbRevLandscape = new IconRadioButton("radiobutton.revlandscape",2154"orientRevLandscape.png", false,2155bg, this);2156rbRevLandscape.addActionListener(this);2157addToGB(rbRevLandscape, this, gridbag, c);2158}21592160public void actionPerformed(ActionEvent e) {2161Object source = e.getSource();21622163if (rbPortrait.isSameAs(source)) {2164asCurrent.add(OrientationRequested.PORTRAIT);2165} else if (rbLandscape.isSameAs(source)) {2166asCurrent.add(OrientationRequested.LANDSCAPE);2167} else if (rbRevPortrait.isSameAs(source)) {2168asCurrent.add(OrientationRequested.REVERSE_PORTRAIT);2169} else if (rbRevLandscape.isSameAs(source)) {2170asCurrent.add(OrientationRequested.REVERSE_LANDSCAPE);2171}2172// orientation affects display of margins.2173if (pnlMargins != null) {2174pnlMargins.updateInfo();2175}2176}21772178/* This is ad hoc to keep things simple */2179void addOrientationListener(MarginsPanel pnl) {2180pnlMargins = pnl;2181}21822183public void updateInfo() {2184Class orCategory = OrientationRequested.class;2185boolean pSupported = false;2186boolean lSupported = false;2187boolean rpSupported = false;2188boolean rlSupported = false;21892190if (isAWT) {2191pSupported = true;2192lSupported = true;2193} else2194if (psCurrent.isAttributeCategorySupported(orCategory)) {2195Object values =2196psCurrent.getSupportedAttributeValues(orCategory,2197docFlavor,2198asCurrent);21992200if (values instanceof OrientationRequested[]) {2201OrientationRequested[] ovalues =2202(OrientationRequested[])values;22032204for (int i = 0; i < ovalues.length; i++) {2205OrientationRequested value = ovalues[i];22062207if (value == OrientationRequested.PORTRAIT) {2208pSupported = true;2209} else if (value == OrientationRequested.LANDSCAPE) {2210lSupported = true;2211} else if (value == OrientationRequested.REVERSE_PORTRAIT) {2212rpSupported = true;2213} else if (value == OrientationRequested.REVERSE_LANDSCAPE) {2214rlSupported = true;2215}2216}2217}2218}221922202221rbPortrait.setEnabled(pSupported);2222rbLandscape.setEnabled(lSupported);2223rbRevPortrait.setEnabled(rpSupported);2224rbRevLandscape.setEnabled(rlSupported);22252226OrientationRequested or = (OrientationRequested)asCurrent.get(orCategory);2227if (or == null ||2228!psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) {22292230or = (OrientationRequested)psCurrent.getDefaultAttributeValue(orCategory);2231// need to validate if default is not supported2232if ((or != null) &&2233!psCurrent.isAttributeValueSupported(or, docFlavor, asCurrent)) {2234or = null;2235Object values =2236psCurrent.getSupportedAttributeValues(orCategory,2237docFlavor,2238asCurrent);2239if (values instanceof OrientationRequested[]) {2240OrientationRequested[] orValues =2241(OrientationRequested[])values;2242if (orValues.length > 1) {2243// get the first in the list2244or = orValues[0];2245}2246}2247}22482249if (or == null) {2250or = OrientationRequested.PORTRAIT;2251}2252asCurrent.add(or);2253}22542255if (or == OrientationRequested.PORTRAIT) {2256rbPortrait.setSelected(true);2257} else if (or == OrientationRequested.LANDSCAPE) {2258rbLandscape.setSelected(true);2259} else if (or == OrientationRequested.REVERSE_PORTRAIT) {2260rbRevPortrait.setSelected(true);2261} else { // if (or == OrientationRequested.REVERSE_LANDSCAPE)2262rbRevLandscape.setSelected(true);2263}2264}2265}2266226722682269/**2270* The "Appearance" tab. Includes the controls for Chromaticity,2271* PrintQuality, JobPriority, JobName, and other related job attributes.2272*/2273private class AppearancePanel extends JPanel {22742275private ChromaticityPanel pnlChromaticity;2276private QualityPanel pnlQuality;2277private JobAttributesPanel pnlJobAttributes;2278private SidesPanel pnlSides;22792280public AppearancePanel() {2281super();22822283GridBagLayout gridbag = new GridBagLayout();2284GridBagConstraints c = new GridBagConstraints();22852286setLayout(gridbag);22872288c.fill = GridBagConstraints.BOTH;2289c.insets = panelInsets;2290c.weightx = 1.0;2291c.weighty = 1.0;22922293c.gridwidth = GridBagConstraints.RELATIVE;2294pnlChromaticity = new ChromaticityPanel();2295addToGB(pnlChromaticity, this, gridbag, c);22962297c.gridwidth = GridBagConstraints.REMAINDER;2298pnlQuality = new QualityPanel();2299addToGB(pnlQuality, this, gridbag, c);23002301c.gridwidth = 1;2302pnlSides = new SidesPanel();2303addToGB(pnlSides, this, gridbag, c);23042305c.gridwidth = GridBagConstraints.REMAINDER;2306pnlJobAttributes = new JobAttributesPanel();2307addToGB(pnlJobAttributes, this, gridbag, c);23082309}23102311public void updateInfo() {2312pnlChromaticity.updateInfo();2313pnlQuality.updateInfo();2314pnlSides.updateInfo();2315pnlJobAttributes.updateInfo();2316}2317}23182319private class ChromaticityPanel extends JPanel2320implements ActionListener2321{2322private final String strTitle = getMsg("border.chromaticity");2323private JRadioButton rbMonochrome, rbColor;23242325public ChromaticityPanel() {2326super();23272328GridBagLayout gridbag = new GridBagLayout();2329GridBagConstraints c = new GridBagConstraints();23302331setLayout(gridbag);2332setBorder(BorderFactory.createTitledBorder(strTitle));23332334c.fill = GridBagConstraints.BOTH;2335c.gridwidth = GridBagConstraints.REMAINDER;2336c.weighty = 1.0;23372338ButtonGroup bg = new ButtonGroup();2339rbMonochrome = createRadioButton("radiobutton.monochrome", this);2340rbMonochrome.setSelected(true);2341bg.add(rbMonochrome);2342addToGB(rbMonochrome, this, gridbag, c);2343rbColor = createRadioButton("radiobutton.color", this);2344bg.add(rbColor);2345addToGB(rbColor, this, gridbag, c);2346}23472348public void actionPerformed(ActionEvent e) {2349Object source = e.getSource();23502351// REMIND: use isSameAs if we move to a IconRB in the future2352if (source == rbMonochrome) {2353asCurrent.add(Chromaticity.MONOCHROME);2354} else if (source == rbColor) {2355asCurrent.add(Chromaticity.COLOR);2356}2357}23582359public void updateInfo() {2360Class chCategory = Chromaticity.class;2361boolean monoSupported = false;2362boolean colorSupported = false;23632364if (isAWT) {2365monoSupported = true;2366colorSupported = true;2367} else2368if (psCurrent.isAttributeCategorySupported(chCategory)) {2369Object values =2370psCurrent.getSupportedAttributeValues(chCategory,2371docFlavor,2372asCurrent);23732374if (values instanceof Chromaticity[]) {2375Chromaticity[] cvalues = (Chromaticity[])values;23762377for (int i = 0; i < cvalues.length; i++) {2378Chromaticity value = cvalues[i];23792380if (value == Chromaticity.MONOCHROME) {2381monoSupported = true;2382} else if (value == Chromaticity.COLOR) {2383colorSupported = true;2384}2385}2386}2387}238823892390rbMonochrome.setEnabled(monoSupported);2391rbColor.setEnabled(colorSupported);23922393Chromaticity ch = (Chromaticity)asCurrent.get(chCategory);2394if (ch == null) {2395ch = (Chromaticity)psCurrent.getDefaultAttributeValue(chCategory);2396if (ch == null) {2397ch = Chromaticity.MONOCHROME;2398}2399}24002401if (ch == Chromaticity.MONOCHROME) {2402rbMonochrome.setSelected(true);2403} else { // if (ch == Chromaticity.COLOR)2404rbColor.setSelected(true);2405}2406}2407}24082409private class QualityPanel extends JPanel2410implements ActionListener2411{2412private final String strTitle = getMsg("border.quality");2413private JRadioButton rbDraft, rbNormal, rbHigh;24142415public QualityPanel() {2416super();24172418GridBagLayout gridbag = new GridBagLayout();2419GridBagConstraints c = new GridBagConstraints();24202421setLayout(gridbag);2422setBorder(BorderFactory.createTitledBorder(strTitle));24232424c.fill = GridBagConstraints.BOTH;2425c.gridwidth = GridBagConstraints.REMAINDER;2426c.weighty = 1.0;24272428ButtonGroup bg = new ButtonGroup();2429rbDraft = createRadioButton("radiobutton.draftq", this);2430bg.add(rbDraft);2431addToGB(rbDraft, this, gridbag, c);2432rbNormal = createRadioButton("radiobutton.normalq", this);2433rbNormal.setSelected(true);2434bg.add(rbNormal);2435addToGB(rbNormal, this, gridbag, c);2436rbHigh = createRadioButton("radiobutton.highq", this);2437bg.add(rbHigh);2438addToGB(rbHigh, this, gridbag, c);2439}24402441public void actionPerformed(ActionEvent e) {2442Object source = e.getSource();24432444if (source == rbDraft) {2445asCurrent.add(PrintQuality.DRAFT);2446} else if (source == rbNormal) {2447asCurrent.add(PrintQuality.NORMAL);2448} else if (source == rbHigh) {2449asCurrent.add(PrintQuality.HIGH);2450}2451}24522453public void updateInfo() {2454Class pqCategory = PrintQuality.class;2455boolean draftSupported = false;2456boolean normalSupported = false;2457boolean highSupported = false;24582459if (isAWT) {2460draftSupported = true;2461normalSupported = true;2462highSupported = true;2463} else2464if (psCurrent.isAttributeCategorySupported(pqCategory)) {2465Object values =2466psCurrent.getSupportedAttributeValues(pqCategory,2467docFlavor,2468asCurrent);24692470if (values instanceof PrintQuality[]) {2471PrintQuality[] qvalues = (PrintQuality[])values;24722473for (int i = 0; i < qvalues.length; i++) {2474PrintQuality value = qvalues[i];24752476if (value == PrintQuality.DRAFT) {2477draftSupported = true;2478} else if (value == PrintQuality.NORMAL) {2479normalSupported = true;2480} else if (value == PrintQuality.HIGH) {2481highSupported = true;2482}2483}2484}2485}24862487rbDraft.setEnabled(draftSupported);2488rbNormal.setEnabled(normalSupported);2489rbHigh.setEnabled(highSupported);24902491PrintQuality pq = (PrintQuality)asCurrent.get(pqCategory);2492if (pq == null) {2493pq = (PrintQuality)psCurrent.getDefaultAttributeValue(pqCategory);2494if (pq == null) {2495pq = PrintQuality.NORMAL;2496}2497}24982499if (pq == PrintQuality.DRAFT) {2500rbDraft.setSelected(true);2501} else if (pq == PrintQuality.NORMAL) {2502rbNormal.setSelected(true);2503} else { // if (pq == PrintQuality.HIGH)2504rbHigh.setSelected(true);2505}2506}250725082509}2510private class SidesPanel extends JPanel2511implements ActionListener2512{2513private final String strTitle = getMsg("border.sides");2514private IconRadioButton rbOneSide, rbTumble, rbDuplex;25152516public SidesPanel() {2517super();25182519GridBagLayout gridbag = new GridBagLayout();2520GridBagConstraints c = new GridBagConstraints();25212522setLayout(gridbag);2523setBorder(BorderFactory.createTitledBorder(strTitle));25242525c.fill = GridBagConstraints.BOTH;2526c.insets = compInsets;2527c.weighty = 1.0;2528c.gridwidth = GridBagConstraints.REMAINDER;25292530ButtonGroup bg = new ButtonGroup();2531rbOneSide = new IconRadioButton("radiobutton.oneside",2532"oneside.png", true,2533bg, this);2534rbOneSide.addActionListener(this);2535addToGB(rbOneSide, this, gridbag, c);2536rbTumble = new IconRadioButton("radiobutton.tumble",2537"tumble.png", false,2538bg, this);2539rbTumble.addActionListener(this);2540addToGB(rbTumble, this, gridbag, c);2541rbDuplex = new IconRadioButton("radiobutton.duplex",2542"duplex.png", false,2543bg, this);2544rbDuplex.addActionListener(this);2545c.gridwidth = GridBagConstraints.REMAINDER;2546addToGB(rbDuplex, this, gridbag, c);2547}25482549public void actionPerformed(ActionEvent e) {2550Object source = e.getSource();25512552if (rbOneSide.isSameAs(source)) {2553asCurrent.add(Sides.ONE_SIDED);2554} else if (rbTumble.isSameAs(source)) {2555asCurrent.add(Sides.TUMBLE);2556} else if (rbDuplex.isSameAs(source)) {2557asCurrent.add(Sides.DUPLEX);2558}2559}25602561public void updateInfo() {2562Class sdCategory = Sides.class;2563boolean osSupported = false;2564boolean tSupported = false;2565boolean dSupported = false;25662567if (psCurrent.isAttributeCategorySupported(sdCategory)) {2568Object values =2569psCurrent.getSupportedAttributeValues(sdCategory,2570docFlavor,2571asCurrent);25722573if (values instanceof Sides[]) {2574Sides[] svalues = (Sides[])values;25752576for (int i = 0; i < svalues.length; i++) {2577Sides value = svalues[i];25782579if (value == Sides.ONE_SIDED) {2580osSupported = true;2581} else if (value == Sides.TUMBLE) {2582tSupported = true;2583} else if (value == Sides.DUPLEX) {2584dSupported = true;2585}2586}2587}2588}2589rbOneSide.setEnabled(osSupported);2590rbTumble.setEnabled(tSupported);2591rbDuplex.setEnabled(dSupported);25922593Sides sd = (Sides)asCurrent.get(sdCategory);2594if (sd == null) {2595sd = (Sides)psCurrent.getDefaultAttributeValue(sdCategory);2596if (sd == null) {2597sd = Sides.ONE_SIDED;2598}2599}26002601if (sd == Sides.ONE_SIDED) {2602rbOneSide.setSelected(true);2603} else if (sd == Sides.TUMBLE) {2604rbTumble.setSelected(true);2605} else { // if (sd == Sides.DUPLEX)2606rbDuplex.setSelected(true);2607}2608}2609}2610261126122613private class JobAttributesPanel extends JPanel2614implements ActionListener, ChangeListener, FocusListener2615{2616private final String strTitle = getMsg("border.jobattributes");2617private JLabel lblPriority, lblJobName, lblUserName;2618private JSpinner spinPriority;2619private SpinnerNumberModel snModel;2620private JCheckBox cbJobSheets;2621private JTextField tfJobName, tfUserName;26222623public JobAttributesPanel() {2624super();26252626GridBagLayout gridbag = new GridBagLayout();2627GridBagConstraints c = new GridBagConstraints();26282629setLayout(gridbag);2630setBorder(BorderFactory.createTitledBorder(strTitle));26312632c.fill = GridBagConstraints.NONE;2633c.insets = compInsets;2634c.weighty = 1.0;26352636cbJobSheets = createCheckBox("checkbox.jobsheets", this);2637c.anchor = GridBagConstraints.LINE_START;2638addToGB(cbJobSheets, this, gridbag, c);26392640JPanel pnlTop = new JPanel();2641lblPriority = new JLabel(getMsg("label.priority"), JLabel.TRAILING);2642lblPriority.setDisplayedMnemonic(getMnemonic("label.priority"));26432644pnlTop.add(lblPriority);2645snModel = new SpinnerNumberModel(1, 1, 100, 1);2646spinPriority = new JSpinner(snModel);2647lblPriority.setLabelFor(spinPriority);2648// REMIND2649((JSpinner.NumberEditor)spinPriority.getEditor()).getTextField().setColumns(3);2650spinPriority.addChangeListener(this);2651pnlTop.add(spinPriority);2652c.anchor = GridBagConstraints.LINE_END;2653c.gridwidth = GridBagConstraints.REMAINDER;2654pnlTop.getAccessibleContext().setAccessibleName(2655getMsg("label.priority"));2656addToGB(pnlTop, this, gridbag, c);26572658c.fill = GridBagConstraints.HORIZONTAL;2659c.anchor = GridBagConstraints.CENTER;2660c.weightx = 0.0;2661c.gridwidth = 1;2662char jmnemonic = getMnemonic("label.jobname");2663lblJobName = new JLabel(getMsg("label.jobname"), JLabel.TRAILING);2664lblJobName.setDisplayedMnemonic(jmnemonic);2665addToGB(lblJobName, this, gridbag, c);2666c.weightx = 1.0;2667c.gridwidth = GridBagConstraints.REMAINDER;2668tfJobName = new JTextField();2669lblJobName.setLabelFor(tfJobName);2670tfJobName.addFocusListener(this);2671tfJobName.setFocusAccelerator(jmnemonic);2672tfJobName.getAccessibleContext().setAccessibleName(2673getMsg("label.jobname"));2674addToGB(tfJobName, this, gridbag, c);26752676c.weightx = 0.0;2677c.gridwidth = 1;2678char umnemonic = getMnemonic("label.username");2679lblUserName = new JLabel(getMsg("label.username"), JLabel.TRAILING);2680lblUserName.setDisplayedMnemonic(umnemonic);2681addToGB(lblUserName, this, gridbag, c);2682c.gridwidth = GridBagConstraints.REMAINDER;2683tfUserName = new JTextField();2684lblUserName.setLabelFor(tfUserName);2685tfUserName.addFocusListener(this);2686tfUserName.setFocusAccelerator(umnemonic);2687tfUserName.getAccessibleContext().setAccessibleName(2688getMsg("label.username"));2689addToGB(tfUserName, this, gridbag, c);2690}26912692public void actionPerformed(ActionEvent e) {2693if (cbJobSheets.isSelected()) {2694asCurrent.add(JobSheets.STANDARD);2695} else {2696asCurrent.add(JobSheets.NONE);2697}2698}26992700public void stateChanged(ChangeEvent e) {2701asCurrent.add(new JobPriority(snModel.getNumber().intValue()));2702}27032704public void focusLost(FocusEvent e) {2705Object source = e.getSource();27062707if (source == tfJobName) {2708asCurrent.add(new JobName(tfJobName.getText(),2709Locale.getDefault()));2710} else if (source == tfUserName) {2711asCurrent.add(new RequestingUserName(tfUserName.getText(),2712Locale.getDefault()));2713}2714}27152716public void focusGained(FocusEvent e) {}27172718public void updateInfo() {2719Class jsCategory = JobSheets.class;2720Class jpCategory = JobPriority.class;2721Class jnCategory = JobName.class;2722Class unCategory = RequestingUserName.class;2723boolean jsSupported = false;2724boolean jpSupported = false;2725boolean jnSupported = false;2726boolean unSupported = false;27272728// setup JobSheets checkbox2729if (psCurrent.isAttributeCategorySupported(jsCategory)) {2730jsSupported = true;2731}2732JobSheets js = (JobSheets)asCurrent.get(jsCategory);2733if (js == null) {2734js = (JobSheets)psCurrent.getDefaultAttributeValue(jsCategory);2735if (js == null) {2736js = JobSheets.NONE;2737}2738}2739cbJobSheets.setSelected(js != JobSheets.NONE);2740cbJobSheets.setEnabled(jsSupported);27412742// setup JobPriority spinner2743if (!isAWT && psCurrent.isAttributeCategorySupported(jpCategory)) {2744jpSupported = true;2745}2746JobPriority jp = (JobPriority)asCurrent.get(jpCategory);2747if (jp == null) {2748jp = (JobPriority)psCurrent.getDefaultAttributeValue(jpCategory);2749if (jp == null) {2750jp = new JobPriority(1);2751}2752}2753int value = jp.getValue();2754if ((value < 1) || (value > 100)) {2755value = 1;2756}2757snModel.setValue(new Integer(value));2758lblPriority.setEnabled(jpSupported);2759spinPriority.setEnabled(jpSupported);27602761// setup JobName text field2762if (psCurrent.isAttributeCategorySupported(jnCategory)) {2763jnSupported = true;2764}2765JobName jn = (JobName)asCurrent.get(jnCategory);2766if (jn == null) {2767jn = (JobName)psCurrent.getDefaultAttributeValue(jnCategory);2768if (jn == null) {2769jn = new JobName("", Locale.getDefault());2770}2771}2772tfJobName.setText(jn.getValue());2773tfJobName.setEnabled(jnSupported);2774lblJobName.setEnabled(jnSupported);27752776// setup RequestingUserName text field2777if (!isAWT && psCurrent.isAttributeCategorySupported(unCategory)) {2778unSupported = true;2779}2780RequestingUserName un = (RequestingUserName)asCurrent.get(unCategory);2781if (un == null) {2782un = (RequestingUserName)psCurrent.getDefaultAttributeValue(unCategory);2783if (un == null) {2784un = new RequestingUserName("", Locale.getDefault());2785}2786}2787tfUserName.setText(un.getValue());2788tfUserName.setEnabled(unSupported);2789lblUserName.setEnabled(unSupported);2790}2791}27922793279427952796/**2797* A special widget that groups a JRadioButton with an associated icon,2798* placed to the left of the radio button.2799*/2800private class IconRadioButton extends JPanel {28012802private JRadioButton rb;2803private JLabel lbl;28042805public IconRadioButton(String key, String img, boolean selected,2806ButtonGroup bg, ActionListener al)2807{2808super(new FlowLayout(FlowLayout.LEADING));2809final URL imgURL = getImageResource(img);2810Icon icon = (Icon)java.security.AccessController.doPrivileged(2811new java.security.PrivilegedAction() {2812public Object run() {2813Icon icon = new ImageIcon(imgURL);2814return icon;2815}2816});2817lbl = new JLabel(icon);2818add(lbl);28192820rb = createRadioButton(key, al);2821rb.setSelected(selected);2822addToBG(rb, this, bg);2823}28242825public void addActionListener(ActionListener al) {2826rb.addActionListener(al);2827}28282829public boolean isSameAs(Object source) {2830return (rb == source);2831}28322833public void setEnabled(boolean enabled) {2834rb.setEnabled(enabled);2835lbl.setEnabled(enabled);2836}28372838public boolean isSelected() {2839return rb.isSelected();2840}28412842public void setSelected(boolean selected) {2843rb.setSelected(selected);2844}2845}28462847/**2848* Similar in functionality to the default JFileChooser, except this2849* chooser will pop up a "Do you want to overwrite..." dialog if the2850* user selects a file that already exists.2851*/2852private class ValidatingFileChooser extends JFileChooser {2853public void approveSelection() {2854File selected = getSelectedFile();2855boolean exists;28562857try {2858exists = selected.exists();2859} catch (SecurityException e) {2860exists = false;2861}28622863if (exists) {2864int val;2865val = JOptionPane.showConfirmDialog(this,2866getMsg("dialog.overwrite"),2867getMsg("dialog.owtitle"),2868JOptionPane.YES_NO_OPTION);2869if (val != JOptionPane.YES_OPTION) {2870return;2871}2872}28732874try {2875if (selected.createNewFile()) {2876selected.delete();2877}2878} catch (IOException ioe) {2879JOptionPane.showMessageDialog(this,2880getMsg("dialog.writeerror")+" "+selected,2881getMsg("dialog.owtitle"),2882JOptionPane.WARNING_MESSAGE);2883return;2884} catch (SecurityException se) {2885//There is already file read/write access so at this point2886// only delete access is denied. Just ignore it because in2887// most cases the file created in createNewFile gets2888// overwritten anyway.2889}2890File pFile = selected.getParentFile();2891if ((selected.exists() &&2892(!selected.isFile() || !selected.canWrite())) ||2893((pFile != null) &&2894(!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {2895JOptionPane.showMessageDialog(this,2896getMsg("dialog.writeerror")+" "+selected,2897getMsg("dialog.owtitle"),2898JOptionPane.WARNING_MESSAGE);2899return;2900}29012902super.approveSelection();2903}2904}2905}290629072908