Source for gnu.javax.print.PrinterDialog

   1: /* PrinterDialog.java --
   2:    Copyright (C) 2006, 2010  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.javax.print;
  39: 
  40: import java.awt.BorderLayout;
  41: import java.awt.Dimension;
  42: import java.awt.Frame;
  43: import java.awt.GraphicsConfiguration;
  44: import java.awt.GridBagConstraints;
  45: import java.awt.GridBagLayout;
  46: import java.awt.HeadlessException;
  47: import java.awt.Insets;
  48: import java.awt.event.ActionEvent;
  49: import java.awt.event.ActionListener;
  50: import java.awt.event.FocusEvent;
  51: import java.awt.event.FocusListener;
  52: import java.util.ArrayList;
  53: import java.util.ResourceBundle;
  54: 
  55: import javax.print.DocFlavor;
  56: import javax.print.PrintService;
  57: import javax.print.attribute.Attribute;
  58: import javax.print.attribute.HashPrintRequestAttributeSet;
  59: import javax.print.attribute.PrintRequestAttributeSet;
  60: import javax.print.attribute.standard.Chromaticity;
  61: import javax.print.attribute.standard.Copies;
  62: import javax.print.attribute.standard.Destination;
  63: import javax.print.attribute.standard.JobName;
  64: import javax.print.attribute.standard.JobPriority;
  65: import javax.print.attribute.standard.JobSheets;
  66: import javax.print.attribute.standard.Media;
  67: import javax.print.attribute.standard.MediaPrintableArea;
  68: import javax.print.attribute.standard.OrientationRequested;
  69: import javax.print.attribute.standard.PageRanges;
  70: import javax.print.attribute.standard.PrintQuality;
  71: import javax.print.attribute.standard.PrinterInfo;
  72: import javax.print.attribute.standard.PrinterIsAcceptingJobs;
  73: import javax.print.attribute.standard.PrinterMakeAndModel;
  74: import javax.print.attribute.standard.PrinterState;
  75: import javax.print.attribute.standard.RequestingUserName;
  76: import javax.print.attribute.standard.SheetCollate;
  77: import javax.print.attribute.standard.Sides;
  78: import javax.swing.BorderFactory;
  79: import javax.swing.Box;
  80: import javax.swing.BoxLayout;
  81: import javax.swing.ButtonGroup;
  82: import javax.swing.JButton;
  83: import javax.swing.JCheckBox;
  84: import javax.swing.JComboBox;
  85: import javax.swing.JDialog;
  86: import javax.swing.JLabel;
  87: import javax.swing.JPanel;
  88: import javax.swing.JRadioButton;
  89: import javax.swing.JSpinner;
  90: import javax.swing.JTabbedPane;
  91: import javax.swing.JTextField;
  92: import javax.swing.SpinnerNumberModel;
  93: import javax.swing.border.TitledBorder;
  94: import javax.swing.event.ChangeEvent;
  95: import javax.swing.event.ChangeListener;
  96: 
  97: /**
  98:  * Implementation of the PrinterDialog used by
  99:  * {@link javax.print.ServiceUI} for visual selection
 100:  * of print services and its attributes.
 101:  *
 102:  * @author Wolfgang Baer (WBaer@gmx.de)
 103:  */
 104: public final class PrinterDialog extends JDialog implements ActionListener
 105: {
 106: 
 107:   /**
 108:    * The General Panel used in the printing dialog.
 109:    * @author Wolfgang Baer (WBaer@gmx.de)
 110:    */
 111:   final class GeneralPanel extends JPanel
 112:   {
 113:     /**
 114:      * Handles the copies attribute.
 115:      * @author Wolfgang Baer (WBaer@gmx.de)
 116:      */
 117:     final class CopiesAndSorted extends JPanel
 118:       implements ChangeListener, ActionListener
 119:     {
 120:       private JCheckBox sort;
 121:       private JSpinner copies;
 122:       private JLabel copies_lb;
 123:       private SpinnerNumberModel copiesModel;
 124: 
 125:       CopiesAndSorted()
 126:       {
 127:         copies_lb = new JLabel(getLocalizedString("lb.copies"));
 128:         sort = new JCheckBox(getLocalizedString("cb.sort"));
 129:         sort.addActionListener(this);
 130: 
 131:         copiesModel = new SpinnerNumberModel(1, 1, 9999, 1);
 132:         copies = new JSpinner(copiesModel);
 133:         copies.addChangeListener(this);
 134: 
 135:         GridBagLayout layout = new GridBagLayout();
 136:         GridBagConstraints c = new GridBagConstraints();
 137:         c.fill = GridBagConstraints.BOTH;
 138:         c.insets = new Insets(5, 5, 5, 5);
 139: 
 140:         setLayout(layout);
 141:         setBorder(new TitledBorder(getLocalizedString("title.copies")));
 142: 
 143:         c.anchor = GridBagConstraints.WEST;
 144: 
 145:         c.gridx = 0;
 146:         c.gridy = 0;
 147:         add(copies_lb, c);
 148: 
 149:         c.gridx = 1;
 150:         c.gridy = 0;
 151:         add(copies, c);
 152: 
 153:         c.gridx = 0;
 154:         c.gridy = 1;
 155:         add(sort, c);
 156:       }
 157: 
 158:       // copies jspinner state
 159:       public void stateChanged(ChangeEvent event)
 160:       {
 161:         int value = ((Integer) copies.getValue()).intValue();
 162:         atts.add(new Copies(value));
 163: 
 164:         if (value > 1 && categorySupported(SheetCollate.class))
 165:           sort.setEnabled(true);
 166:         else
 167:           sort.setEnabled(false);
 168:       }
 169: 
 170:       // sorted checkbox state
 171:       public void actionPerformed(ActionEvent event)
 172:       {
 173:         if (sort.isSelected())
 174:           atts.add(SheetCollate.COLLATED);
 175:       }
 176: 
 177:       /**
 178:        * Called to update for new selected
 179:        * print service. Tests if currently
 180:        * selected attributes are supported.
 181:        */
 182:       void updateForSelectedService()
 183:       {
 184:         if (categorySupported(Copies.class))
 185:           {
 186:             copies.setEnabled(true);
 187:             copies_lb.setEnabled(true);
 188: 
 189:             Copies copies = (Copies) attribute(Copies.class);
 190:             if (copies != null)
 191:               copiesModel.setValue(new Integer(copies.getValue()));
 192: 
 193:             if (((Integer)copiesModel.getValue()).intValue() > 1
 194:                 && categorySupported(SheetCollate.class))
 195:               {
 196:                 sort.setEnabled(true);
 197:                 Attribute collate = attribute(SheetCollate.class);
 198:                 if (collate != null && collate.equals(SheetCollate.COLLATED))
 199:                   sort.setSelected(true);
 200:               }
 201:             else
 202:               sort.setEnabled(false);
 203:           }
 204:         else
 205:           {
 206:             copies.setEnabled(false);
 207:             copies_lb.setEnabled(false);
 208:           }
 209:       }
 210:     }
 211: 
 212:     /**
 213:      * Handles the print ranges attribute.
 214:      * @author Wolfgang Baer (WBaer@gmx.de)
 215:      */
 216:     final class PrintRange extends JPanel
 217:       implements ActionListener, FocusListener
 218:     {
 219:       private JLabel to;
 220:       private JRadioButton all_rb, pages_rb;
 221:       private JTextField from_tf, to_tf;
 222: 
 223:       PrintRange()
 224:       {
 225:         to = new JLabel(getLocalizedString("lb.to"));
 226:         to.setEnabled(false);
 227: 
 228:         all_rb = new JRadioButton(getLocalizedString("rbt.all"));
 229:         all_rb.setSelected(true);
 230:         all_rb.setActionCommand("ALL");
 231:         all_rb.addActionListener(this);
 232:         pages_rb = new JRadioButton(getLocalizedString("rbt.pages"));
 233:         pages_rb.setActionCommand("PAGES");
 234:         pages_rb.setEnabled(false);
 235:         pages_rb.addActionListener(this);
 236: 
 237:         ButtonGroup group = new ButtonGroup();
 238:         group.add(all_rb);
 239:         group.add(pages_rb);
 240: 
 241:         from_tf = new JTextField("1", 4);
 242:         from_tf.setEnabled(false);
 243:         from_tf.addFocusListener(this);
 244:         to_tf = new JTextField("1", 4);
 245:         to_tf.setEnabled(false);
 246:         to_tf.addFocusListener(this);
 247: 
 248:         GridBagLayout layout = new GridBagLayout();
 249:         GridBagConstraints c = new GridBagConstraints();
 250:         c.fill = GridBagConstraints.BOTH;
 251: 
 252:         setLayout(layout);
 253:         setBorder(new TitledBorder(getLocalizedString("title.printrange")));
 254: 
 255:         c.insets = new Insets(15, 5, 5, 5);
 256:         c.gridx = 0;
 257:         c.gridy = 0;
 258:         add(all_rb, c);
 259: 
 260:         c.insets = new Insets(5, 5, 15, 5);
 261:         c.gridx = 0;
 262:         c.gridy = 1;
 263:         add(pages_rb, c);
 264: 
 265:         c.gridx = 1;
 266:         c.gridy = 1;
 267:         add(from_tf, c);
 268: 
 269:         c.gridx = 2;
 270:         c.gridy = 1;
 271:         add(to, c);
 272: 
 273:         c.insets = new Insets(5, 5, 15, 15);
 274:         c.gridx = 3;
 275:         c.gridy = 1;
 276:         add(to_tf, c);
 277:       }
 278: 
 279:       // focus pagerange
 280:       public void focusGained(FocusEvent event)
 281:       {
 282:         updatePageRanges();
 283:       }
 284: 
 285:       public void focusLost(FocusEvent event)
 286:       {
 287:         updatePageRanges();
 288:       }
 289: 
 290:       // updates the range after user changed it
 291:       private void updatePageRanges()
 292:       {
 293:         int lower = Integer.parseInt(from_tf.getText());
 294:         int upper = Integer.parseInt(to_tf.getText());
 295: 
 296:         if (lower > upper)
 297:           {
 298:             upper = lower;
 299:             to_tf.setText("" + lower);
 300:           }
 301: 
 302:         PageRanges range = new PageRanges(lower, upper);
 303:         atts.add(range);
 304:       }
 305: 
 306:       // page range change
 307:       public void actionPerformed(ActionEvent e)
 308:       {
 309:         // if ALL is selected we must use a full-range object
 310:         if (e.getActionCommand().equals("ALL"))
 311:           {
 312:             from_tf.setEnabled(false);
 313:             to.setEnabled(false);
 314:             to_tf.setEnabled(false);
 315: 
 316:             atts.add(new PageRanges(1, Integer.MAX_VALUE));
 317:           }
 318:         else
 319:           {
 320:             from_tf.setEnabled(true);
 321:             to.setEnabled(true);
 322:             to_tf.setEnabled(true);
 323:             all_rb.setSelected(false);
 324:           }
 325:       }
 326: 
 327:       /**
 328:        * Called to update for new selected
 329:        * print service. Tests if currently
 330:        * selected attributes are supported.
 331:        */
 332:       void updateForSelectedService()
 333:       {
 334:         if (categorySupported(PageRanges.class))
 335:           {
 336:             pages_rb.setEnabled(true);
 337:             PageRanges range = (PageRanges) attribute(PageRanges.class);
 338:             if (range != null)
 339:               {
 340:                 from_tf.setEnabled(true);
 341:                 to.setEnabled(true);
 342:                 to_tf.setEnabled(true);
 343:                 all_rb.setSelected(false);
 344:                 pages_rb.setSelected(true);
 345: 
 346:                 int[][] members = range.getMembers();
 347:                 // Although passed in attributes may contain more than one
 348:                 // range we only take the first one
 349:                 from_tf.setText("" + members[0][0]);
 350:                 to_tf.setText("" + members[0][1]);
 351:               }
 352:           }
 353:         else
 354:           {
 355:             from_tf.setEnabled(false);
 356:             to.setEnabled(false);
 357:             to_tf.setEnabled(false);
 358:             all_rb.setSelected(true);
 359:           }
 360:        }
 361:     }
 362: 
 363:     /**
 364:      * Handles the selection of the print services
 365:      * and its location and description attributes.
 366:      * @author Wolfgang Baer (WBaer@gmx.de)
 367:      */
 368:     final class PrintServices extends JPanel
 369:       implements ActionListener
 370:     {
 371:       private JLabel name, status, typ, info;
 372:       private JLabel statusValue, typValue, infoValue;
 373:       private JButton attributes;
 374:       private JComboBox services_cob;
 375:       private JCheckBox fileRedirection_cb;
 376: 
 377:       PrintServices()
 378:       {
 379:         name = new JLabel(getLocalizedString("lb.name"));
 380:         status = new JLabel(getLocalizedString("lb.status"));
 381:         typ = new JLabel(getLocalizedString("lb.typ"));
 382:         info = new JLabel(getLocalizedString("lb.info"));
 383:         typValue = new JLabel();
 384:         infoValue = new JLabel();
 385:         statusValue = new JLabel();
 386: 
 387:         attributes = new JButton(getLocalizedString("bt.attributes"));
 388:         attributes.setEnabled(false);
 389:         attributes.setActionCommand("ATTRIBUTES");
 390:         attributes.addActionListener(this);
 391: 
 392:         services_cob = new JComboBox(getPrintServices());
 393:         services_cob.setActionCommand("SERVICE");
 394:         services_cob.addActionListener(this);
 395: 
 396:         fileRedirection_cb = new JCheckBox(getLocalizedString("cb.output"));
 397:         fileRedirection_cb.setEnabled(false);
 398: 
 399:         GridBagLayout layout = new GridBagLayout();
 400:         GridBagConstraints c = new GridBagConstraints();
 401: 
 402:         setLayout(layout);
 403:         setBorder(new TitledBorder(getLocalizedString("title.printservice")));
 404: 
 405:         c.insets = new Insets(5, 5, 5, 5);
 406:         c.anchor = GridBagConstraints.LINE_END;
 407:         c.gridx = 0;
 408:         c.gridy = 0;
 409:         add(name, c);
 410: 
 411:         c.gridx = 0;
 412:         c.gridy = 1;
 413:         add(status, c);
 414: 
 415:         c.gridx = 0;
 416:         c.gridy = 2;
 417:         add(typ, c);
 418: 
 419:         c.gridx = 0;
 420:         c.gridy = 3;
 421:         add(info, c);
 422: 
 423:         c.gridx = 2;
 424:         c.gridy = 3;
 425:         c.weightx = 1;
 426:         add(fileRedirection_cb, c);
 427: 
 428:         c.anchor = GridBagConstraints.LINE_START;
 429:         c.fill = GridBagConstraints.HORIZONTAL;
 430:         c.gridx = 1;
 431:         c.gridy = 0;
 432:         c.weightx = 1.5;
 433:         add(services_cob, c);
 434: 
 435:         c.gridx = 1;
 436:         c.gridy = 1;
 437:         c.gridwidth = 2;
 438:         c.weightx = 1;
 439:         add(statusValue, c);
 440: 
 441:         c.gridx = 1;
 442:         c.gridy = 2;
 443:         c.gridwidth = 2;
 444:         c.weightx = 1;
 445:         add(typValue, c);
 446: 
 447:         c.gridx = 1;
 448:         c.gridy = 3;
 449:         c.gridwidth = 2;
 450:         c.weightx = 1;
 451:         add(infoValue, c);
 452: 
 453:         c.gridx = 2;
 454:         c.gridy = 0;
 455:         c.weightx = 1.5;
 456:         add(attributes, c);
 457:       }
 458: 
 459:       public void actionPerformed(ActionEvent e)
 460:       {
 461:         if (e.getActionCommand().equals("SERVICE"))
 462:           {
 463:             setSelectedPrintService((PrintService) services_cob.getSelectedItem());
 464:             updateAll();
 465:           }
 466:         else if (e.getActionCommand().equals("ATTRIBUTES"))
 467:           {
 468:             // TODO LowPriority-Enhancement: As tests have shown this button
 469:             // is even gray and not enabled under Windows - Its a good place
 470:             // to provide a classpath specific browsing dialog for all
 471:             // attributes not in the default printing dialog.
 472:           }
 473:       }
 474: 
 475:       /**
 476:        * Called to update for new selected
 477:        * print service. Tests if currently
 478:        * selected attributes are supported.
 479:        */
 480:       void updateForSelectedService()
 481:       {
 482:         PrinterMakeAndModel att1 =
 483:           getSelectedPrintService().getAttribute(PrinterMakeAndModel.class);
 484:         typValue.setText(att1 == null ? "" : att1.getValue());
 485: 
 486:         PrinterInfo att2 =
 487:           getSelectedPrintService().getAttribute(PrinterInfo.class);
 488:         infoValue.setText(att2 == null ? "" : att2.getValue());
 489: 
 490:         PrinterIsAcceptingJobs att3 =
 491:           getSelectedPrintService().getAttribute(PrinterIsAcceptingJobs.class);
 492:         PrinterState att4 =
 493:           getSelectedPrintService().getAttribute(PrinterState.class);
 494: 
 495:         String status = att4.toString();
 496:         if (att3 == PrinterIsAcceptingJobs.ACCEPTING_JOBS)
 497:           status += " - " + getLocalizedString("lb.acceptingjobs");
 498:         else if (att3 == PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS)
 499:           status += " - " + getLocalizedString("lb.notacceptingjobs");
 500: 
 501:         statusValue.setText(status);
 502: 
 503:         if (categorySupported(Destination.class))
 504:           {
 505:             fileRedirection_cb.setEnabled(false);
 506:           }
 507:       }
 508: 
 509:     }
 510: 
 511:     private PrintServices printserv_panel;
 512:     private PrintRange printrange_panel;
 513:     private CopiesAndSorted copies;
 514: 
 515:     /**
 516:      * Constructs the General Panel.
 517:      */
 518:     public GeneralPanel()
 519:     {
 520:       setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 521: 
 522:       printserv_panel = new PrintServices();
 523:       printrange_panel = new PrintRange();
 524:       copies = new CopiesAndSorted();
 525: 
 526:       JPanel layout_panel = new JPanel();
 527:       layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS));
 528:       layout_panel.add(printrange_panel);
 529:       layout_panel.add(Box.createRigidArea(new Dimension(10, 0)));
 530:       layout_panel.add(copies);
 531: 
 532:       setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
 533:       add(printserv_panel);
 534:       add(Box.createRigidArea(new Dimension(0, 12)));
 535:       add(layout_panel);
 536:     }
 537: 
 538:     /**
 539:      * Calls update on all internal panels to adjust
 540:      * for a new selected print service.
 541:      */
 542:     void update()
 543:     {
 544:       printserv_panel.updateForSelectedService();
 545:       printrange_panel.updateForSelectedService();
 546:       copies.updateForSelectedService();
 547:     }
 548:   }
 549: 
 550:   /**
 551:    * The Page setup Panel.
 552:    * @author Wolfgang Baer (WBaer@gmx.de)
 553:    */
 554:   final class PageSetupPanel extends JPanel
 555:   {
 556:     /**
 557:      * Handles the orientation attribute.
 558:      * @author Wolfgang Baer (WBaer@gmx.de)
 559:      */
 560:     final class Orientation extends JPanel implements ActionListener
 561:     {
 562:       private JRadioButton portrait, landscape, rev_portrait, rev_landscape;
 563: 
 564:       Orientation()
 565:       {
 566:         portrait = new JRadioButton(getLocalizedString("rbt.portrait"));
 567:         portrait.addActionListener(this);
 568:         landscape = new JRadioButton(getLocalizedString("rbt.landscape"));
 569:         landscape.addActionListener(this);
 570:         rev_portrait = new JRadioButton(getLocalizedString("rbt.revportrait"));
 571:         rev_portrait.addActionListener(this);
 572:         rev_landscape = new JRadioButton(getLocalizedString("rbt.revlandscape"));
 573:         rev_landscape.addActionListener(this);
 574: 
 575:         ButtonGroup group = new ButtonGroup();
 576:         group.add(portrait);
 577:         group.add(landscape);
 578:         group.add(rev_portrait);
 579:         group.add(rev_landscape);
 580: 
 581:         GridBagLayout layout = new GridBagLayout();
 582:         GridBagConstraints c = new GridBagConstraints();
 583:         c.fill = GridBagConstraints.BOTH;
 584: 
 585:         setLayout(layout);
 586:         setBorder(new TitledBorder(getLocalizedString("title.orientation")));
 587: 
 588:         c.insets = new Insets(5, 5, 5, 5);
 589:         c.gridx = 0;
 590:         c.gridy = 0;
 591:         add(portrait, c);
 592: 
 593:         c.gridx = 0;
 594:         c.gridy = 1;
 595:         add(landscape, c);
 596: 
 597:         c.gridx = 0;
 598:         c.gridy = 2;
 599:         add(rev_portrait, c);
 600: 
 601:         c.gridx = 0;
 602:         c.gridy = 3;
 603:         add(rev_landscape, c);
 604:       }
 605: 
 606:       // event handling orientation
 607:       public void actionPerformed(ActionEvent e)
 608:       {
 609:         if (e.getSource() == portrait)
 610:           atts.add(OrientationRequested.PORTRAIT);
 611:         else if (e.getSource() == landscape)
 612:           atts.add(OrientationRequested.LANDSCAPE);
 613:         else if (e.getSource() == rev_portrait)
 614:           atts.add(OrientationRequested.REVERSE_PORTRAIT);
 615:         else
 616:           atts.add(OrientationRequested.REVERSE_LANDSCAPE);
 617:       }
 618: 
 619:       /**
 620:        * Called to update for new selected
 621:        * print service. Tests if currently
 622:        * selected attributes are supported.
 623:        */
 624:       void updateForSelectedService()
 625:       {
 626:         if (categorySupported(OrientationRequested.class))
 627:           {
 628:             portrait.setEnabled(true);
 629:             landscape.setEnabled(true);
 630:             rev_landscape.setEnabled(true);
 631:             rev_portrait.setEnabled(true);
 632: 
 633:             Attribute orientation = attribute(OrientationRequested.class);
 634:             if (orientation != null)
 635:               {
 636:                 if (orientation.equals(OrientationRequested.LANDSCAPE))
 637:                   landscape.setSelected(true);
 638:                 else if (orientation.equals(OrientationRequested.PORTRAIT))
 639:                   portrait.setSelected(true);
 640:                 else if (orientation.equals(OrientationRequested.REVERSE_PORTRAIT))
 641:                   rev_portrait.setSelected(true);
 642:                 else
 643:                   rev_landscape.setSelected(true);
 644:               }
 645:             else
 646:               {
 647:                 Object defaultValue = defaultValue(OrientationRequested.class);
 648:                 if (defaultValue.equals(OrientationRequested.LANDSCAPE))
 649:                   landscape.setSelected(true);
 650:                 else if (defaultValue.equals(OrientationRequested.PORTRAIT))
 651:                   portrait.setSelected(true);
 652:                 else if (defaultValue.equals(OrientationRequested.REVERSE_PORTRAIT))
 653:                   rev_portrait.setSelected(true);
 654:                 else
 655:                   rev_landscape.setSelected(true);
 656:               }
 657:           }
 658:         else
 659:           {
 660:             portrait.setEnabled(false);
 661:             landscape.setEnabled(false);
 662:             rev_landscape.setEnabled(false);
 663:             rev_portrait.setEnabled(false);
 664:           }
 665:       }
 666:     }
 667: 
 668:     /**
 669:      * Handles the media attribute.
 670:      * @author Wolfgang Baer (WBaer@gmx.de)
 671:      */
 672:     final class MediaTypes extends JPanel implements ActionListener
 673:     {
 674:       private JLabel size_lb, source_lb;
 675:       private JComboBox size, source;
 676: 
 677:       MediaTypes()
 678:       {
 679:         size_lb = new JLabel(getLocalizedString("lb.size"));
 680:         source_lb = new JLabel(getLocalizedString("lb.source"));
 681: 
 682:         size = new JComboBox();
 683:         size.setEditable(false);
 684:         size.addActionListener(this);
 685:         source = new JComboBox();
 686:         source.setEditable(false);
 687:         size.addActionListener(this);
 688: 
 689:         GridBagLayout layout = new GridBagLayout();
 690:         GridBagConstraints c = new GridBagConstraints();
 691: 
 692:         setLayout(layout);
 693:         setBorder(new TitledBorder(getLocalizedString("title.medias")));
 694: 
 695:         c.insets = new Insets(5, 5, 5, 5);
 696:         c.anchor = GridBagConstraints.LINE_END;
 697:         c.gridx = 0;
 698:         c.gridy = 0;
 699:         add(size_lb, c);
 700: 
 701:         c.gridx = 0;
 702:         c.gridy = 1;
 703:         add(source_lb, c);
 704: 
 705:         c.anchor = GridBagConstraints.LINE_START;
 706:         c.fill = GridBagConstraints.HORIZONTAL;
 707:         c.gridx = 1;
 708:         c.gridy = 0;
 709:         c.weightx = 1.5;
 710:         add(size, c);
 711: 
 712:         c.gridx = 1;
 713:         c.gridy = 1;
 714:         c.weightx = 1.5;
 715:         add(source, c);
 716:       }
 717: 
 718:       public void actionPerformed(ActionEvent event)
 719:       {
 720:         if (event.getSource() == size)
 721:           {
 722:             Object obj = size.getSelectedItem();
 723:             if (obj instanceof Media)
 724:               atts.add((Media) obj);
 725:           }
 726: 
 727:         // we ignore source events currently
 728:         // as only the automatic selection is used.
 729:       }
 730: 
 731:       /**
 732:        * Called to update for new selected
 733:        * print service. Tests if currently
 734:        * selected attributes are supported.
 735:        */
 736:       void updateForSelectedService()
 737:       {
 738:         if (categorySupported(Media.class))
 739:           {
 740:             Media[] medias = (Media[]) getSelectedPrintService()
 741:               .getSupportedAttributeValues(Media.class, flavor, null);
 742: 
 743:             size.removeAllItems();
 744:             if (medias.length == 0)
 745:               size.addItem(getLocalizedString("lb.automatically"));
 746:             else
 747:               for (int i=0; i < medias.length; i++)
 748:                 size.addItem(medias[i]);
 749: 
 750:             Media media = (Media) attribute(Media.class);
 751:             if (media != null)
 752:               size.setSelectedItem(media);
 753: 
 754:             // this is currently ignored
 755:             source.removeAllItems();
 756:             source.addItem(getLocalizedString("lb.automatically"));
 757:           }
 758:         else
 759:           {
 760:             size.removeAllItems();
 761:             source.removeAllItems();
 762: 
 763:             size.addItem(getLocalizedString("lb.automatically"));
 764:             source.addItem(getLocalizedString("lb.automatically"));
 765:           }
 766:        }
 767:     }
 768: 
 769:     /**
 770:      * Handles the media printable area attribute.
 771:      * @author Wolfgang Baer (WBaer@gmx.de)
 772:      */
 773:     final class Margins extends JPanel implements FocusListener
 774:     {
 775:       private JLabel left, right, top, bottom;
 776:       private JTextField left_tf, right_tf, top_tf, bottom_tf;
 777: 
 778:       Margins()
 779:       {
 780:         left = new JLabel(getLocalizedString("lb.left"));
 781:         right = new JLabel(getLocalizedString("lb.right"));
 782:         top = new JLabel(getLocalizedString("lb.top"));
 783:         bottom = new JLabel(getLocalizedString("lb.bottom"));
 784: 
 785:         left_tf = new JTextField(7);
 786:         left_tf.addFocusListener(this);
 787:         right_tf = new JTextField(7);
 788:         right_tf.addFocusListener(this);
 789:         top_tf = new JTextField(7);
 790:         top_tf.addFocusListener(this);
 791:         bottom_tf = new JTextField(7);
 792:         bottom_tf.addFocusListener(this);
 793: 
 794:         GridBagLayout layout = new GridBagLayout();
 795:         GridBagConstraints c = new GridBagConstraints();
 796: 
 797:         setLayout(layout);
 798:         setBorder(new TitledBorder(getLocalizedString("title.margins")));
 799: 
 800:         c.insets = new Insets(5, 5, 5, 5);
 801:         c.gridx = 0;
 802:         c.gridy = 0;
 803:         add(left, c);
 804: 
 805:         c.gridx = 1;
 806:         c.gridy = 0;
 807:         add(right, c);
 808: 
 809:         c.insets = new Insets(5, 5, 5, 5);
 810:         c.gridx = 0;
 811:         c.gridy = 1;
 812:         add(left_tf, c);
 813: 
 814:         c.gridx = 1;
 815:         c.gridy = 1;
 816:         add(right_tf, c);
 817: 
 818:         c.insets = new Insets(10, 5, 5, 5);
 819:         c.gridx = 0;
 820:         c.gridy = 2;
 821:         add(top, c);
 822: 
 823:         c.gridx = 1;
 824:         c.gridy = 2;
 825:         add(bottom, c);
 826: 
 827:         c.insets = new Insets(0, 5, 5, 5);
 828:         c.gridx = 0;
 829:         c.gridy = 3;
 830:         add(top_tf, c);
 831: 
 832:         c.gridx = 1;
 833:         c.gridy = 3;
 834:         add(bottom_tf, c);
 835:       }
 836: 
 837:       public void focusGained(FocusEvent event)
 838:       {
 839:         updateMargins();
 840:       }
 841: 
 842:       public void focusLost(FocusEvent event)
 843:       {
 844:         updateMargins();
 845:       }
 846: 
 847:       // updates the margins after user changed it
 848:       private void updateMargins()
 849:       {
 850:         // We currently do not support this attribute
 851:         // as it is not in the IPP spec and therefore not in CUPS
 852:       }
 853: 
 854:       /**
 855:        * Called to update for new selected
 856:        * print service. Tests if currently
 857:        * selected attributes are supported.
 858:        */
 859:       void updateForSelectedService()
 860:       {
 861:         if (categorySupported(MediaPrintableArea.class))
 862:           {
 863:             left.setEnabled(true);
 864:             right.setEnabled(true);
 865:             top.setEnabled(true);
 866:             bottom.setEnabled(true);
 867:             left_tf.setEnabled(true);
 868:             right_tf.setEnabled(true);
 869:             top_tf.setEnabled(true);
 870:             bottom_tf.setEnabled(true);
 871:           }
 872:         else
 873:           {
 874:             left.setEnabled(false);
 875:             right.setEnabled(false);
 876:             top.setEnabled(false);
 877:             bottom.setEnabled(false);
 878:             left_tf.setEnabled(false);
 879:             right_tf.setEnabled(false);
 880:             top_tf.setEnabled(false);
 881:             bottom_tf.setEnabled(false);
 882:           }
 883:        }
 884:     }
 885: 
 886:     private MediaTypes media_panel;
 887:     private Orientation orientation_panel;
 888:     private Margins margins_panel;
 889: 
 890:     /**
 891:      * Constructs the page setup user interface.
 892:      */
 893:     public PageSetupPanel()
 894:     {
 895:       setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 896: 
 897:       media_panel = new MediaTypes();
 898:       orientation_panel = new Orientation();
 899:       margins_panel = new Margins();
 900: 
 901:       JPanel layout_panel = new JPanel();
 902:       layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS));
 903:       layout_panel.add(orientation_panel);
 904:       layout_panel.add(Box.createRigidArea(new Dimension(10, 0)));
 905:       layout_panel.add(margins_panel);
 906: 
 907:       setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
 908:       add(media_panel);
 909:       add(Box.createRigidArea(new Dimension(0, 12)));
 910:       add(layout_panel);
 911:     }
 912: 
 913:     /**
 914:      * Calls update on all internal panels to adjust
 915:      * for a new selected print service.
 916:      */
 917:     void update()
 918:     {
 919:       media_panel.updateForSelectedService();
 920:       orientation_panel.updateForSelectedService();
 921:       margins_panel.updateForSelectedService();
 922:     }
 923:   }
 924: 
 925:   /**
 926:    * The Appearance panel for quality, color etc.
 927:    * @author Wolfgang Baer (WBaer@gmx.de)
 928:    */
 929:   final class AppearancePanel extends JPanel
 930:   {
 931:     /**
 932:      * Handles the print quality attribute.
 933:      * @author Wolfgang Baer (WBaer@gmx.de)
 934:      */
 935:     final class Quality extends JPanel implements ActionListener
 936:     {
 937:       private JRadioButton low, normal, high;
 938:       private ButtonGroup group;
 939: 
 940:       Quality()
 941:       {
 942:         low = new JRadioButton(getLocalizedString("rbt.low"));
 943:         low.addActionListener(this);
 944:         normal = new JRadioButton(getLocalizedString("rbt.normal"));
 945:         normal.addActionListener(this);
 946:         high = new JRadioButton(getLocalizedString("rbt.high"));
 947:         high.addActionListener(this);
 948: 
 949:         group = new ButtonGroup();
 950:         group.add(low);
 951:         group.add(normal);
 952:         group.add(high);
 953: 
 954:         GridBagLayout layout = new GridBagLayout();
 955:         GridBagConstraints c = new GridBagConstraints();
 956: 
 957:         setLayout(layout);
 958:         setBorder(new TitledBorder(getLocalizedString("title.quality")));
 959: 
 960:         c.fill = GridBagConstraints.HORIZONTAL;
 961:         c.insets = new Insets(5, 5, 5, 5);
 962:         c.gridx = 0;
 963:         c.gridy = 0;
 964:         add(low, c);
 965: 
 966:         c.gridx = 0;
 967:         c.gridy = 1;
 968:         add(normal, c);
 969: 
 970:         c.gridx = 0;
 971:         c.gridy = 2;
 972:         add(high, c);
 973:       }
 974: 
 975:       public void actionPerformed(ActionEvent e)
 976:       {
 977:         if (e.getSource() == low)
 978:           atts.add(PrintQuality.DRAFT);
 979:         else if (e.getSource() == normal)
 980:           atts.add(PrintQuality.NORMAL);
 981:         else
 982:           atts.add(PrintQuality.HIGH);
 983:       }
 984: 
 985:       /**
 986:        * Called to update for new selected
 987:        * print service. Tests if currently
 988:        * selected attributes are supported.
 989:        */
 990:       void updateForSelectedService()
 991:       {
 992:         if (categorySupported(PrintQuality.class))
 993:           {
 994:             low.setEnabled(true);
 995:             normal.setEnabled(true);
 996:             high.setEnabled(true);
 997: 
 998:             Object defaultValue = defaultValue(PrintQuality.class);
 999:             Attribute quality = attribute(PrintQuality.class);
1000: 
1001:             if (quality != null)
1002:               {
1003:                 if (quality.equals(PrintQuality.DRAFT))
1004:                   low.setSelected(true);
1005:                 else if (quality.equals(PrintQuality.NORMAL))
1006:                   normal.setSelected(true);
1007:                 else
1008:                   high.setSelected(true);
1009:               }
1010:             else
1011:               {
1012:                 if (defaultValue.equals(PrintQuality.DRAFT))
1013:                   low.setSelected(true);
1014:                 else if (defaultValue.equals(PrintQuality.NORMAL))
1015:                   normal.setSelected(true);
1016:                 else
1017:                   high.setSelected(true);
1018:               }
1019:           }
1020:         else
1021:           {
1022:             low.setEnabled(false);
1023:             normal.setEnabled(false);
1024:             high.setEnabled(false);
1025:           }
1026:       }
1027:     }
1028: 
1029:     /**
1030:      * Handles the job attributes as requesting username, jobname etc.
1031:      * @author Wolfgang Baer (WBaer@gmx.de)
1032:      */
1033:     final class JobAttributes extends JPanel
1034:       implements ActionListener, ChangeListener, FocusListener
1035:     {
1036:       private JLabel jobname, username, priority_lb;
1037:       private JTextField jobname_tf, username_tf;
1038:       private JCheckBox cover;
1039:       private JSpinner priority;
1040:       private SpinnerNumberModel model;
1041: 
1042:       JobAttributes()
1043:       {
1044:         jobname = new JLabel(getLocalizedString("lb.jobname"));
1045:         username = new JLabel(getLocalizedString("lb.username"));
1046:         priority_lb = new JLabel(getLocalizedString("lb.priority"));
1047: 
1048:         cover = new JCheckBox(getLocalizedString("cb.cover"));
1049:         cover.addActionListener(this);
1050: 
1051:         model = new SpinnerNumberModel(1, 1, 100, 1);
1052:         priority = new JSpinner(model);
1053:         priority.addChangeListener(this);
1054: 
1055:         jobname_tf = new JTextField();
1056:         jobname_tf.addFocusListener(this);
1057:         username_tf = new JTextField();
1058:         username_tf.addFocusListener(this);
1059: 
1060:         GridBagLayout layout = new GridBagLayout();
1061:         GridBagConstraints c = new GridBagConstraints();
1062: 
1063:         setLayout(layout);
1064:         setBorder(new TitledBorder(getLocalizedString("title.jobattributes")));
1065: 
1066:         c.insets = new Insets(10, 5, 10, 5);
1067:         c.gridx = 0;
1068:         c.gridy = 0;
1069:         add(cover, c);
1070: 
1071:         c.anchor = GridBagConstraints.LINE_END;
1072:         c.gridx = 1;
1073:         c.gridy = 0;
1074:         c.weightx = 2;
1075:         add(priority_lb, c);
1076: 
1077:         c.gridx = 2;
1078:         c.gridy = 0;
1079:         c.weightx = 0.5;
1080:         add(priority, c);
1081: 
1082:         c.anchor = GridBagConstraints.LINE_END;
1083:         c.gridx = 0;
1084:         c.gridy = 1;
1085:         add(jobname, c);
1086: 
1087:         c.gridx = 0;
1088:         c.gridy = 2;
1089:         add(username, c);
1090: 
1091:         c.anchor = GridBagConstraints.CENTER;
1092:         c.fill = GridBagConstraints.HORIZONTAL;
1093:         c.gridx = 1;
1094:         c.gridy = 1;
1095:         c.gridwidth = 2;
1096:         c.weightx = 1.5;
1097:         add(jobname_tf, c);
1098: 
1099:         c.insets = new Insets(10, 5, 15, 5);
1100:         c.gridx = 1;
1101:         c.gridy = 2;
1102:         add(username_tf, c);
1103:       }
1104: 
1105:       public void actionPerformed(ActionEvent event)
1106:       {
1107:         if (cover.isSelected())
1108:           atts.add(JobSheets.STANDARD);
1109:         else
1110:           atts.add(JobSheets.NONE);
1111:       }
1112: 
1113:       public void stateChanged(ChangeEvent event)
1114:       {
1115:         int value = ((Integer) priority.getValue()).intValue();
1116:         atts.add(new JobPriority(value));
1117:       }
1118: 
1119:       public void focusGained(FocusEvent event)
1120:       {
1121:         updateTextfields(event);
1122:       }
1123: 
1124:       public void focusLost(FocusEvent event)
1125:       {
1126:         updateTextfields(event);
1127:       }
1128: 
1129:       private void updateTextfields(FocusEvent event)
1130:       {
1131:         if (event.getSource() == jobname_tf)
1132:             atts.add(new JobName(jobname_tf.getText(), null));
1133:         else
1134:             atts.add(new RequestingUserName(username_tf.getText(), null));
1135:       }
1136: 
1137:       /**
1138:        * Called to update for new selected
1139:        * print service. Tests if currently
1140:        * selected attributes are supported.
1141:        */
1142:       void updateForSelectedService()
1143:       {
1144:         // JobPriority
1145:         if (categorySupported(JobPriority.class))
1146:           {
1147:             JobPriority prio = (JobPriority) attribute(JobPriority.class);
1148:             JobPriority value = (JobPriority) defaultValue(JobPriority.class);
1149:             priority.setEnabled(true);
1150:             if (prio != null)
1151:               model.setValue(new Integer(prio.getValue()));
1152:             else
1153:               model.setValue(new Integer(value.getValue()));
1154:           }
1155:         else
1156:           priority.setEnabled(false);
1157: 
1158:         // Requesting username
1159:         if (categorySupported(RequestingUserName.class))
1160:           {
1161:             Attribute user = attribute(RequestingUserName.class);
1162:             Object value = defaultValue(RequestingUserName.class);
1163:             username.setEnabled(true);
1164:             if (user != null)
1165:               username_tf.setText(user.toString());
1166:             else
1167:               username_tf.setText(value.toString());
1168:           }
1169:         else
1170:           username.setEnabled(false);
1171: 
1172:         // Job Name
1173:         if (categorySupported(JobName.class))
1174:           {
1175:             Attribute job = attribute(JobName.class);
1176:             Object value = defaultValue(JobName.class);
1177:             jobname.setEnabled(true);
1178:             if (job != null)
1179:               jobname_tf.setText(job.toString());
1180:             else
1181:               jobname_tf.setText(value.toString());
1182:           }
1183:         else
1184:           jobname.setEnabled(false);
1185: 
1186:         // Job sheets
1187:         if (categorySupported(JobSheets.class))
1188:           {
1189:             Attribute sheet = attribute(JobSheets.class);
1190:             Object value = defaultValue(JobSheets.class);
1191:             cover.setEnabled(true);
1192:             if (sheet != null)
1193:               {
1194:                 if (sheet.equals(JobSheets.NONE))
1195:                   cover.setSelected(false);
1196:                 else
1197:                   cover.setSelected(true);
1198:               }
1199:             else
1200:               {
1201:                 if (value.equals(JobSheets.NONE))
1202:                   cover.setSelected(false);
1203:                 else
1204:                   cover.setSelected(true);
1205:               }
1206:           }
1207:         else
1208:           cover.setEnabled(false);
1209:       }
1210:     }
1211: 
1212:     /**
1213:      * Handles the sides attributes.
1214:      * @author Wolfgang Baer (WBaer@gmx.de)
1215:      */
1216:     final class SidesPanel extends JPanel implements ActionListener
1217:     {
1218:       private JRadioButton oneside, calendar, duplex;
1219: 
1220:       SidesPanel()
1221:       {
1222:         oneside = new JRadioButton(getLocalizedString("rbt.onesided"));
1223:         oneside.addActionListener(this);
1224:         calendar = new JRadioButton(getLocalizedString("rbt.calendar"));
1225:         calendar.addActionListener(this);
1226:         duplex = new JRadioButton(getLocalizedString("rbt.duplex"));
1227:         duplex.addActionListener(this);
1228: 
1229:         ButtonGroup group = new ButtonGroup();
1230:         group.add(oneside);
1231:         group.add(calendar);
1232:         group.add(duplex);
1233: 
1234:         GridBagLayout layout = new GridBagLayout();
1235:         GridBagConstraints c = new GridBagConstraints();
1236:         c.fill = GridBagConstraints.BOTH;
1237: 
1238:         setLayout(layout);
1239:         setBorder(new TitledBorder(getLocalizedString("title.sides")));
1240: 
1241:         c.insets = new Insets(5, 5, 5, 5);
1242:         c.gridx = 0;
1243:         c.gridy = 0;
1244:         add(oneside, c);
1245: 
1246:         c.gridx = 0;
1247:         c.gridy = 1;
1248:         add(calendar, c);
1249: 
1250:         c.gridx = 0;
1251:         c.gridy = 2;
1252:         add(duplex, c);
1253:       }
1254: 
1255:       public void actionPerformed(ActionEvent e)
1256:       {
1257:         if (e.getSource() == calendar)
1258:           atts.add(Sides.TWO_SIDED_SHORT_EDGE);
1259:         else if (e.getSource() == oneside)
1260:           atts.add(Sides.ONE_SIDED);
1261:         else
1262:           atts.add(Sides.TWO_SIDED_LONG_EDGE);
1263:       }
1264: 
1265:       /**
1266:        * Called to update for new selected
1267:        * print service. Tests if currently
1268:        * selected attributes are supported.
1269:        */
1270:       void updateForSelectedService()
1271:       {
1272:         if (categorySupported(Sides.class))
1273:           {
1274:             oneside.setEnabled(true);
1275:             calendar.setEnabled(true);
1276:             duplex.setEnabled(true);
1277: 
1278:             Object defaultValue = defaultValue(Sides.class);
1279:             Attribute sides = attribute(Sides.class);
1280:             if (sides != null)
1281:               {
1282:                 if (sides.equals(Sides.TWO_SIDED_SHORT_EDGE))
1283:                   calendar.setSelected(true);
1284:                 else if (sides.equals(Sides.ONE_SIDED))
1285:                   oneside.setSelected(true);
1286:                 else
1287:                   duplex.setSelected(true);
1288:               }
1289:             else
1290:               {
1291:                 if (defaultValue.equals(Sides.TWO_SIDED_SHORT_EDGE))
1292:                   calendar.setSelected(true);
1293:                 else if (defaultValue.equals(Sides.ONE_SIDED))
1294:                   oneside.setSelected(true);
1295:                 else
1296:                   duplex.setSelected(true);
1297:               }
1298:           }
1299:         else
1300:           {
1301:             oneside.setEnabled(false);
1302:             calendar.setEnabled(false);
1303:             duplex.setEnabled(false);
1304:           }
1305:       }
1306:     }
1307: 
1308:     /**
1309:      * Handles the chromaticity attributes.
1310:      * @author Wolfgang Baer (WBaer@gmx.de)
1311:      */
1312:     final class Color extends JPanel implements ActionListener
1313:     {
1314:       private JRadioButton bw, color;
1315: 
1316:       Color()
1317:       {
1318:         bw = new JRadioButton(getLocalizedString("rbt.blackwhite"));
1319:         bw.addActionListener(this);
1320:         color = new JRadioButton(getLocalizedString("rbt.color"));
1321:         color.addActionListener(this);
1322: 
1323:         ButtonGroup group = new ButtonGroup();
1324:         group.add(bw);
1325:         group.add(color);
1326: 
1327:         GridBagLayout layout = new GridBagLayout();
1328:         GridBagConstraints c = new GridBagConstraints();
1329: 
1330:         setLayout(layout);
1331:         setBorder(new TitledBorder(getLocalizedString("title.color")));
1332: 
1333:         c.fill = GridBagConstraints.HORIZONTAL;
1334:         c.insets = new Insets(5, 5, 5, 5);
1335:         c.gridx = 0;
1336:         c.gridy = 0;
1337:         add(bw, c);
1338: 
1339:         c.gridx = 0;
1340:         c.gridy = 1;
1341:         add(color, c);
1342:       }
1343: 
1344:       public void actionPerformed(ActionEvent e)
1345:       {
1346:         if (e.getSource() == bw)
1347:           atts.add(Chromaticity.MONOCHROME);
1348:         else
1349:           atts.add(Chromaticity.COLOR);
1350:       }
1351: 
1352:       /**
1353:        * Called to update for new selected
1354:        * print service. Tests if currently
1355:        * selected attributes are supported.
1356:        */
1357:       void updateForSelectedService()
1358:       {
1359:         if (categorySupported(Chromaticity.class))
1360:           {
1361:             bw.setEnabled(true);
1362:             color.setEnabled(true);
1363: 
1364:             Object defaultValue = defaultValue(Chromaticity.class);
1365:             Attribute chromaticity = attribute(Chromaticity.class);
1366:             if (chromaticity != null)
1367:               {
1368:                 if (chromaticity.equals(Chromaticity.MONOCHROME))
1369:                   bw.setSelected(true);
1370:                 else
1371:                   color.setSelected(true);
1372:               }
1373:             else
1374:               {
1375:                 if (defaultValue.equals(Chromaticity.MONOCHROME))
1376:                   bw.setSelected(true);
1377:                 else
1378:                   color.setSelected(true);
1379:               }
1380:           }
1381:         else
1382:           {
1383:             bw.setEnabled(false);
1384:             color.setEnabled(false);
1385:           }
1386:       }
1387:     }
1388: 
1389:     private Quality quality_panel;
1390:     private JobAttributes jobAttr_panel;
1391:     private SidesPanel sides_panel;
1392:     private Color chromaticy_panel;
1393: 
1394:     /**
1395:      * Creates the panel for appearance attributes.
1396:      */
1397:     public AppearancePanel()
1398:     {
1399:       setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
1400: 
1401:       quality_panel = new Quality();
1402:       jobAttr_panel = new JobAttributes();
1403:       sides_panel = new SidesPanel();
1404:       chromaticy_panel = new Color();
1405: 
1406:       JPanel layout_panel = new JPanel();
1407:       layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS));
1408:       layout_panel.add(chromaticy_panel);
1409:       layout_panel.add(Box.createRigidArea(new Dimension(10, 0)));
1410:       layout_panel.add(quality_panel);
1411: 
1412:       JPanel layout2_panel = new JPanel();
1413:       layout2_panel.setLayout(new BoxLayout(layout2_panel, BoxLayout.LINE_AXIS));
1414:       layout2_panel.add(sides_panel);
1415:       layout2_panel.add(Box.createRigidArea(new Dimension(10, 0)));
1416:       layout2_panel.add(jobAttr_panel);
1417: 
1418:       setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
1419:       add(layout_panel);
1420:       add(Box.createRigidArea(new Dimension(0, 12)));
1421:       add(layout2_panel);
1422:     }
1423: 
1424:     /**
1425:      * Calls update on all internal panels to adjust
1426:      * for a new selected print service.
1427:      */
1428:     void update()
1429:     {
1430:       quality_panel.updateForSelectedService();
1431:       jobAttr_panel.updateForSelectedService();
1432:       sides_panel.updateForSelectedService();
1433:       chromaticy_panel.updateForSelectedService();
1434:     }
1435:   }
1436: 
1437:   // on main contentpane
1438:   private JButton ok_bt;
1439:   private JButton cancel_bt;
1440: 
1441:   // the tabs
1442:   private GeneralPanel general_panel;
1443:   private PageSetupPanel pagesetup_panel;
1444:   private AppearancePanel appearance_panel;
1445: 
1446:   private PrintService[] services;
1447:   private PrintService defaultService;
1448:   private PrintService selectedService;
1449:   private DocFlavor flavor;
1450:   private PrintRequestAttributeSet attributes;
1451: 
1452:   private boolean onlyPageDialog;
1453:   private PrintRequestAttributeSet atts;
1454: 
1455:   private final static ResourceBundle messages
1456:     = ResourceBundle.getBundle("gnu.javax.print.MessagesBundle");
1457: 
1458:   // TODO LowPriority: Include checks so that if a specific value formerly
1459:   // selected is no more supported by the new service changes to the default.
1460: 
1461:   /**
1462:    * Class private constructs a printer dialog.
1463:    *
1464:    * @param gc the screen to use. <code>null</code> is default screen.
1465:    * @param services the print services to browse (not null).
1466:    * @param defaultService the default service. If <code>null</code>
1467:    * the first of the print services in the services array will be used.
1468:    * @param flavor the flavours to be printed.
1469:    * @param attributes the attributes requested. Will be updated
1470:    * by selections done by the user in the dialog.
1471:    * @param onlyPageDialog if true a page settings only dialog is constructed.
1472:    *
1473:    * @throws HeadlessException if GraphicsEnvironment is headless
1474:    */
1475:   private PrinterDialog(GraphicsConfiguration gc, PrintService[] services,
1476:     PrintService defaultService, DocFlavor flavor,
1477:     PrintRequestAttributeSet attributes, boolean onlyPageDialog, String title)
1478:     throws HeadlessException
1479:   {
1480:     super((Frame)null, title, true, gc);
1481: 
1482:     setResizable(false);
1483:     setDefaultCloseOperation(DISPOSE_ON_CLOSE);
1484: 
1485:     // check and remove service not supporting the flavor
1486:     if (flavor != null)
1487:       {
1488:         ArrayList list = new ArrayList(services.length);
1489:         for(int i=0; i < services.length; i++)
1490:           if (services[i].isDocFlavorSupported(flavor))
1491:             list.add(services[i]);
1492: 
1493:         if (defaultService != null
1494:             && (! list.contains(defaultService)))
1495:           defaultService = (PrintService) list.get(0);
1496: 
1497:         PrintService[] newServices = new PrintService[list.size()];
1498:         this.services = (PrintService[]) list.toArray(newServices);
1499:       }
1500:     else
1501:       this.services = services;
1502: 
1503:     if (defaultService == null)
1504:       this.defaultService = services[0];
1505:     else
1506:       this.defaultService = defaultService;
1507: 
1508:     this.selectedService = this.defaultService;
1509:     this.flavor = flavor;
1510: 
1511:     // the attributes given by the user
1512:     this.attributes = attributes;
1513:     // the one to work with during browsing
1514:     this.atts = new HashPrintRequestAttributeSet(attributes);
1515: 
1516:     this.onlyPageDialog = onlyPageDialog;
1517: 
1518:     initUI(onlyPageDialog);
1519:     pack();
1520:     updateAll();
1521:   }
1522: 
1523:   /**
1524:    * Constructs a page settings only dialog.
1525:    *
1526:    * @param gc the screen to use. <code>null</code> is default screen.
1527:    * @param service the print service for the page dialog.
1528:    * the first of the print services in the services array will be used.
1529:    * @param flavor the flavours to be printed.
1530:    * @param attributes the attributes requested. Will be updated
1531:    * by selections done by the user in the dialog.
1532:    *
1533:    * @throws HeadlessException if GraphicsEnvironment is headless
1534:    */
1535:   public PrinterDialog(GraphicsConfiguration gc, PrintService service,
1536:     DocFlavor flavor, PrintRequestAttributeSet attributes)
1537:     throws HeadlessException
1538:   {
1539:     this(gc, new PrintService[] {service}, service, flavor, attributes,
1540:          true, getLocalizedString("title.pagedialog"));
1541:   }
1542: 
1543:   /**
1544:    * Constructs a printer dialog.
1545:    *
1546:    * @param gc the screen to use. <code>null</code> is default screen.
1547:    * @param services the print services to browse (not null).
1548:    * @param defaultService the default service. If <code>null</code>
1549:    * the first of the print services in the services array will be used.
1550:    * @param flavor the flavours to be printed.
1551:    * @param attributes the attributes requested. Will be updated
1552:    * by selections done by the user in the dialog.
1553:    *
1554:    * @throws HeadlessException if GraphicsEnvironment is headless
1555:    */
1556:   public PrinterDialog(GraphicsConfiguration gc, PrintService[] services,
1557:     PrintService defaultService, DocFlavor flavor,
1558:     PrintRequestAttributeSet attributes)
1559:     throws HeadlessException
1560:   {
1561:     this(gc, services, defaultService, flavor, attributes,
1562:          false, getLocalizedString("title.printdialog"));
1563:   }
1564: 
1565:   // initializes the gui parts
1566:   private void initUI(boolean onlyPageDialog)
1567:   {
1568:     JPanel buttonPane = new JPanel();
1569: 
1570:     if (onlyPageDialog)
1571:       {
1572:         JPanel pane = new JPanel();
1573:         pane.setLayout(new BorderLayout());
1574:         pagesetup_panel = new PageSetupPanel();
1575:         pane.add(pagesetup_panel, BorderLayout.CENTER);
1576: 
1577:         ok_bt = new JButton(getLocalizedString("bt.OK"));
1578:         ok_bt.addActionListener(this);
1579:         cancel_bt = new JButton(getLocalizedString("bt.cancel"));
1580:         cancel_bt.addActionListener(this);
1581: 
1582:         getContentPane().add(pane, BorderLayout.CENTER);
1583:       }
1584:     else
1585:       {
1586:         general_panel = new GeneralPanel();
1587:         pagesetup_panel = new PageSetupPanel();
1588:         appearance_panel = new AppearancePanel();
1589: 
1590:         JTabbedPane pane = new JTabbedPane();
1591:         pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
1592: 
1593:         ok_bt = new JButton(getLocalizedString("bt.print"));
1594:         ok_bt.addActionListener(this);
1595:         cancel_bt = new JButton(getLocalizedString("bt.cancel"));
1596:         cancel_bt.addActionListener(this);
1597: 
1598:         // populate jtabbedpane
1599:         pane.addTab(getLocalizedString("tab.general"), general_panel);
1600:         pane.addTab(getLocalizedString("tab.pagesetup"), pagesetup_panel);
1601:         pane.addTab(getLocalizedString("tab.appearance"), appearance_panel);
1602: 
1603:         // Put everything together
1604:         getContentPane().add(pane, BorderLayout.CENTER);
1605:       }
1606: 
1607:     buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
1608:     buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
1609:     buttonPane.add(Box.createHorizontalGlue());
1610:     buttonPane.add(ok_bt);
1611:     buttonPane.add(Box.createRigidArea(new Dimension(5, 0)));
1612:     buttonPane.add(cancel_bt);
1613: 
1614:     getContentPane().add(buttonPane, BorderLayout.PAGE_END);
1615:   }
1616: 
1617:   /**
1618:    * Returns the modified attributes set.
1619:    * @return The attributes.
1620:    */
1621:   public PrintRequestAttributeSet getAttributes()
1622:   {
1623:     return attributes;
1624:   }
1625: 
1626:   /**
1627:    * Returns the print service selected by the user.
1628:    * @return The selected print service.
1629:    */
1630:   public PrintService getSelectedPrintService()
1631:   {
1632:     return selectedService;
1633:   }
1634: 
1635:   /**
1636:    * Sets the currently selected print service.
1637:    *
1638:    * @param service the service selected.
1639:    */
1640:   protected void setSelectedPrintService(PrintService service)
1641:   {
1642:     selectedService = service;
1643:   }
1644: 
1645:   /**
1646:    * Returns the print service array.
1647:    * @return The print services.
1648:    */
1649:   protected PrintService[] getPrintServices()
1650:   {
1651:     return services;
1652:   }
1653: 
1654:   /**
1655:    * Calls update on all panels to adjust
1656:    * for a new selected print service.
1657:    */
1658:   void updateAll()
1659:   {
1660:     pagesetup_panel.update();
1661: 
1662:     if (! onlyPageDialog)
1663:       {
1664:         general_panel.update();
1665:         appearance_panel.update();
1666:       }
1667:   }
1668: 
1669:   boolean categorySupported(Class category)
1670:   {
1671:     return getSelectedPrintService().
1672:       isAttributeCategorySupported(category);
1673:   }
1674: 
1675:   Object defaultValue(Class category)
1676:   {
1677:     return getSelectedPrintService().
1678:       getDefaultAttributeValue(category);
1679:   }
1680: 
1681:   Attribute attribute(Class category)
1682:   {
1683:     return atts.get(category);
1684:   }
1685: 
1686:   /**
1687:    *  Action handler for Print/Cancel buttons.
1688:    *  If cancel is pressed we reset the attributes
1689:    *  and the selected service.
1690:    *
1691:    *  @param e the ActionEvent
1692:    */
1693:   public void actionPerformed(ActionEvent e)
1694:   {
1695:     if (e.getSource() == ok_bt)
1696:       {
1697:         setVisible(false);
1698:         attributes.addAll(atts);
1699:         dispose();
1700:       }
1701:     else
1702:       {
1703:         setVisible(false);
1704:         selectedService = null;
1705:         dispose();
1706:       }
1707:   }
1708: 
1709:   /**
1710:    * Retrieves localized messages from the resource bundle.
1711:    *
1712:    * @param key the key
1713:    * @return The localized value for the key.
1714:    */
1715:   static final String getLocalizedString(String key) {
1716:     return messages.getString(key);
1717:   }
1718: }