History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/print/ServiceDialog.java (1 of 18352 files). Show all

Unified · Split

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