/*  PrintPreviewDialog (= default print preview in J2PrinterWorks.jar)
    (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.
*/

//only difference in J2PrinterWorks.jar class: package com.wildcrest.j2printerworks;

import com.wildcrest.j2printerworks.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.awt.image.*;
import java.util.*;
import java.net.URL;

class PrintPreviewDialog extends JDialog {
   Frame frame;
   Pageable pageable;
   J2Printer j2p;

   static PrintPreviewDialog instance;

   static private boolean is12or13 = System.getProperty("java.version").startsWith("1.2") ||
       System.getProperty("java.version").startsWith("1.3");

   static private JToolBar toolBar = null;
   static JPanel toolBarPanel = null;

   static JButton printButton, pageSetupButton, firstPageButton, previousPageButton, nextPageButton;
   static JButton lastPageButton, zoomOutButton, zoomInButton, onePageButton, twoPageButton, closeButton;
   static String previousPageString, nextPageString, firstPageString, lastPageString, zoomOutString;
   static String zoomInString, twoPageString, onePageString, printPreviewString;
   static String printString, pageSetupString, closeString, pageString, ofString, numberOfPagesString;
   static JTextField currentPageField, scaleField;
   static JLabel pageLabel, ofLabel, numberOfPagesLabel;
   static JSeparator separatorPrintPageSetup, separatorPageSetupFirstPage, separatorLastPageZoomOut;
   static JSeparator separatorZoomInOnePage, separatorTwoPageClose;

   PageDisplayPanel pageDisplayPanel;
   MyJScrollPane scrollpane;
   BufferedImage image1, image2;

   static Locale rememberLocale = null;

   int numberOfPages;
   int extraWindowWidth, extraWindowHeight;

   static boolean isTwoPage;
   static double currentScale;
   static int currentPage;

   static Image iconImage = null;

   static private boolean isCrossPlatform;

   static double getCurrentPrintPreviewScale() {
      return currentScale;
   }

   static int getCurrentPrintPreviewPageNumber() {
      return currentPage;
   }

   static boolean isCurrentPrintPreviewTwoPageDisplay() {
      return isTwoPage;
   }

   static private boolean changeLookAndFeel = true;

   ActionListener printAction, pageSetupAction, closeAction, firstPageAction, previousPageAction;
   ActionListener nextPageAction, lastPageAction, zoomOutAction, zoomInAction, currentPageAction;
   ActionListener onePageAction, twoPageAction, scaleAction;

   static {
      rememberLocale = java.util.Locale.getDefault();
      setupStringResources(rememberLocale);
   }

   PrintPreviewDialog(Frame frame, J2Printer j2p, Pageable pageable) {
      super(frame, "Print Preview", true); // true = modal
      this.j2p = j2p;
      this.pageable = pageable;
      this.frame = frame;
      this.instance = this; // save for refresh method

      //this.setResizable(false); // would be preferable, but can lead to improper recentering of
                                  // dialog on some systems (e.g. jumps by about an inch on landscape
                                  // to portrait transition at 100% on Macs with screen height = 900)

      buildPrintPreviewDialog();
   }

   static private void setupStringResources(Locale locale) { //get resources for Locale
      ResourceBundle resources;
      try {
         resources = ResourceBundle.getBundle("com.wildcrest.j2printerworks.J2PrinterWorks", locale);
         printString = unquote(resources.getString("print"));
         previousPageString = unquote(resources.getString("prevpage"));
         nextPageString = unquote(resources.getString("nextpage"));
         pageSetupString = unquote(resources.getString("pagesetup"));
         closeString = unquote(resources.getString("done"));
         pageString = unquote(resources.getString("page"));
         ofString = unquote(resources.getString("of"));
         firstPageString = unquote(resources.getString("firstpage"));
         lastPageString = unquote(resources.getString("lastpage"));
         zoomOutString = unquote(resources.getString("zoomout"));
         zoomInString = unquote(resources.getString("zoomin"));
         twoPageString = unquote(resources.getString("twopagedisplay"));
         onePageString = unquote(resources.getString("onepagedisplay"));
         printPreviewString = unquote(resources.getString("printpreview"));
      } catch (Exception e) { // if exception, default to English
         printString = "Print...";
         previousPageString = "Previous Page";
         nextPageString = "Next Page";
         pageSetupString = "Page Setup";
         closeString = "Done";
         pageString = "Page ";
         ofString = " of ";
         firstPageString = "First Page";
         lastPageString = "Last Page";
         zoomOutString = "Zoom Out";
         zoomInString = "Zoom In";
         twoPageString = "Two Page Display";
         onePageString = "One Page Display";
         printPreviewString = "Print Preview";
      }
      resources = null;
   }

   static private String unquote(String str) { // if string starts and ends with quote, remove them
      String ret = str;
      if (str.startsWith("\"") && str.endsWith("\""))
         ret = str.substring(1, str.length() - 1);
      return ret;
   }

   static void changeLookAndFeel(boolean change) {
      changeLookAndFeel = change;
   }

   static private void createToolBar() {
      LookAndFeel rememberLAF = UIManager.getLookAndFeel();

      if (changeLookAndFeel) {
         try {
            if (isCrossPlatform)
               UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
            else
               UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
         } catch (Exception exception) {}
      }

      boolean isWindowsLF = UIManager.getLookAndFeel() instanceof com.sun.java.swing.plaf.windows.
          WindowsLookAndFeel;
      boolean isMacLF = UIManager.getLookAndFeel().toString().indexOf("apple.laf.AquaLookAndFeel") >= 0;

      // Motif test:
      //try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
      //} catch (Exception e) {}
      //isWindows = false; isCrossPlatform = false; isMac = false;

      toolBar = new JToolBar();
      toolBar.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
      if (isCrossPlatform) {
         Color backgroundColor = new Color(new JButton().getBackground().getRGB());
         toolBar.setBackground(backgroundColor);
      }

      printButton = new JButton();
      pageSetupButton = new JButton();
      firstPageButton = new JButton();
      previousPageButton = new JButton();
      pageLabel = new JLabel("Page ");
      currentPageField = new JTextField(" 1 ");
      ofLabel = new JLabel(" of ");
      numberOfPagesLabel = new JLabel("99");
      nextPageButton = new JButton();
      lastPageButton = new JButton();
      zoomOutButton = new JButton();
      scaleField = new JTextField("100%");
      zoomInButton = new JButton();
      onePageButton = new JButton();
      twoPageButton = new JButton();
      closeButton = new JButton();

      ImageIcon printIcon = new ImageIcon(J2Printer.class.getResource("print.gif"));
      ImageIcon pageSetupIcon = new ImageIcon(J2Printer.class.getResource("pagesetup.gif"));
      ImageIcon firstPageIcon = new ImageIcon(J2Printer.class.getResource("first.gif"));
      ImageIcon previousPageIcon = new ImageIcon(J2Printer.class.getResource("previous.gif"));
      ImageIcon nextPageIcon = new ImageIcon(J2Printer.class.getResource("next.gif"));
      ImageIcon lastPageIcon = new ImageIcon(J2Printer.class.getResource("last.gif"));
      ImageIcon zoomOutIcon = new ImageIcon(J2Printer.class.getResource("zoomout.gif"));
      ImageIcon zoomInIcon = new ImageIcon(J2Printer.class.getResource("zoomin.gif"));
      ImageIcon onePageIcon = new ImageIcon(J2Printer.class.getResource("onepage.gif"));
      ImageIcon twoPageIcon = new ImageIcon(J2Printer.class.getResource("twopage.gif"));

      printButton.setIcon(printIcon);
      printButton.setText(printString);
      printButton.setToolTipText(printString);
      pageSetupButton.setIcon(pageSetupIcon);
      pageSetupButton.setText(pageSetupString);
      pageSetupButton.setToolTipText(pageSetupString);
      firstPageButton.setIcon(firstPageIcon);
      firstPageButton.setToolTipText(firstPageString);
      previousPageButton.setIcon(previousPageIcon);
      previousPageButton.setToolTipText(previousPageString);
      nextPageButton.setIcon(nextPageIcon);
      nextPageButton.setToolTipText(nextPageString);
      lastPageButton.setIcon(lastPageIcon);
      lastPageButton.setToolTipText(lastPageString);
      zoomOutButton.setIcon(zoomOutIcon);
      zoomOutButton.setToolTipText(zoomOutString);
      zoomInButton.setIcon(zoomInIcon);
      zoomInButton.setToolTipText(zoomInString);
      onePageButton.setIcon(onePageIcon);
      onePageButton.setToolTipText(onePageString);
      twoPageButton.setIcon(twoPageIcon);
      twoPageButton.setToolTipText(twoPageString);
      closeButton.setText(closeString);
      closeButton.setToolTipText(closeString);
      pageLabel.setText(pageString);
      ofLabel.setText(ofString);

      toolBar.add(printButton);
      separatorPrintPageSetup = new JSeparator(JSeparator.VERTICAL);
      toolBar.add(separatorPrintPageSetup);
      toolBar.add(pageSetupButton);
      separatorPageSetupFirstPage = new JSeparator(JSeparator.VERTICAL);
      toolBar.add(separatorPageSetupFirstPage);
      toolBar.add(firstPageButton);
      toolBar.add(previousPageButton);
      toolBar.add(pageLabel);
      toolBar.add(currentPageField);
      toolBar.add(ofLabel);
      toolBar.add(numberOfPagesLabel);
      toolBar.add(nextPageButton);
      toolBar.add(lastPageButton);
      separatorLastPageZoomOut = new JSeparator(JSeparator.VERTICAL);
      toolBar.add(separatorLastPageZoomOut);
      toolBar.add(zoomOutButton);
      toolBar.add(scaleField);
      toolBar.add(zoomInButton);
      separatorZoomInOnePage = new JSeparator(JSeparator.VERTICAL);
      toolBar.add(separatorZoomInOnePage);
      toolBar.add(onePageButton);
      toolBar.add(twoPageButton);
      separatorTwoPageClose = new JSeparator(JSeparator.VERTICAL);
      toolBar.add(separatorTwoPageClose);
      toolBar.add(closeButton);
      toolBar.setFloatable(false);

      //toolBar.setRollover(true); // not present in JDK 1.2.x or 1.3.x so call by introspection:
      try {
         java.lang.reflect.Method method = toolBar.getClass().getMethod("setRollover", new Class[] {boolean.class});
         method.invoke(toolBar, new Object[] {new Boolean(true)});
      } catch (Exception e) {} // silent failure if method doesn't exist (prior to JDK 1.4)

      if (isCrossPlatform || isWindowsLF || isMacLF) { // must be after setRollover, at least for WindowsLookAndFeel
         // Motif rollover highlighting of buttons doesn't work if you do this
         printButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         pageSetupButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         firstPageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         previousPageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         nextPageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         lastPageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         zoomOutButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         zoomInButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         onePageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         twoPageButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
         closeButton.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
      }

      toolBarPanel = new JPanel();
      toolBarPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
      toolBarPanel.add(toolBar);
      toolBarPanel.setBackground(toolBar.getBackground());

      // needed for JDK 1.6 due to bug in early access release
      fixUI(firstPageButton);
      fixUI(previousPageButton);
      fixUI(nextPageButton);
      fixUI(lastPageButton);
      fixUI(zoomOutButton);
      fixUI(zoomInButton);
      fixUI(onePageButton);
      fixUI(twoPageButton);
      fixUI(printButton);
      fixUI(pageSetupButton);
      fixUI(closeButton);

      if (changeLookAndFeel) {
         try {
            UIManager.setLookAndFeel(rememberLAF);
         } catch (Exception e) {}
      }

   }

   static private void fixUI(JButton button) {
      // needed to prevent red selection backgrounds on Mac in cross platform:
      if (System.getProperty("os.name").toLowerCase().startsWith("mac") && isCrossPlatform)
         button.setContentAreaFilled(false);
      // needed for JDK 1.6 due to bug in early access release:
      if (button.getText().length() == 0)
         button.setPreferredSize(button.getPreferredSize());
   }

   static JToolBar getToolBar(J2Printer j2p) {
      Locale newLocale = getLocale(j2p);
      if (!newLocale.equals(rememberLocale)) {
         rememberLocale = newLocale;
         setupStringResources(rememberLocale);
         createToolBar();
         return toolBar;
      }

      boolean wasCrossPlatform = isCrossPlatform;
      isCrossPlatform = isCrossPlatform(j2p);
      if (isCrossPlatform != wasCrossPlatform || toolBar == null)
         createToolBar();
      return toolBar;
   }

   static boolean isCrossPlatform(J2Printer j2p) {
      boolean isCrossPlatform = false;
      try {
         isCrossPlatform = j2p.isCrossPlatformDialogs();
      } catch (Exception e) {}
      return isCrossPlatform;
   }

   private void buildPrintPreviewDialog() {
      JToolBar jtb = getToolBar(j2p);

      currentPage = j2p.getPrintPreviewPageNumber();
      isTwoPage = j2p.isPrintPreviewTwoPageDisplay();
      currentScale = j2p.getPrintPreviewScale();

      setTitle(printPreviewString);
      if (iconImage != null) {
         //this.setIconImage(iconImage);
         try {
            Class classPrintPreviewDialog = this.getClass();
            Class[] classArgs = new Class[] {Image.class};
            java.lang.reflect.Method methodSetIconImage = classPrintPreviewDialog.getMethod(
                "setIconImage", classArgs);
            methodSetIconImage.invoke( (Object)this, new Object[] {iconImage});
         } catch (Exception e) {}
      }

      JPanel container = new JPanel();
      container.setLayout(new BorderLayout());

      numberOfPages = pageable.getNumberOfPages();

      if (currentPage > numberOfPages || currentPage < 1)
         currentPage = 1;

      boolean pagesExist = numberOfPages > 0;

      if (pagesExist) {
         pageDisplayPanel = new PageDisplayPanel(this);
         scrollpane = new MyJScrollPane();
         scrollpane.setVisible(true);
         scrollpane.setSize(pageDisplayPanel.getPreferredSize());
         scrollpane.getViewport().add(pageDisplayPanel);
         container.add(scrollpane, BorderLayout.CENTER);
         container.add(toolBarPanel, BorderLayout.NORTH);
      }

      printButton.setFocusPainted(false);
      setFocusable(printButton, false); // cleans up button coming up rolled over bug in JDK 1.6

      printAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            printPressed();
         }
      };
      printButton.addActionListener(printAction);
      printButton.registerKeyboardAction(printAction, KeyStroke.getKeyStroke("control P"),
                                         JComponent.WHEN_IN_FOCUSED_WINDOW);
      printButton.setEnabled(pagesExist);

      pageSetupButton.setFocusPainted(false);
      setFocusable(pageSetupButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      pageSetupAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            pageSetupPressed();
         }
      };
      pageSetupButton.addActionListener(pageSetupAction);

      closeButton.setFocusPainted(false);
      setFocusable(closeButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      closeAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            closePressed();
         }
      };
      closeButton.addActionListener(closeAction);
      closeButton.registerKeyboardAction(closeAction, KeyStroke.getKeyStroke("ESCAPE"),
                                         JComponent.WHEN_IN_FOCUSED_WINDOW);

      closeButton.setEnabled(false);
      closeButton.setEnabled(true); // cleans up left behind rollover bug in JDK 1.5 and previous

      addWindowListener(new java.awt.event.WindowAdapter() {
         public void windowClosing(java.awt.event.WindowEvent e) {
            closePressed();
         }
      });

      firstPageButton.setFocusPainted(false);
      setFocusable(firstPageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      firstPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            firstPagePressed();
         }
      };
      firstPageButton.addActionListener(firstPageAction);
      firstPageButton.registerKeyboardAction(firstPageAction, KeyStroke.getKeyStroke("HOME"),
                                             JComponent.WHEN_IN_FOCUSED_WINDOW);

      previousPageButton.setFocusPainted(false);
      setFocusable(previousPageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      previousPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            prevPagePressed();
         }
      };
      previousPageButton.addActionListener(previousPageAction);
      previousPageButton.registerKeyboardAction(previousPageAction, KeyStroke.getKeyStroke("PAGE_UP"),
                                                JComponent.WHEN_IN_FOCUSED_WINDOW);

      currentPageField.setColumns(1 + (numberOfPages < 100 ? 2 : numberOfPages < 1000 ? 3 : 4));
      currentPageField.setHorizontalAlignment(JTextField.CENTER);
      currentPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            currentPageEntered();
         }
      };
      currentPageField.addActionListener(currentPageAction);
      numberOfPagesLabel.setText(numberOfPages + "");

      nextPageButton.setFocusPainted(false);
      setFocusable(nextPageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      nextPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            nextPagePressed();
         }
      };
      nextPageButton.addActionListener(nextPageAction);
      nextPageButton.registerKeyboardAction(nextPageAction, KeyStroke.getKeyStroke("PAGE_DOWN"),
                                            JComponent.WHEN_IN_FOCUSED_WINDOW);

      lastPageButton.setFocusPainted(false);
      setFocusable(lastPageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      lastPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            lastPagePressed();
         }
      };
      lastPageButton.addActionListener(lastPageAction);
      lastPageButton.registerKeyboardAction(lastPageAction, KeyStroke.getKeyStroke("END"),
                                            JComponent.WHEN_IN_FOCUSED_WINDOW);

      zoomOutButton.setFocusPainted(false);
      setFocusable(zoomOutButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      zoomOutAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            zoomOutPressed();
         }
      };
      zoomOutButton.addActionListener(zoomOutAction);

      String initialScale = (int) (100 * currentScale) + "%";

      scaleField.setText(initialScale);
      scaleField.setColumns(5);
      scaleField.setHorizontalAlignment(JTextField.CENTER);
      scaleAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            scaleEntered();
         }
      };
      scaleField.addActionListener(scaleAction);

      zoomInButton.setFocusPainted(false);
      setFocusable(zoomInButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      zoomInAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            zoomInPressed();
         }
      };
      zoomInButton.addActionListener(zoomInAction);

      enableZoomButtons();

      onePageButton.setFocusPainted(false);
      setFocusable(onePageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      onePageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            onePagePressed();
         }
      };
      onePageButton.addActionListener(onePageAction);

      twoPageButton.setFocusPainted(false);
      setFocusable(twoPageButton, false); // cleans up button coming up rolled over bug in JDK 1.6
      twoPageAction = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            twoPagePressed();
         }
      };
      twoPageButton.addActionListener(twoPageAction);

      onePageButton.setEnabled(numberOfPages > 1);
      twoPageButton.setEnabled(numberOfPages > 1);
      if (isTwoPage)
         twoPagePressed();
      else
         onePagePressed();

      enableViewButtons();

      getContentPane().add(container);
      if (pagesExist)
         displayCurrentPage(true);
      pack();
      centerDialog();

      moveFocus();

      // hack: need an extra delayed refresh to get HTML <IMG> to display unde JDK 1.5.0
      if (pagesExist) {
         try {
            Thread.currentThread().sleep(100);
         } catch (Exception e) {}
         ;
         displayCurrentPage(true);
      }
      else
         setSize(600, 400);
   }

   private void setFocusable(Component component, boolean truefalse) {
      //component.setFocusable(truefalse); // call by introspection so will compile on JDK's < 1.4
      try {
         Class classComponent = Class.forName("java.awt.Component");
         Class[] classArgs = new Class[] {boolean.class};
         java.lang.reflect.Method methodSetFocusable = classComponent.getMethod("setFocusable",
             classArgs);
         Boolean bool = new Boolean(truefalse);
         methodSetFocusable.invoke(component, new Object[] {bool});
      } catch (Exception e) {} // fail silently (pre-JDK 1.4)
   }

   private void displayCurrentPage(boolean pack) {
      image1 = j2p.getPageImage(pageable, currentPage, currentScale, 2, true); // use drop shadow
      // assumes currentPage<numberOfPages if isTwoPage==true
      if (isTwoPage)
         image2 = j2p.getPageImage(pageable, Math.min(currentPage + 1, numberOfPages),
                                         currentScale, 2, true); // use drop shadow
      currentPageField.setText(currentPage + "");

      pageDisplayPanel.repaint(); // does drawImage of image to Graphics

      Dimension startingSize = getSize();
      Point startingLocation = getLocation();

      if (pack)
         pack(); // possible resize and relayout on panel size change (but keep location the same)

      Dimension mySize = getSize(); // make sure print preview fits on screen
      if (mySize.equals(startingSize)) {
         validate();
         return;
      } // leave position alone if size same

      Dimension screenSize = this.getToolkit().getScreenSize();
      screenSize.height -= windowsTaskBarHeight; // make room for Windows task bar (since Java doesn't)
      if (mySize.width > screenSize.width)
         mySize.width = screenSize.width;
      if (mySize.height > screenSize.height)
         mySize.height = screenSize.height;
      // center horizontally (keeps buttons in same place on orientation change)
      setBounds(startingLocation.x - (mySize.width - startingSize.width) / 2, getLocation().y,
                mySize.width, mySize.height);
      validate(); // cause redraw, scroll bar(s) may show up

      Dimension oldSize = new Dimension(mySize);
      if (scrollpane.getVerticalScrollBar().isVisible()) // if now vertical scrollbar, make wider
         mySize.width = mySize.width + scrollpane.getVerticalScrollBar().getSize().width;
      if (scrollpane.getHorizontalScrollBar().isVisible()) // if now horizontal scrollbar, make taller
         mySize.height = mySize.height + scrollpane.getHorizontalScrollBar().getSize().height;

      if (mySize.width > screenSize.width)
         mySize.width = screenSize.width; // but keep within screen area
      if (mySize.height > screenSize.height)
         mySize.height = screenSize.height;

      if (!mySize.equals(oldSize)) { // if changed, reset bounds
         setBounds(startingLocation.x - (mySize.width - startingSize.width) / 2, getLocation().y,
                   mySize.width, mySize.height);
         validate();
      }
   }

   private class PageDisplayPanel extends JPanel {
      int inset = 5;
      JDialog dialog;
      PageDisplayPanel(JDialog dialog) {
         this.dialog = dialog;
      }

      public void paint(Graphics g) {
         dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
         Graphics2D g2d = (Graphics2D) g;
         g2d.setColor(getBackground());
         Dimension panelSize = getSize();
         g2d.fillRect(0, 0, panelSize.width, panelSize.height);
         g2d.setColor(getForeground());
         Dimension imagePlusInsetsSize = getPreferredSize();

         Dimension image1Size = exactPageSize(j2p, pageable, currentPage, currentScale);
         int originX = inset + (panelSize.width - imagePlusInsetsSize.width) / 2;
         int originY = (panelSize.height - image1Size.height) / 2;
         g2d.drawImage(image1, originX, originY, this);

         if (isTwoPage && currentPage < numberOfPages) {
            Dimension image2Size = exactPageSize(j2p, pageable, currentPage + 1, currentScale);
            originX = originX + image1Size.width + inset;
            originY = (panelSize.height - image2Size.height) / 2;
            g2d.drawImage(image2, originX, originY, this);
         }

         dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }

      public Dimension getPreferredSize() {
         Dimension image1Size = exactPageSize(j2p, pageable, currentPage, currentScale);
         int w = image1Size.width + 2 * inset;
         int h = image1Size.height + 2 * inset;
         if (isTwoPage) {
            Dimension image2Size = exactPageSize(j2p, pageable, Math.min(currentPage + 1, numberOfPages),
                                                 currentScale);
            w = w + image2Size.width + inset;
            h = Math.max(h, image2Size.height + 2 * inset);
         }
         return new Dimension(w, h);
      }

      public Dimension getMinimumSize() {
         return getPreferredSize();
      }

      public Dimension getMaximumSize() {
         return getPreferredSize();
      }
   }

   private static Dimension exactPageSize(J2Printer printer, Pageable pageable, int currentPage,
                                          double scale) {
      int pageW = (int) printer.getPaperWidth();
      int pageH = (int) printer.getPaperHeight();
      if (pageable.getPageFormat(currentPage - 1).getOrientation() != PageFormat.PORTRAIT) {
         int temp = pageH;
         pageH = pageW;
         pageW = temp;
      }
      //// also !=REVERSE_PORTRAIT when Sun implements this
      return new Dimension( (int) (pageW * scale), (int) (pageH * scale));
   }

   private class MyJScrollPane extends JScrollPane { // preferred size changes only when panel size changes
      Dimension panelSize = null;
      public Dimension getPreferredSize() {
         if (panelSize == null)
            panelSize = pageDisplayPanel.getPreferredSize();
         else { // if panel same size, don't change scrollpane size (e.g., if window was resized)
            Dimension currentPanelSize = pageDisplayPanel.getPreferredSize();
            if (panelSize.equals(currentPanelSize))
               return getSize(); // don't change scrollpane
            else
               panelSize = currentPanelSize; // remember new panel size
         }
         int inset = pageDisplayPanel.inset;
         return (new Dimension(panelSize.width + 2 * inset, panelSize.height + 2 * inset));
      }
   }

   private Dimension centerDialogScreenSize = null;
   private int windowsTaskBarHeight = 32; // hard code for now until Java gives us a way to determine

   private void centerDialog() { // called once when first opened
      if (centerDialogScreenSize == null) {
         centerDialogScreenSize = this.getToolkit().getScreenSize();
         centerDialogScreenSize.height -= windowsTaskBarHeight; // make room for Windows task bar (since Java doesn't)
      }
      Dimension size = this.getSize();
      size.height = Math.min(size.height, centerDialogScreenSize.height); // no bigger than screen
      size.width = Math.min(size.width, centerDialogScreenSize.width);
      int y = (centerDialogScreenSize.height - size.height) / 2;
      int x = (centerDialogScreenSize.width - size.width) / 2;
      setBounds(x, y, size.width, size.height);
   }

   private void assureOnScreen() {
      if (centerDialogScreenSize == null) {
         centerDialogScreenSize = this.getToolkit().getScreenSize();
         centerDialogScreenSize.height -= windowsTaskBarHeight; // make room for Windows task bar (since Java doesn't)
      }
      Dimension size = this.getSize();
      Point location = this.getLocation();
      int x = location.x;
      int y = location.y;

      int margin = 10;

      int extraX = (centerDialogScreenSize.width - size.width) / 2;
      if (extraX < 0)
         extraX = 0;
      if (extraX > margin)
         extraX = margin;
      if (x < 0)
         x = 0 + extraX;
      else if (x + size.width > centerDialogScreenSize.width)
         x = centerDialogScreenSize.width - size.width - extraX;

      int extraY = (centerDialogScreenSize.height - size.height) / 2;
      if (extraY < 0)
         extraY = 0;
      if (extraY > margin)
         extraY = margin;
      if (y < 0)
         y = 0 + extraY;
      else if (y + size.height > centerDialogScreenSize.height)
         y = centerDialogScreenSize.height - size.height - extraY;
      setBounds(x, y, size.width, size.height); //// someday fix: if multiple screens, jumps to main screen
   }

   static void setPrintPreviewIconImage(Image icon) {
      iconImage = icon;
   }

   static int[] scaleChoices = {25, 35, 50, 75, 100, 125, 150, 200, 300};
   static void setZoomLevels(int[] zoomLevels) {
      scaleChoices = zoomLevels;
   }

   private void zoomOutPressed() {
      int currentScale = getScale();
      int newScale = scaleChoices[0];
      for (int i = 1; i < scaleChoices.length; i++) {
         if (scaleChoices[i] < currentScale)
            newScale = scaleChoices[i];
      }
      setScale(newScale);
   }

   private void zoomInPressed() {
      int currentScale = getScale();
      int newScale = scaleChoices[scaleChoices.length - 1];
      for (int i = scaleChoices.length - 2; i >= 0; i--) {
         if (scaleChoices[i] > currentScale)
            newScale = scaleChoices[i];
      }
      setScale(newScale);
   }

   private void scaleEntered() {
      int scale = getScale(); // get scale from text field
      if (scale < 1)
         scale = 1;
      if (scale > 400)
         scale = 400;
      setScale(scale); // set scale in text field and sctual display
   }

   private void setScale(int scale) {
      scaleField.setText(scale + "%");
      currentScale = scale / 100.0;
      displayCurrentPage(true);
      assureOnScreen();
      enableZoomButtons();
   }

   private void enableZoomButtons() {
      zoomOutButton.setEnabled(100 * currentScale > scaleChoices[0]);
      zoomInButton.setEnabled(100 * currentScale < scaleChoices[scaleChoices.length - 1]);
      moveFocus();
   }

   private void moveFocus() {
      setFocusable(toolBar, true); // cleans up button coming up rolled over bug in JDK 1.6
      toolBar.requestFocus();
      toolBar.getParent().transferFocus();
   }

   private int getScale() {
      String desiredScale = scaleField.getText();
      if (desiredScale.endsWith("%"))
         desiredScale = desiredScale.substring(0, desiredScale.length() - 1);
      try {
         return Integer.parseInt(desiredScale);
      } catch (Exception e) {
         return (int) (100 * currentScale);
      }
   }

   private void prevPagePressed() {
      gotoPageNumber(currentPage - 1);
   }

   private void nextPagePressed() {
      gotoPageNumber(currentPage + 1);
   }

   private void firstPagePressed() {
      gotoPageNumber(1);
   }

   private void lastPagePressed() {
      gotoPageNumber(numberOfPages);
   }

   private void currentPageEntered() {
      currentPage = Integer.parseInt(currentPageField.getText());
      gotoPageNumber(currentPage);
   }

   static void refresh() { // provide for developers
      instance.updateNumberOfPages();
      instance.gotoPageNumber(currentPage);
   }

   private void updateNumberOfPages() {
      pageable = j2p.getPageable();
      numberOfPages = pageable.getNumberOfPages();
      currentPageField.setColumns(1 + (numberOfPages < 100 ? 2 : numberOfPages < 1000 ? 3 : 4));
      numberOfPagesLabel.setText(numberOfPages + "");
   }

   private void gotoPageNumber(int pageNum) {
      currentPage = pageNum;
      if (currentPage < 1)
         currentPage = 1;
      if (currentPage > numberOfPages)
         currentPage = numberOfPages;
      displayCurrentPage(true);
      enableViewButtons();
      currentPageField.setText(currentPage + "");
   }

   private void enableViewButtons() {
      previousPageButton.setEnabled(false);
      nextPageButton.setEnabled(false);
      firstPageButton.setEnabled(false);
      lastPageButton.setEnabled(false);

      if (currentPage > 1) {
         previousPageButton.setEnabled(true);
         firstPageButton.setEnabled(true);
      }
      if (currentPage < numberOfPages) {
         nextPageButton.setEnabled(true);
         lastPageButton.setEnabled(true);
      }
      moveFocus();
   }

   private void twoPagePressed() {
      if (numberOfPages < 2)
         return;
      twoPageButton.setEnabled(false);
      onePageButton.setEnabled(true);
      isTwoPage = true;
      j2p.setNumberOfPageImageBuffers(2); // does nothing if already 2 buffers; also don't change back to 1
      displayCurrentPage(true);
      enableViewButtons();
   }

   private void onePagePressed() {
      if (numberOfPages < 2)
         return;
      twoPageButton.setEnabled(true);
      onePageButton.setEnabled(false);
      isTwoPage = false;
      displayCurrentPage(true);
      enableViewButtons();
   }

   private void printPressed() { // getPrintPreviewCloseOnPrint options are BEFORE, WAIT, and NEVER
      if (j2p.getPrintPreviewCloseOnPrint() == J2Printer.BEFORE) { //old "simple version" (seems preferrable on certain OS's, e.g. Solaris)
         closePrintPreview();
         j2p.print();
         return;
      }

      //new:
      // Cleaner UI refresh
      // fixes problem of no print dialog if J2Printer14 + crossplatform=true + separatethread=false
      //
      // Previously had problem of exit before print even if setSeparatePrintThread(false) (if "exit on close"?)
      // but this problem seems to have gone away
      //
      // NOTE: we have a report that this code hangs on Solaris, whereas simple version above is fine

      setBusyCursor(true);

      j2p.addPropertyChangeListener(new java.beans.PropertyChangeListener() { // wait to turn off busy cursor and dismiss print preview dialog
         public void propertyChange(java.beans.PropertyChangeEvent evt) {
            if (j2p==null) {
               setBusyCursor(false);
               closePrintPreview();
            }
            else if (j2p.isPrintDialogUsed() == true && evt.getPropertyName().equals("printDialogResponse")) { // if print dialog used
               setBusyCursor(false);
               j2p.removePropertyChangeListener(this);
               if (j2p.getPrintPreviewCloseOnPrint() == J2Printer.WAIT && j2p.isPrintDialogResponse())
                  closePrintPreview(); // if hit "OK" + close-on-print
            }
            else if (j2p.isPrintDialogUsed() == false && evt.getPropertyName().equals("printingUnderway")) { // if no print dialog used
               setBusyCursor(false);
               j2p.removePropertyChangeListener(this);
               if (j2p.getPrintPreviewCloseOnPrint() == J2Printer.WAIT)
                  closePrintPreview(); // if close-on-print
            }
         }
      });

      new Thread() {
         public void run() {
            try {
               sleep(100);
            } catch (Exception e) {}
            ;
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  j2p.print();
               }
            });
         }
      }.start();

   }

   private void setBusyCursor(boolean busy) {
      J2Printer.setBusyCursor(this, busy);
      J2Printer.setBusyCursor(frame, busy);
   }

   private void closePrintPreview() {
      closePressed();
   }

   private void pageSetupPressed() {
      setBusyCursor(true);
      if (j2p.getPrintPreviewPageSetupDialog() != null)
         j2p.getPrintPreviewPageSetupDialog().setVisible(true);
      else
         j2p.showPageSetupDialog();
      pageable = j2p.getPageable();
      numberOfPages = pageable.getNumberOfPages();
      currentPage = Math.min(currentPage, numberOfPages);
      numberOfPagesLabel.setText(numberOfPages + "");
      enableViewButtons();
      displayCurrentPage(true);
      setBusyCursor(false);
   }

   private void closePressed() {
      printButton.removeActionListener(printAction);
      pageSetupButton.removeActionListener(pageSetupAction);
      closeButton.removeActionListener(closeAction);
      firstPageButton.removeActionListener(firstPageAction);
      previousPageButton.removeActionListener(previousPageAction);
      nextPageButton.removeActionListener(nextPageAction);
      lastPageButton.removeActionListener(lastPageAction);
      zoomOutButton.removeActionListener(zoomOutAction);
      zoomInButton.removeActionListener(zoomInAction);
      currentPageField.removeActionListener(currentPageAction);
      onePageButton.removeActionListener(onePageAction);
      twoPageButton.removeActionListener(twoPageAction);
      scaleField.removeActionListener(scaleAction);
      this.setVisible(false);
      disposeImageDisplayObjects();
      frame=null; pageable=null;
   }

   void disposeImageDisplayObjects() { // help the garbage collector
      if (image1 != null) {
         image1.flush();
         image1 = null;
      }
      if (image2 != null) {
         image2.flush();
         image2 = null;
      }
      if (j2p != null) {
         j2p.disposePageImageBuffers();
      }
      pageDisplayPanel = null;
      scrollpane = null;
   }

   static void disposePrintPreviewDialogObjects() {
     instance.disposeImageDisplayObjects();
     instance=null;
     toolBar=null; toolBarPanel=null;

     printButton=null; pageSetupButton=null; firstPageButton=null;
     previousPageButton=null; nextPageButton=null;
     lastPageButton=null; zoomOutButton=null; zoomInButton=null;
     onePageButton=null; twoPageButton=null; closeButton=null;
     previousPageString=null; nextPageString=null; firstPageString=null;
     lastPageString=null; zoomOutString=null; zoomInString=null;
     twoPageString=null; onePageString=null; printPreviewString=null;
     printString=null; pageSetupString=null; closeString=null; pageString=null;
     ofString=null; numberOfPagesString=null; currentPageField=null;
     scaleField=null; pageLabel=null; ofLabel=null; numberOfPagesLabel=null;
     separatorPrintPageSetup=null; separatorPageSetupFirstPage=null;
     separatorLastPageZoomOut=null; separatorZoomInOnePage=null;
     separatorTwoPageClose=null;

     rememberLocale=null; iconImage=null;
     instance.j2p = null;
   }

   static void setPrintPreviewString(J2Printer j2p, String name, String value) {
      Locale newLocale = getLocale(j2p);
      if (!newLocale.equals(rememberLocale)) {
         rememberLocale = newLocale;
         setupStringResources(rememberLocale);
      }

      isCrossPlatform = isCrossPlatform(j2p);

      if ("PRINT".equalsIgnoreCase(name))
         printString = value;
      else if ("PREVIOUSPAGE".equalsIgnoreCase(name))
         previousPageString = value;
      else if ("NEXTPAGE".equalsIgnoreCase(name))
         nextPageString = value;
      else if ("PAGESETUP".equalsIgnoreCase(name))
         pageSetupString = value;
      else if ("DONE".equalsIgnoreCase(name))
         closeString = value;
      else if ("FIRSTPAGE".equalsIgnoreCase(name))
         firstPageString = value;
      else if ("LASTPAGE".equalsIgnoreCase(name))
         lastPageString = value;
      else if ("ZOOMOUT".equalsIgnoreCase(name))
         zoomOutString = value;
      else if ("ZOOMIN".equalsIgnoreCase(name))
         zoomInString = value;
      else if ("TWOPAGEDISPLAY".equalsIgnoreCase(name))
         twoPageString = value;
      else if ("ONEPAGEDISPLAY".equalsIgnoreCase(name))
         onePageString = value;
      else if ("PAGE".equalsIgnoreCase(name))
         pageString = value;
      else if ("OF".equalsIgnoreCase(name))
         ofString = value;
      else if ("PRINTPREVIEW".equalsIgnoreCase(name))
         printPreviewString = value;
      createToolBar();
   }

   static String getPrintPreviewString(J2Printer j2p, String name) {
      boolean createToolBar = false;
      Locale newLocale = getLocale(j2p);
      if (!newLocale.equals(rememberLocale)) {
         rememberLocale = newLocale;
         setupStringResources(rememberLocale);
         createToolBar = true;
      }

      boolean wasCrossPlatform = isCrossPlatform;
      isCrossPlatform = isCrossPlatform(j2p);
      if (createToolBar || isCrossPlatform != wasCrossPlatform)
         createToolBar();

      if ("PRINT".equalsIgnoreCase(name))
         return printString;
      else if ("PREVIOUSPAGE".equalsIgnoreCase(name))
         return previousPageString;
      else if ("NEXTPAGE".equalsIgnoreCase(name))
         return nextPageString;
      else if ("PAGESETUP".equalsIgnoreCase(name))
         return pageSetupString;
      else if ("DONE".equalsIgnoreCase(name))
         return closeString;
      else if ("FIRSTPAGE".equalsIgnoreCase(name))
         return firstPageString;
      else if ("LASTPAGE".equalsIgnoreCase(name))
         return lastPageString;
      else if ("ZOOMOUT".equalsIgnoreCase(name))
         return zoomOutString;
      else if ("ZOOMIN".equalsIgnoreCase(name))
         return zoomInString;
      else if ("TWOPAGEDISPLAY".equalsIgnoreCase(name))
         return twoPageString;
      else if ("ONEPAGEDISPLAY".equalsIgnoreCase(name))
         return onePageString;
      else if ("PAGE".equalsIgnoreCase(name))
         return pageString;
      else if ("OF".equalsIgnoreCase(name))
         return ofString;
      else if ("PRINTPREVIEW".equalsIgnoreCase(name))
         return printPreviewString;
      return "";
   }

   private static Locale getLocale(J2Printer j2p) {
      Locale newLocale;
      try {
         newLocale = j2p.getLocale();
      } catch (IllegalComponentStateException e) {
         newLocale = java.util.Locale.getDefault();
      }
      return newLocale;
   }

}

