/*  TabbedPrintDialog
    (C) Copyright 2009
    Wildcrest Associates
    http://www.wildcrest.com
This source code may be freely used, modified, incorporated, and
distributed without restriction as part of any software that uses
J2PrinterWorks by Wildcrest Associates.
*/

import com.wildcrest.j2printerworks.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.border.TitledBorder;
import javax.print.attribute.standard.*;
import javax.print.PrintService;
import javax.swing.event.*;
import javax.print.attribute.HashPrintRequestAttributeSet;
import java.awt.print.PageFormat;

public class TabbedPrintDialog extends JDialog {
   public static final int CANCEL = 0;
   public static final int PRINT = 1;

   private J2Printer14 printer;
   private Frame frame;
   private PrintRequestAttributeSet attributeSet;
   private String printerName;
   private PageFormat pageFormat;
   private JComboBox printerChoices;
   private String currentPrinter;
   private int retVal;
   private JTextField pageRangesField;
   private JRadioButton allButton, rangeButton, portraitButton, landscapeButton;
   private SpinnerNumberModel copiesSpinnerModel;
   private Integer int1 = new Integer(1);
   private Integer int999 = new Integer(999);
   private JCheckBox collateCheckBox;
   private JComboBox mediaChoices;
   private String currentMedia;
   private ImagePanel collatedImagePanel;
   private Image isCollatedImage, notCollatedImage;
   private SpinnerNumberModel leftMarginSpinnerModel, rightMarginSpinnerModel;
   private SpinnerNumberModel topMarginSpinnerModel, bottomMarginSpinnerModel;
   private int leftMinimumMargin, rightMinimumMargin, topMinimumMargin, bottomMinimumMargin;
   private JSpinner leftMarginSpinner, rightMarginSpinner, topMarginSpinner, bottomMarginSpinner;
   private JFormattedTextField leftMarginTextField, rightMarginTextField, topMarginTextField, bottomMarginTextField;
   private int halfPage;
   private JTextField leftHeaderField, centerHeaderField, rightHeaderField;
   private JTextField leftFooterField, centerFooterField, rightFooterField;
   private String leftHeaderString, centerHeaderString, rightHeaderString;
   private String leftFooterString, centerFooterString, rightFooterString;

   TabbedPrintDialog(Frame frame, J2Printer14 printer) {
      super(frame, "Print", true); // true = modal
      this.printer = printer;
      this.frame = frame;
      this.setResizable(false);

      PrintRequestAttributeSet aset = printer.getPrintRequestAttributeSet(); // pointer to printer's aset
   //tests:
      //aset.add(OrientationRequested.LANDSCAPE);
      //aset.add(MediaSizeName.NA_NUMBER_10_ENVELOPE);  // or MediaSizeName.ISO_A4, etc.
      //aset.add(new Copies(2));
      //aset.add(SheetCollate.COLLATED);
      //aset.add(new PageRanges(2,printer.getPageable().getNumberOfPages()));

      this.attributeSet = new HashPrintRequestAttributeSet(aset);
      this.printerName = printer.getPrinter();
      this.pageFormat = printer.getPageFormat();
      this.getContentPane().setLayout(new BorderLayout());
      JTabbedPane tabbedPane = new JTabbedPane();
      JPanel generalTab = new JPanel();
      JPanel pageSetupTab = new JPanel();
      JPanel headersFootersTab = new JPanel();
      generalTab.setLayout(new BorderLayout());
      pageSetupTab.setLayout(new BorderLayout());
      headersFootersTab.setLayout(new BorderLayout());

// General tab //

   // printer choices
      JPanel selectPrinterLine = new JPanel();
      selectPrinterLine.setBorder(new TitledBorder("Select Printer"));
      selectPrinterLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      printerChoices = new JComboBox(printer.getAllPrinterNames());
      printerChoices.setEditable(false);
      currentPrinter = printer.getPrinter(); // returns default printer if none specified
      printerChoices.setSelectedItem(currentPrinter);
      JPanel printerField = new JPanel();
      printerField.add(new JLabel("Name: "));
      printerField.add(printerChoices);
      selectPrinterLine.add(printerField);
      generalTab.add(selectPrinterLine, "North");

      printerChoices.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { printerChanged(); }});

   // page range
      JPanel pageRangePanel = new JPanel();
      pageRangePanel.setBorder(new TitledBorder("Page Range"));
      pageRangePanel.setLayout(new BorderLayout());

      allButton = new JRadioButton("All");
      rangeButton = new JRadioButton("Pages: ");
      ButtonGroup pagesGroup = new ButtonGroup();
      pagesGroup.add(allButton);
      pagesGroup.add(rangeButton);

      JPanel allLine = new JPanel();
      allLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      allLine.add(allButton);

      JPanel pageNumbersLine = new JPanel();
      pageNumbersLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      pageNumbersLine.add(rangeButton);
      pageRangesField = new JTextField(6);
      pageNumbersLine.add(pageRangesField);
      JLabel pageNumbersLabel = new JLabel("e.g. 1-3,6,9-12");
      pageNumbersLabel.setBackground(this.getContentPane().getBackground());
      pageNumbersLabel.setFont(new Font("SanSerif",Font.PLAIN,11));
      pageNumbersLine.add(pageNumbersLabel);

      String pageRanges = printer.getPageRanges();
      if (pageRanges.length() == 0) pageRangesField.setText("1-" + printer.getPageable().getNumberOfPages());
      else pageRangesField.setText(pageRanges);

      pageRangePanel.add(allLine, "North");
      pageRangePanel.add(pageNumbersLine, "South");

      allButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { pageRangesChanged(); }});
      rangeButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { pageRangesChanged(); }});
      pageRangesField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { pageRangesChanged(); } });
      pageRangesField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { pageRangesChanged(); }
         public void focusGained(FocusEvent fe) {  }
      });

   // copies
      JPanel copiesPanel = new JPanel();
      copiesPanel.setBorder(new TitledBorder("Copies"));
      copiesPanel.setLayout(new BorderLayout());
      JPanel numberOfCopiesLine = new JPanel();
      numberOfCopiesLine.add(new JLabel("Number of copies: "));
      copiesSpinnerModel = new SpinnerNumberModel(printer.getCopies(), 1, 999, 1);
      numberOfCopiesLine.add(new JSpinner(copiesSpinnerModel));
      copiesPanel.add(numberOfCopiesLine, "North");

      copiesSpinnerModel.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) { copiesChanged(); }});

  // collate
      collateCheckBox = new JCheckBox("Collate ");
      JPanel collatePanel = new JPanel();
      collatePanel.add(collateCheckBox);

      isCollatedImage = new ImageIcon("isCollated.png").getImage();
      notCollatedImage = new ImageIcon("notCollated.png").getImage();

      collatedImagePanel = new ImagePanel();
      collatedImagePanel.setBackground(this.getContentPane().getBackground());
      collatePanel.add(collatedImagePanel);

      copiesPanel.add(collatePanel, "South");

      collateCheckBox.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { collateChanged(); }});
      collateCheckBox.setSelected(printer.getCollate());
      collateChanged();

   // page range + copies panel
      JPanel printerOptions = new JPanel();
      printerOptions.setLayout(new GridLayout());
      printerOptions.add(pageRangePanel);
      printerOptions.add(copiesPanel);
      generalTab.add(printerOptions, "Center");

// Page Setup tab //

 // media
      JPanel selectMediaPanel = new JPanel();
      TitledBorder selectMediaBorder = new TitledBorder("Media");
      selectMediaPanel.setBorder(new TitledBorder("Size:"));
      selectMediaPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      mediaChoices = new JComboBox(printer.getMediaSizes());
      if (mediaChoices.getItemCount()==0) {
         mediaChoices.addItem("Letter");
         printer.setPaperSize(612.0, 792.0);
         printer.setMediaSize("Letter");
      }
      mediaChoices.setEditable(false);
      currentMedia = printer.getMediaSize();
      mediaChoices.setSelectedItem(currentMedia);
      JPanel mediaField = new JPanel();
      mediaField.add(new JLabel("Name: "));
      mediaField.add(mediaChoices);
      selectMediaPanel.add(mediaField);
      pageSetupTab.add(selectMediaPanel, "North");

      mediaChoices.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { mediaChanged(); }});

   // orientation
      JPanel orientationPanel = new JPanel();
      orientationPanel.setBorder(new TitledBorder("Orientation"));
      orientationPanel.setLayout(new BorderLayout());

      ButtonGroup orientationGroup = new ButtonGroup();
      portraitButton = new JRadioButton("Portrait");
      landscapeButton = new JRadioButton("Landscape");
      orientationGroup.add(portraitButton);
      orientationGroup.add(landscapeButton);
      // dialog only supports PORTRAIT and LANDSCAPE for now, can add REVERSE_LANDSCAPE if desired
      if (printer.getOrientation()==printer.REVERSE_LANDSCAPE) printer.setOrientation(printer.LANDSCAPE);
      boolean isLandscape = printer.getOrientation()==printer.LANDSCAPE;
      landscapeButton.setSelected(isLandscape);
      portraitButton.setSelected(!isLandscape);

      JPanel portraitLine = new JPanel();
      portraitLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      Image portraitImage = new ImageIcon("orientPortrait.png").getImage();
      ImagePanel portraitImagePanel = new ImagePanel(portraitImage);
      portraitImagePanel.setBackground(this.getContentPane().getBackground());
      portraitLine.add(portraitImagePanel);
      portraitLine.add(portraitButton);

      JPanel landscapeLine = new JPanel();
      landscapeLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      Image landscapeImage = new ImageIcon("orientLandscape.png").getImage();
      ImagePanel landscapeImagePanel = new ImagePanel(landscapeImage);
      landscapeImagePanel.setBackground(this.getContentPane().getBackground());
      landscapeLine.add(landscapeImagePanel);
      landscapeLine.add(landscapeButton);

      orientationPanel.add(portraitLine, "North");
      orientationPanel.add(landscapeLine, "South");

      portraitButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { orientationChanged(); }});
      landscapeButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { orientationChanged(); }});

   // margins
      JPanel marginsPanel = new JPanel();
      marginsPanel.setBorder(new TitledBorder("Margins (1/72 inch)"));
      marginsPanel.setLayout(new GridLayout(2,2));
      halfPage = ((int) printer.getBodyWidth()/2)-1; // quick way to prevent margin overlap

      JPanel leftMarginLine = new JPanel();
      leftMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      leftMarginLine.add(new JLabel("Left: "));
      leftMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getLeftMargin()*72.0), 0, halfPage, 1);
      leftMarginSpinner = new JSpinner(leftMarginSpinnerModel);
      leftMarginLine.add(leftMarginSpinner);
      marginsPanel.add(leftMarginLine);
      leftMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      leftMarginTextField = ((JSpinner.DefaultEditor)leftMarginSpinner.getEditor()).getTextField();
      leftMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(leftMarginSpinnerModel, leftMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      JPanel rightMarginLine = new JPanel();
      rightMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      rightMarginLine.add(new JLabel("Right: "));
      rightMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getRightMargin()*72.0), 0, halfPage, 1);
      rightMarginSpinner = new JSpinner(rightMarginSpinnerModel);
      rightMarginLine.add(rightMarginSpinner);
      marginsPanel.add(rightMarginLine);
      rightMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      rightMarginTextField = ((JSpinner.DefaultEditor)rightMarginSpinner.getEditor()).getTextField();
      rightMarginTextField.addFocusListener(new FocusListener() {
          public void focusLost(FocusEvent fe) { commitMarginEdit(rightMarginSpinnerModel, rightMarginTextField); marginsChanged(); }
          public void focusGained(FocusEvent fe) {}
       });

      JPanel topMarginLine = new JPanel();
      topMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      topMarginLine.add(new JLabel("Top: "));
      topMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getTopMargin()*72.0), 0, halfPage, 1);
      topMarginSpinner = new JSpinner(topMarginSpinnerModel);
      topMarginLine.add(topMarginSpinner);
      marginsPanel.add(topMarginLine);
      topMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      topMarginTextField = ((JSpinner.DefaultEditor)topMarginSpinner.getEditor()).getTextField();
      topMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(topMarginSpinnerModel, topMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      JPanel bottomMarginLine = new JPanel();
      bottomMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      bottomMarginLine.add(new JLabel("Bottom: "));
      bottomMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getBottomMargin()*72.0), 0, halfPage, 1);
      bottomMarginSpinner = new JSpinner(bottomMarginSpinnerModel);
      bottomMarginLine.add(bottomMarginSpinner);
      marginsPanel.add(bottomMarginLine);
      bottomMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      bottomMarginTextField = ((JSpinner.DefaultEditor)bottomMarginSpinner.getEditor()).getTextField();
      bottomMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(bottomMarginSpinnerModel, bottomMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      calculateMinimumMargins();

   // orientation + margins panel
      JPanel pageSetupOptions = new JPanel();
      pageSetupOptions.setLayout(new GridLayout());
      pageSetupOptions.add(orientationPanel);
      pageSetupOptions.add(marginsPanel);
      pageSetupTab.add(pageSetupOptions, "Center");

// Headers/Footers tab //

      int fieldWidth = 17;

   // headers
      JPanel headersPanel = new JPanel();
      headersPanel.setBorder(new TitledBorder("Headers"));
      headersPanel.setLayout(new GridLayout(1, 3));

      JPanel leftHeaderPanel = new JPanel();
      leftHeaderPanel.setBorder(new TitledBorder("Left"));
      leftHeaderPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      leftHeaderField = new JTextField(fieldWidth);
      leftHeaderField.setFont(new Font("Dialog", Font.PLAIN, 11));
      leftHeaderString = (String)printer.getLeftHeader();
      leftHeaderField.setText(leftHeaderString);
      leftHeaderPanel.add(leftHeaderField);
      headersPanel.add(leftHeaderPanel);
      leftHeaderField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      FocusListener headerFooterFocusListener = new FocusListener() {
         public void focusLost(FocusEvent fe) { headersFootersChanged(); }
         public void focusGained(FocusEvent fe) {  }
      };
      leftHeaderField.addFocusListener(headerFooterFocusListener);

      JPanel centerHeaderPanel = new JPanel();
      centerHeaderPanel.setBorder(new TitledBorder("Center"));
      centerHeaderPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      centerHeaderField = new JTextField(fieldWidth);
      centerHeaderField.setFont(new Font("Dialog", Font.PLAIN, 11));
      centerHeaderString = (String)printer.getCenterHeader();
      centerHeaderField.setText(centerHeaderString);
      centerHeaderPanel.add(centerHeaderField);
      headersPanel.add(centerHeaderPanel);
      centerHeaderField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      centerHeaderField.addFocusListener(headerFooterFocusListener);

      JPanel rightHeaderPanel = new JPanel();
      rightHeaderPanel.setBorder(new TitledBorder("Right"));
      rightHeaderPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      rightHeaderField = new JTextField(fieldWidth);
      rightHeaderField.setFont(new Font("Dialog", Font.PLAIN, 11));
      rightHeaderString = (String)printer.getRightHeader();
      rightHeaderField.setText(rightHeaderString);
      rightHeaderPanel.add(rightHeaderField);
      headersPanel.add(rightHeaderPanel);
      rightHeaderField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      rightHeaderField.addFocusListener(headerFooterFocusListener);

      headersFootersTab.add(headersPanel, "North");

   // footers
      JPanel footersPanel = new JPanel();
      footersPanel.setBorder(new TitledBorder("Footers"));
      footersPanel.setLayout(new GridLayout(1, 3));

      JPanel leftFooterPanel = new JPanel();
      leftFooterPanel.setBorder(new TitledBorder("Left"));
      leftFooterPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      leftFooterField = new JTextField(fieldWidth);
      leftFooterField.setFont(new Font("Dialog", Font.PLAIN, 11));
      leftFooterString = (String)printer.getLeftFooter();
      leftFooterField.setText(leftFooterString);
      leftFooterPanel.add(leftFooterField);
      footersPanel.add(leftFooterPanel);
      leftFooterField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      leftFooterField.addFocusListener(headerFooterFocusListener);

      JPanel centerFooterPanel = new JPanel();
      centerFooterPanel.setBorder(new TitledBorder("Center"));
      centerFooterPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      centerFooterField = new JTextField(fieldWidth);
      centerFooterField.setFont(new Font("Dialog", Font.PLAIN, 11));
      centerFooterString = (String)printer.getCenterFooter();
      centerFooterField.setText(centerFooterString);
      centerFooterPanel.add(centerFooterField);
      footersPanel.add(centerFooterPanel);
      centerFooterField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      centerFooterField.addFocusListener(headerFooterFocusListener);

      JPanel rightFooterPanel = new JPanel();
      rightFooterPanel.setBorder(new TitledBorder("Right"));
      rightFooterPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      rightFooterField = new JTextField(fieldWidth);
      rightFooterField.setFont(new Font("Dialog", Font.PLAIN, 11));
      rightFooterString = (String)printer.getRightFooter();
      rightFooterField.setText(rightFooterString);
      rightFooterPanel.add(rightFooterField);
      footersPanel.add(rightFooterPanel);
      rightFooterField.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            headersFootersChanged(); } });
      rightFooterField.addFocusListener(headerFooterFocusListener);

      headersFootersTab.add(footersPanel, "South");

   // print + cancel buttons
      JPanel printCancel = new JPanel();
      JButton printButton = new JButton("Print");
      JButton cancelButton = new JButton("Cancel");
      printCancel.setLayout(new FlowLayout(FlowLayout.RIGHT));
      printCancel.add(printButton);
      printCancel.add(cancelButton);
      this.getContentPane().add(printCancel, "South");

      printButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { print(); }});
      cancelButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { cancel(); }});

      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) { cancel(); }});

      updateUI();

      tabbedPane.addTab("General", generalTab);
      tabbedPane.addTab("Page Setup", pageSetupTab);
      tabbedPane.addTab("Headers/Footers", headersFootersTab);

      this.getContentPane().add(tabbedPane, "Center");

      pack();
      Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
      Rectangle frameDim = getBounds();
      setLocation( (screenDim.width - frameDim.width) / 2, (screenDim.height - frameDim.height) / 2);
   }

   void updateUI() {
      // update copies UI given printer selection
      PrintService ps = printer.getPrinterJob().getPrintService();
      Object copies = ps.getSupportedAttributeValues(Copies.class, null, null);
      if (copies!=null && copies.toString().equals("1")) {
        copiesSpinnerModel.setValue(int1);
         copiesSpinnerModel.setMaximum(int1);
         printer.setCopies(1);
         collateCheckBox.setSelected(false);
      }
      else {
         copiesSpinnerModel.setMaximum(int999);
      }

      // update collate UI
      int nCopies = printer.getCopies();
      collateCheckBox.setEnabled(nCopies > 1);
      if (nCopies == 1) collateCheckBox.setSelected(false);
      if (collateCheckBox.isSelected()) collatedImagePanel.setImage(isCollatedImage);
      else collatedImagePanel.setImage(notCollatedImage);


      // update media sizes UI
      if (mediaChoices==null) mediaChoices = new JComboBox(printer.getMediaSizes());
      else mediaChoices.setModel(new DefaultComboBoxModel(printer.getMediaSizes()));
      if (mediaChoices.getItemCount()==0) {
         mediaChoices.addItem("Letter");
         printer.setPaperSize(612.0, 792.0);
         printer.setMediaSize("Letter");
      }
      currentMedia = printer.getMediaSize();
      mediaChoices.setSelectedItem(currentMedia);

      // update orientation UI
      boolean isLandscape = (printer.getOrientation()==printer.LANDSCAPE);
      if (landscapeButton!=null) landscapeButton.setSelected(isLandscape);
      if (portraitButton!=null) portraitButton.setSelected(!isLandscape);

      // update margins UI
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      if (leftMarginSpinnerModel!=null) leftMarginSpinnerModel.setValue(new Integer((int)(72.0*inLM)));
      if (rightMarginSpinnerModel!=null) rightMarginSpinnerModel.setValue(new Integer((int)(72.0*inRM)));
      if (topMarginSpinnerModel!=null) topMarginSpinnerModel.setValue(new Integer((int)(72.0*inTM)));
      if (bottomMarginSpinnerModel != null) bottomMarginSpinnerModel.setValue(new Integer((int)(72.0*inBM)));

      // update page ranges UI
      try { PageRanges pr = new PageRanges(pageRangesField.getText()); }
      catch (Exception e) { pageRangesField.setText("1-"+printer.getPageable().getNumberOfPages()); }
      boolean isAll = printer.getPageRanges().length()==0;
      pageRangesField.setEnabled(!isAll);
      rangeButton.setSelected(!isAll);
      allButton.setSelected(isAll);

      repaint();
   }

   void printerChanged() {
      printer.setPrinter( (String) printerChoices.getSelectedItem());
      mediaChoices.setSelectedItem(currentMedia); // see if new printer changes media selection
      String resultingMedia = (String)mediaChoices.getSelectedItem();
      if (resultingMedia.equals(currentMedia)==false) { // if media changed, reset
         printer.setMediaSize(resultingMedia);
         mediaChanged();
         printer.setPrinter( (String) printerChoices.getSelectedItem()); // recalculates minimum margins
      }
      calculateMinimumMargins();
      updateUI();
   }

   void copiesChanged() {
      printer.setCopies(copiesSpinnerModel.getNumber().intValue());
      updateUI();
   }

   void collateChanged() {
      printer.setCollate(collateCheckBox.isSelected());
      updateUI();
   }

   void pageRangesChanged() {
      boolean isAll = allButton.isSelected();
      if (isAll) printer.setPageRanges(null);
      else try { printer.setPageRanges(pageRangesField.getText()); } catch (Exception e) { }
      updateUI();
   }

   void mediaChanged() {
      String media = (String)mediaChoices.getSelectedItem();
      printer.setMediaSize(media);
      double paperWidth = printer.getPaperWidth(); // gets values from printer attribute
      double paperHeight = printer.getPaperHeight(); // sets them into take effect
      printer.setPaperSize(paperWidth, paperHeight); // sometimes changes media size to different equivalent name
      printer.setMediaSize(media); // so restore name as selected by user
      halfPage = ((int) (paperWidth - leftMinimumMargin - rightMinimumMargin)/2) - 1;  // new maximum margins
      Integer iVal = new Integer(halfPage);
      leftMarginSpinnerModel.setMaximum(iVal);
      rightMarginSpinnerModel.setMaximum(iVal);
      topMarginSpinnerModel.setMaximum(iVal);
      bottomMarginSpinnerModel.setMaximum(iVal);
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      double halfPageInches = halfPage/72.0;
      double newLM = inLM<halfPageInches?inLM:halfPageInches;
      double newRM = inRM<halfPageInches?inRM:halfPageInches;
      double newTM = inTM<halfPageInches?inTM:halfPageInches;
      double newBM = inBM<halfPageInches?inBM:halfPageInches;
      printer.setMargins(newLM, newRM, newTM, newBM);
      updateUI();
   }

   void orientationChanged() {
      calculateMinimumMargins();
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      int inOrientation = printer.getOrientation();
      if (portraitButton.isSelected()) printer.setOrientation(printer.PORTRAIT);
      else printer.setOrientation(printer.LANDSCAPE);
      int outOrientation = printer.getOrientation();
      if (inOrientation==printer.PORTRAIT && outOrientation==printer.LANDSCAPE)
         printer.setMargins(inBM, inTM, inLM, inRM);
      if (inOrientation==printer.LANDSCAPE && outOrientation==printer.PORTRAIT)
         printer.setMargins(inTM, inBM, inRM, inLM);
      updateUI();
   }

   void marginsChanged() {
      keepMarginInRange(leftMarginSpinnerModel, leftMinimumMargin, halfPage);
      keepMarginInRange(rightMarginSpinnerModel, rightMinimumMargin, halfPage);
      keepMarginInRange(topMarginSpinnerModel, topMinimumMargin, halfPage);
      keepMarginInRange(bottomMarginSpinnerModel, bottomMinimumMargin, halfPage);
      double leftMargin = leftMarginSpinnerModel.getNumber().intValue()/72.0;
      double rightMargin = rightMarginSpinnerModel.getNumber().intValue()/72.0;
      double topMargin = topMarginSpinnerModel.getNumber().intValue()/72.0;
      double bottomMargin = bottomMarginSpinnerModel.getNumber().intValue()/72.0;
      printer.setMargins(leftMargin, rightMargin, topMargin, bottomMargin);
      updateUI();
   }

   void keepMarginInRange(SpinnerNumberModel snm, int min, int max) {
      int num = snm.getNumber().intValue();
      if (num<min) num = min;
      if (num>max) num = max;
      snm.setValue(new Integer(num));
   }

   void commitMarginEdit(SpinnerNumberModel spinnerModel, JFormattedTextField textField) {
      Integer val;
      try { val = Integer.valueOf(textField.getText());} catch (Exception e) { return; } // retain old value if bad
      if (val.intValue()>halfPage) val = new Integer(halfPage);
      spinnerModel.setValue(val);
   }

   void calculateMinimumMargins() {
     int orientation = printer.getOrientation();
     leftMinimumMargin = (int) printer.getMinimumLeftMargin(orientation);
     rightMinimumMargin = (int)  printer.getMinimumRightMargin(orientation);
     topMinimumMargin = (int) printer.getMinimumTopMargin(orientation);
     bottomMinimumMargin = (int) printer.getMinimumBottomMargin(orientation);

     Integer iVal = new Integer(leftMinimumMargin);
     leftMarginSpinnerModel.setMinimum(iVal);
     int leftVal = leftMarginSpinnerModel.getNumber().intValue();
     if (leftVal<leftMinimumMargin) leftMarginSpinnerModel.setValue(iVal);

     iVal = new Integer(rightMinimumMargin);
     rightMarginSpinnerModel.setMinimum(iVal);
     int rightVal = rightMarginSpinnerModel.getNumber().intValue();
     if (rightVal<rightMinimumMargin) rightMarginSpinnerModel.setValue(iVal);

     iVal = new Integer(topMinimumMargin);
     topMarginSpinnerModel.setMinimum(iVal);
     int topVal = topMarginSpinnerModel.getNumber().intValue();
     if (topVal<topMinimumMargin) topMarginSpinnerModel.setValue(iVal);

     iVal = new Integer(bottomMinimumMargin);
     bottomMarginSpinnerModel.setMinimum(iVal);
     int bottomVal = bottomMarginSpinnerModel.getNumber().intValue();
     if (bottomVal<bottomMinimumMargin) bottomMarginSpinnerModel.setValue(iVal);
  }

   void headersFootersChanged() {
      printer.setLeftHeader(leftHeaderField.getText());
      printer.setCenterHeader(centerHeaderField.getText());
      printer.setRightHeader(rightHeaderField.getText());

      printer.setLeftFooter(leftFooterField.getText());
      printer.setCenterFooter(centerFooterField.getText());
      printer.setRightFooter(rightFooterField.getText());

      //alternative implementation supporting both HTML and plain text entries:
      //String str = leftHeaderField.getText();
      //if (str.substring(0,6).toLowerCase().equals("<html>")) printer.setLeftHeader(new JLabel(str));
      //else printer.setLeftHeader(str);
      //...similarly for left/center/right headers and footers
   }

   public int showDialog() {
      setVisible(true);
      return retVal;
   }

   public void print() {
      retVal = TabbedPrintDialog.PRINT;
      setVisible(false);
   }

   public void cancel() {
      printer.setPrintRequestAttributeSet(attributeSet);
      printer.setPrinter(printerName);
      printer.setPageFormat(pageFormat);

      printer.setLeftHeader(leftHeaderString);
      printer.setCenterHeader(centerHeaderString);
      printer.setRightHeader(rightHeaderString);

      printer.setLeftFooter(leftFooterString);
      printer.setCenterFooter(centerFooterString);
      printer.setRightFooter(rightFooterString);

      retVal = TabbedPrintDialog.CANCEL;
      setVisible(false);
   }

}
