/*
 * @(#)JPDFFilePanel.java  1.2  2010-01-29
 * 
 * Copyright (c) 2008-2010 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.pdf;

import ch.randelshofer.gui.GlassPaneProgressView;
import ch.randelshofer.pdf.action.*;
import ch.randelshofer.pdf.plaf.*;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import javax.swing.event.ChangeEvent;
import org.jhotdraw.util.ResourceBundleUtil;
import com.sun.pdfview.*;
import java.applet.AppletContext;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.ParseException;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.*;

/**
 * A Swing-based panel that displays a PDF file.
 *
 * @author Werner Randelshofer, Hausmatt 10, CH-6405 Immensee
 * @version 1.2 2010-01-29 Toggle subpixel antialiasing using the "s" key.
 * <br>1.1 2009-11-22 Added rotate page function.
 * <br>1.0 September 18, 2008 Created.
 */
public class JPDFFilePanel extends javax.swing.JPanel {

    public final static double SLIDER_POWER = 1.6;
    public final static double SLIDER_BASE = Math.pow(50, SLIDER_POWER);
    public final static String APPLET_CONTEXT_PROPERTY = "appletContext";
    public final static String DOCUMENT_URL_PROPERTY = "documentURL";
    public final static String PDF_PROPERTY = "pdf";
    public final static String CURRENT_PAGE_NUMBER_PROPERTY = "currentPageNumber";
    private PDFFile pdf;
    private URL documentURL;
    private DecimalFormat decimalFormat = new DecimalFormat("#.#");
    /**
     * Current Page number.
     */
    private int curpage;
    /** a thread that pre-loads the next page for faster response */
    private PagePreparer pagePrep;
    private AppletContext appletContext;
    private boolean isOpenWindowEnabled;

    private class EventHandler implements PageChangeListener, PropertyChangeListener, ActionListener, ChangeListener {

        private int busy;

        @Override
        public void gotoPage(int pageNumber) {
            JPDFFilePanel.this.setCurrentPageNumber(pageNumber);
        }

        @Override
        public void gotoPage(PDFDestination dest) {
            try {
                JPDFFilePanel.this.setCurrentPageNumber(pdf.getPageNumber(dest.getPage()));
                if (dest.getZoom() != 0) {
                    pagePanel.setPreferredZoomFactor(dest.getZoom());
                }
                pagePanel.scrollPageRectToVisible(new Rectangle2D.Float(dest.getLeft(), dest.getTop(), Math.max(1, dest.getRight() - dest.getLeft()), Math.max(1, dest.getBottom() - dest.getTop())));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (busy++ == 0) {
                String name = evt.getPropertyName();
                if (name == JPDFPagePanel.ZOOM_FACTOR_PROPERTY) {
                    double zoomFactor = (Double) evt.getNewValue();
                    zoomFactorField.setText(decimalFormat.format(zoomFactor * 100d));
                    updateZoomSliderValue();
                }
                if (evt.getSource() == thumbnailsPanel) {
                    if (name == "preferredSize") {
                        updateDividerLocation();
                    }
                }
            }
            busy--;
        }

        @Override
        public void actionPerformed(ActionEvent evt) {
            if (busy++ == 0) {
                if (evt.getSource() == zoomFactorField) {
                    String str = (String) zoomFactorField.getText();
                    if (str.equals(labels.getTextProperty("view.zoom.actualSize"))) {
                        setZoomPolicy(ZoomPolicy.FIXED_SIZE);
                        pagePanel.setPreferredZoomFactor(1);
                    } else if (str.equals(labels.getTextProperty("view.zoom.fitWidth"))) {
                        getActionMap().get(ViewZoomFitWidthAction.ID).actionPerformed(evt);
                    } else if (str.equals(labels.getTextProperty("view.zoom.fitHeight"))) {
                        getActionMap().get(ViewZoomFitHeightAction.ID).actionPerformed(evt);
                    } else if (str.equals(labels.getTextProperty("view.zoom.fitPage"))) {
                        getActionMap().get(ViewZoomFitPageAction.ID).actionPerformed(evt);
                    } else if (str.equals(labels.getTextProperty("view.rotatePage"))) {
                        getActionMap().get(ViewRotatePageAction.ID).actionPerformed(evt);
                    } else {
                        try {
                            str = str.trim();
                            if (str.endsWith("%")) {
                                str = str.substring(0, str.length() - 1).trim();
                            }
                            //double zoomFactor = Double.parseDouble(str) / 100d;
                            double zoomFactor = decimalFormat.parse(str).doubleValue() / 100d;
                            setZoomPolicy(ZoomPolicy.FIXED_SIZE);
                            pagePanel.setPreferredZoomFactor(zoomFactor);
                            updateZoomSliderValue();
                        } catch (ParseException e) {
                        }
                    }
                } else if (evt.getSource() == pageNumberField) {
                    String str = (String) pageNumberField.getText();
                    try {
                        int pageNumber = decimalFormat.parse(str).intValue();
                        if (pageNumber >= 1 && pageNumber <= pdf.getNumPages());
                        setCurrentPageNumber(pageNumber - 1);
                    } catch (ParseException e) {
                    }
                }
            }
            busy--;
        }
        /** Center of the zoom currently being in progress. */
        private Point2D.Double zoomCenter;
        private boolean sliderIsAdjusting;

        @Override
        public void stateChanged(ChangeEvent e) {
            if (busy++ == 0) {
                Object src = e.getSource();
                if (src == pageScrollPane.getHorizontalScrollBar().getModel()
                        || src == pageScrollPane.getVerticalScrollBar().getModel()) {
                    if (!sliderIsAdjusting) {
                        // zoomCenter = null;
                    }
                } else if (src == zoomFactorSlider) {
                    sliderIsAdjusting = zoomFactorSlider.getModel().getValueIsAdjusting();
                    if (zoomCenter == null) {
                        Rectangle oldViewRect = pageScrollPane.getViewport().getViewRect();
                        Dimension oldViewSize = pageScrollPane.getViewport().getViewSize();
                        zoomCenter = new Point2D.Double(
                                (oldViewRect.x + oldViewRect.width / 2) / (double) oldViewSize.width,
                                (oldViewRect.y + oldViewRect.height / 2) / (double) oldViewSize.height);
                    }
                    int sliderValue = zoomFactorSlider.getValue();
                    double zoomFactor = Math.pow(sliderValue, SLIDER_POWER) / SLIDER_BASE;
                    setZoomPolicy(ZoomPolicy.FIXED_SIZE);
                    pagePanel.setPreferredZoomFactor(zoomFactor);

                    if (zoomCenter != null) {
                        Rectangle newViewRect = pageScrollPane.getViewport().getViewRect();
                        Dimension newViewSize = pageScrollPane.getViewport().getViewSize();
                        pageScrollPane.getViewport().setViewPosition(new Point(
                                (int) (newViewSize.width * zoomCenter.x) - newViewRect.width / 2,
                                (int) (newViewSize.height * zoomCenter.y) - newViewRect.height / 2));

                        if (!zoomFactorSlider.getValueIsAdjusting()) {
                            zoomCenter = null;
                        }
                    }
                }
            }
            busy--;
        }
    }
    private EventHandler eventHandler = new EventHandler();
    private ResourceBundleUtil labels;

    /** Creates new form JPDFFilePanel */
    public JPDFFilePanel() {
        labels = ResourceBundleUtil.getBundle("ch.randelshofer.pdf.Labels");

        initComponents();

        pageScrollPane.setBorder(null);
        pageScrollPane.setMinimumSize(new Dimension(0,0));
        thumbnailsScrollPane.setBorder(null);
        thumbnailsScrollPane.setMinimumSize(new Dimension(0,0));
        thumbnailsPanel.addPageChangeListener(eventHandler);
        initActions();
        pagePanel.addPropertyChangeListener(eventHandler);
        pagePanel.addPageChangeListener(eventHandler);
        pageScrollPane.getHorizontalScrollBar().getModel().addChangeListener(eventHandler);
        pageScrollPane.getVerticalScrollBar().getModel().addChangeListener(eventHandler);
        pageNumberField.addActionListener(eventHandler);

        zoomFactorField.setText("100%");
        zoomFactorField.addActionListener(eventHandler);

        PDFLookAndFeel plaf = PDFLookAndFeel.getInstance();
        Color bg = plaf.getColor("Viewport.background");

        thumbnailsPanel.setBackground(bg);
        thumbnailsPanel.setBorder(new EmptyBorder(0, 4, 4, 4));
        thumbnailsPanel.addPropertyChangeListener(eventHandler);
        pagePanel.setBackground(bg);

        nextPageButton.setIcon(plaf.getIcon("View.nextPageIcon"));
        previousPageButton.setIcon(plaf.getIcon("View.previousPageIcon"));
        fitPageButton.setIcon(plaf.getIcon("View.fitPageIcon"));
        fitWidthButton.setIcon(plaf.getIcon("View.fitWidthIcon"));
        openWindowButton.setIcon(plaf.getIcon("View.openInNewWindowIcon"));
        rotatePageButton.setIcon(plaf.getIcon("View.rotatePageIcon"));
        printButton.setIcon(plaf.getIcon("View.printIcon"));

        toolBar.setUI((ToolBarUI) PDFToolBarUI.createUI(toolBar));
        JButton[] buttons = {nextPageButton, previousPageButton, fitPageButton,
            fitWidthButton, openWindowButton, rotatePageButton, printButton};
        for (JButton b : buttons) {
            b.setText(null);
            b.setUI((ButtonUI) PDFButtonUI.createUI(b));
            b.setOpaque(false);
            b.setBorderPainted(false);
        }

        zoomFactorField.setUI((TextUI) PDFTextFieldUI.createUI(zoomFactorField));
        pageNumberField.setUI((TextUI) PDFTextFieldUI.createUI(pageNumberField));
        pageNumberField.setMaximumSize(pageNumberField.getPreferredSize());
        pageNumberField.setMinimumSize(pageNumberField.getPreferredSize());
        zoomFactorField.setMaximumSize(zoomFactorField.getPreferredSize());
        zoomFactorField.setMinimumSize(zoomFactorField.getPreferredSize());
        pageCountLabel.setUI((LabelUI) PDFLabelUI.createUI(pageCountLabel));
        zoomFactorLabel.setUI((LabelUI) PDFLabelUI.createUI(zoomFactorLabel));
        zoomFactorSlider.setUI((SliderUI) PDFSliderUI.createUI(zoomFactorSlider));
        splitPane.setUI((SplitPaneUI) PDFSplitPaneUI.createUI(splitPane));
        Dimension sliderDim = zoomFactorSlider.getPreferredSize();
        sliderDim.width = 100;
        zoomFactorSlider.setPreferredSize(sliderDim);
        zoomFactorSlider.setMinimumSize(sliderDim);
        zoomFactorSlider.setMaximumSize(sliderDim);
        zoomFactorSlider.addChangeListener(eventHandler);
        pageScrollPane.getViewport().setBackground(plaf.getColor("Viewport.background"));
        thumbnailsScrollPane.getViewport().setBackground(plaf.getColor("Viewport.background"));
        pageScrollPane.getHorizontalScrollBar().setUI((ScrollBarUI) PDFScrollBarUI.createUI(pageScrollPane.getHorizontalScrollBar()));
        pageScrollPane.getVerticalScrollBar().setUI((ScrollBarUI) PDFScrollBarUI.createUI(pageScrollPane.getVerticalScrollBar()));
        thumbnailsScrollPane.getHorizontalScrollBar().setUI((ScrollBarUI) PDFScrollBarUI.createUI(thumbnailsScrollPane.getHorizontalScrollBar()));
        thumbnailsScrollPane.getVerticalScrollBar().setUI((ScrollBarUI) PDFScrollBarUI.createUI(thumbnailsScrollPane.getVerticalScrollBar()));
        //setBorder(new LineBorder(new Color(0x666666))); // FIXME - Set this border only for the applet
        pageScrollPane.setViewportBorder(plaf.getBorder("ScrollPane.viewportBorder"));
        separator1.setUI((SeparatorUI) PDFToolBarSeparatorUI.createUI(separator1));
        separator2.setUI((SeparatorUI) PDFToolBarSeparatorUI.createUI(separator2));
        openWindowButton.setVisible(false);

        splitPane.setDividerLocation(thumbnailsPanel.getPreferredSize().width);
    }

    public void setAppletContext(AppletContext newValue) {
        AppletContext oldValue = appletContext;
        appletContext = newValue;
        firePropertyChange(APPLET_CONTEXT_PROPERTY, oldValue, newValue);
        openWindowButton.setVisible(isOpenWindowEnabled && newValue != null);
    }

    public AppletContext getAppletContext() {
        return appletContext;
    }

    public void setDocumentURL(URL newValue) {
        URL oldValue = documentURL;
        documentURL = newValue;
        firePropertyChange(DOCUMENT_URL_PROPERTY, oldValue, newValue);
        openWindowButton.setEnabled(newValue != null);
    }

    public URL getDocumentURL() {
        return documentURL;
    }

    public JPDFPagePanel getPagePanel() {
        return pagePanel;
    }

    private void updateZoomSliderValue() {
        double zoomFactor = pagePanel.getZoomFactor();
        int sliderValue = (int) Math.pow(zoomFactor * SLIDER_BASE, 1 / SLIDER_POWER);
        zoomFactorSlider.setValue(sliderValue);
    }

    public void setZoomPolicy(ZoomPolicy newValue) {
        pageScrollPane.getViewport().invalidate();
        switch (newValue) {
            case FIT_HEIGHT:
                pageScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                pageScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                break;
            case FIT_WIDTH:
                pageScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                pageScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                break;
            case FIT_PAGE:
                pageScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                pageScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                break;
            case FIXED_SIZE:
                pageScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                pageScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                break;
        }

        ZoomableViewportLayout layout = ((ZoomableViewportLayout) pageScrollPane.getViewport().getLayout());
        ZoomPolicy oldValue = layout.getZoomPolicy();
        layout.setZoomPolicy(newValue);
        firePropertyChange(ZoomableViewportLayout.ZOOM_POLICY_PROPERTY, oldValue, newValue);
        pagePanel.invalidate();
        pageScrollPane.validate();
        pageScrollPane.repaint();
    }

    public ZoomPolicy getZoomPolicy() {
        return ((ZoomableViewportLayout) pageScrollPane.getViewport().getLayout()).getZoomPolicy();
    }

    public void setSubpixAAEnabled(boolean newValue) {
        pagePanel.setSubpixAAEnabled(newValue);
    }

    public boolean isSubpixAAEnabled() {
        return pagePanel.isSubpixAAEnabled();
    }

    public void setOpenWindowEnabled(boolean newValue) {
        isOpenWindowEnabled = newValue;
        openWindowButton.setVisible(newValue && appletContext != null);
        toolBar.revalidate();
    }

    public boolean isOpenWindowEnabled() {
        return isOpenWindowEnabled;
    }

    private void initActions() {
        ActionMap am = new ActionMap();
        am.put(ViewGoToNextPageAction.ID, new ViewGoToNextPageAction(this));
        am.put(ViewGoToPreviousPageAction.ID, new ViewGoToPreviousPageAction(this));
        am.put(ViewGoToFirstPageAction.ID, new ViewGoToFirstPageAction(this));
        am.put(ViewGoToLastPageAction.ID, new ViewGoToLastPageAction(this));
        am.put(ViewZoomFitPageAction.ID, new ViewZoomFitPageAction(this));
        am.put(ViewZoomFitWidthAction.ID, new ViewZoomFitWidthAction(this));
        am.put(ViewZoomFitHeightAction.ID, new ViewZoomFitHeightAction(this));
        am.put(ViewZoomIncreaseAction.INCREASE_ID, new ViewZoomIncreaseAction(this, 1.25));
        am.put(ViewZoomIncreaseAction.DECREASE_ID, new ViewZoomIncreaseAction(this, 0.75));
        am.put(ViewOpenInNewWindowAction.ID, new ViewOpenInNewWindowAction(this));
        am.put(ViewRotatePageAction.ID, new ViewRotatePageAction(this));
        am.put(ViewToggleSubpixAAAction.ID, new ViewToggleSubpixAAAction(this));
        setActionMap(am);
        thumbnailsPanel.setActionMap(am);
        pagePanel.setActionMap(am);

        InputMap im = new InputMap();
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), ViewGoToNextPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), ViewGoToPreviousPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), ViewGoToNextPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), ViewGoToPreviousPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), ViewGoToNextPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), ViewGoToPreviousPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), ViewGoToFirstPageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), ViewGoToLastPageAction.ID);
        im.put(KeyStroke.getKeyStroke('+'), ViewZoomIncreaseAction.INCREASE_ID);
        im.put(KeyStroke.getKeyStroke('-'), ViewZoomIncreaseAction.DECREASE_ID);
        im.put(KeyStroke.getKeyStroke('s'), ViewToggleSubpixAAAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.META_DOWN_MASK), ViewRotatePageAction.ID);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK), ViewRotatePageAction.ID);

        setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, im);
        setInputMap(WHEN_FOCUSED, im);
        thumbnailsPanel.setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, im);
        thumbnailsPanel.setInputMap(WHEN_FOCUSED, im);
        pagePanel.setInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, im);
        pagePanel.setInputMap(WHEN_FOCUSED, im);
        pagePanel.setOpaque(false);
        pageNumberField.setUI((TextUI) PDFTextFieldUI.createUI(zoomFactorField));

        pageScrollPane.getViewport().setLayout(new ZoomableViewportLayout());

        zoomFactorField.setUI((TextUI) PDFTextFieldUI.createUI(zoomFactorField));
        zoomFactorField.setMaximumSize(zoomFactorField.getPreferredSize());
        zoomFactorField.setMinimumSize(zoomFactorField.getPreferredSize());
        zoomFactorSlider.setMaximumSize(zoomFactorSlider.getPreferredSize());

        nextPageButton.setAction(am.get(ViewGoToNextPageAction.ID));
        previousPageButton.setAction(am.get(ViewGoToPreviousPageAction.ID));
        fitPageButton.setAction(am.get(ViewZoomFitPageAction.ID));
        fitWidthButton.setAction(am.get(ViewZoomFitWidthAction.ID));
        rotatePageButton.setAction(am.get(ViewRotatePageAction.ID));

        setZoomPolicy(ZoomPolicy.FIT_WIDTH);
    }

    public JPDFThumbnailsPanel getThumbnailsPanel() {
        return thumbnailsPanel;
    }

    public void setPDF(PDFFile newValue) {
        PDFFile oldValue = pdf;
        this.pdf = newValue;
        thumbnailsPanel.setPDF(newValue);

        firePropertyChange(PDF_PROPERTY, oldValue, newValue);

        splitPane.setDividerLocation(1);
        
        if (pdf != null) {
            setCurrentPageNumber(0);
            pageCountLabel.setText("/" + pdf.getNumPages());
        } else {
            pageNumberField.setText("");
            pageCountLabel.setText("");
            pagePanel.setPage(null);
        }

        boolean b = pdf != null;
        setEnabled(b);
    }

    public PDFFile getPDF() {
        return pdf;
    }

    public void setCurrentPageNumber(int newValue) {
        if (newValue < 0) {
            newValue = 0;
        } else if (newValue >= pdf.getNumPages()) {
            newValue = pdf.getNumPages() - 1;
        }
        forceGotoPage(newValue);
    }

    public int getCurrentPageNumber() {
        return curpage;
    }

    public int getPageCount() {
        return (pdf == null) ? 0 : pdf.getNumPages();
    }

    /**
     * Changes the displayed page.
     * @param newValue the page to display
     */
    protected void forceGotoPage(int newValue) {
        int oldValue = curpage;

        if (newValue <= 0) {
            newValue = 0;
        } else if (newValue >= pdf.getNumPages()) {
            newValue = pdf.getNumPages() - 1;
        }
//        System.out.println("Going to page " + newValue);
        curpage = newValue;

        // update the page text field
        pageNumberField.setText(String.valueOf(curpage + 1));

        // fetch the page and show it in the appropriate place
        PDFPage pg = pdf.getPage(newValue + 1);
        pagePanel.setPage(pg);
        pagePanel.requestFocus();

        // update the thumb panel
        //if (doThumb) {
        thumbnailsPanel.pageShown(newValue);
        //}

        // stop any previous page prepper, and start a new one
        if (pagePrep != null) {
            pagePrep.quit();
        }
        pagePrep = new PagePreparer(newValue);
        pagePrep.start();

//            setEnabling();
        firePropertyChange(CURRENT_PAGE_NUMBER_PROPERTY, oldValue, newValue);
    }

    public void dispose() {
        if (pdf != null) {
            pdf = null;
        }
    }

    /**
     * A class to pre-cache the next page for better UI response
     */
    class PagePreparer extends Thread {

        int waitforPage;
        int prepPage;

        /**
         * Creates a new PagePreparer to prepare the page after the current
         * one.
         * @param waitforPage the current page number, 0 based 
         */
        public PagePreparer(int waitforPage) {
            setDaemon(true);

            this.waitforPage = waitforPage;
            this.prepPage = waitforPage + 1;
        }

        public void quit() {
            waitforPage = -1;
        }

        @Override
        public void run() {
            Dimension size = null;
            Rectangle2D clip = null;

            // wait for the current page
            //            System.out.println("Preparer waiting for page " + (waitforPage + 1));
            pagePanel.waitForCurrentPage();
            size = pagePanel.getViewRect().getSize();
            clip = pagePanel.getClipRect();

            if (waitforPage == curpage) {
                // don't go any further if the user changed pages.
                //                System.out.println("Preparer generating page " + (prepPage + 2));
                PDFPage pdfPage = pdf.getPage(prepPage + 1, true);
                if (pdfPage != null && waitforPage == curpage) {
                    // don't go any further if the user changed pages
                    //                    System.out.println("Generating image for page " + (prepPage + 2));

                    pdfPage.getImage(size.width, size.height, clip, null, true, true);
                    //		    System.out.println("Generated image for page "+ (prepPage+2));
                }
            }
        }
    }

    @Override
    public void setEnabled(boolean b) {
        super.setEnabled(b);

        JComponent[] cs = {pageScrollPane,previousPageButton, nextPageButton,
            rotatePageButton, printButton, openWindowButton, fitPageButton,
            fitWidthButton, zoomFactorSlider, zoomFactorField, pageNumberField};
        for (JComponent c : cs) {
            c.setEnabled(b);
        }
    }

    private void updateDividerLocation() {
        int newDividerLocation;
        if (pdf == null || pdf.getNumPages() < 2) {
            newDividerLocation = Math.max(splitPane.getDividerLocation(), 1);
        } else {
            Dimension ps = thumbnailsPanel.getPreferredSize();
            if (ps.height > pageScrollPane.getViewport().getHeight()) {
                ps.width += pageScrollPane.getVerticalScrollBar().getPreferredSize().getWidth();
            }
            Border vb = pageScrollPane.getViewportBorder();
            if (vb != null) {
                Insets vbi = vb.getBorderInsets(pageScrollPane.getViewport());
                ps.width += vbi.left + vbi.right;
            }
            Border sb = pageScrollPane.getBorder();
            if (sb != null) {
                Insets sbi = sb.getBorderInsets(pageScrollPane);
                ps.width += sbi.left + sbi.right;
            }

            newDividerLocation = Math.max(splitPane.getDividerLocation(), ps.width);
        }
        if (newDividerLocation != splitPane.getDividerLocation()) {
            splitPane.setDividerLocation(newDividerLocation);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        splitPane = new javax.swing.JSplitPane();
        pageScrollPane = new javax.swing.JScrollPane();
        pagePanel = new ch.randelshofer.pdf.JPDFPagePanel();
        thumbnailsScrollPane = new javax.swing.JScrollPane();
        thumbnailsPanel = new ch.randelshofer.pdf.JPDFThumbnailsPanel();
        toolBar = new javax.swing.JToolBar();
        previousPageButton = new javax.swing.JButton();
        nextPageButton = new javax.swing.JButton();
        pageNumberField = new javax.swing.JTextField();
        pageCountLabel = new javax.swing.JLabel();
        separator1 = new javax.swing.JToolBar.Separator();
        zoomFactorSlider = new javax.swing.JSlider();
        zoomFactorField = new javax.swing.JTextField();
        zoomFactorLabel = new javax.swing.JLabel();
        separator2 = new javax.swing.JToolBar.Separator();
        fitWidthButton = new javax.swing.JButton();
        fitPageButton = new javax.swing.JButton();
        rotatePageButton = new javax.swing.JButton();
        openWindowButton = new javax.swing.JButton();
        printButton = new javax.swing.JButton();

        setLayout(new java.awt.BorderLayout());

        pageScrollPane.setViewportView(pagePanel);

        splitPane.setRightComponent(pageScrollPane);

        thumbnailsScrollPane.setViewportView(thumbnailsPanel);

        splitPane.setLeftComponent(thumbnailsScrollPane);

        add(splitPane, java.awt.BorderLayout.CENTER);

        toolBar.setFloatable(false);
        toolBar.setRollover(true);

        previousPageButton.setText(labels.getString("view.goTo.previousPage.text")); // NOI18N
        previousPageButton.setToolTipText(labels.getString("view.goTo.previousPage.toolTipText")); // NOI18N
        previousPageButton.setEnabled(false);
        previousPageButton.setFocusable(false);
        previousPageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        previousPageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBar.add(previousPageButton);

        nextPageButton.setText(labels.getString("view.goTo.nextPage.text")); // NOI18N
        nextPageButton.setToolTipText(labels.getString("view.goTo.nextPage.toolTipText")); // NOI18N
        nextPageButton.setEnabled(false);
        nextPageButton.setFocusable(false);
        nextPageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        nextPageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBar.add(nextPageButton);

        pageNumberField.setColumns(3);
        pageNumberField.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        pageNumberField.setEnabled(false);
        toolBar.add(pageNumberField);

        pageCountLabel.setAlignmentY(0.51F);
        toolBar.add(pageCountLabel);
        toolBar.add(separator1);

        zoomFactorSlider.setMinimum(5);
        zoomFactorSlider.setEnabled(false);
        toolBar.add(zoomFactorSlider);

        zoomFactorField.setColumns(4);
        zoomFactorField.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        zoomFactorField.setEnabled(false);
        toolBar.add(zoomFactorField);

        zoomFactorLabel.setText("%");
        toolBar.add(zoomFactorLabel);
        toolBar.add(separator2);

        fitWidthButton.setText(labels.getString("view.zoom.fitWidth.text")); // NOI18N
        fitWidthButton.setToolTipText(labels.getString("view.zoom.fitWidth.toolTipText")); // NOI18N
        fitWidthButton.setEnabled(false);
        fitWidthButton.setFocusable(false);
        fitWidthButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        fitWidthButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBar.add(fitWidthButton);

        fitPageButton.setText(labels.getString("view.zoom.fitPage.text")); // NOI18N
        fitPageButton.setToolTipText(labels.getString("view.zoom.fitPage.toolTipText")); // NOI18N
        fitPageButton.setEnabled(false);
        fitPageButton.setFocusable(false);
        fitPageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        fitPageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBar.add(fitPageButton);

        rotatePageButton.setText(labels.getString("view.rotatePage.text")); // NOI18N
        rotatePageButton.setToolTipText(labels.getString("view.rotatePage.toolTipText")); // NOI18N
        rotatePageButton.setEnabled(false);
        rotatePageButton.setFocusable(false);
        rotatePageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        rotatePageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBar.add(rotatePageButton);

        openWindowButton.setText(labels.getString("view.openInNewWindow.text")); // NOI18N
        openWindowButton.setToolTipText(labels.getString("view.openInNewWindow.toolTipText")); // NOI18N
        openWindowButton.setEnabled(false);
        openWindowButton.setFocusable(false);
        openWindowButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        openWindowButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        openWindowButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openWindowPerformed(evt);
            }
        });
        toolBar.add(openWindowButton);

        printButton.setText("Print");
        printButton.setToolTipText("Click to print the document");
        printButton.setEnabled(false);
        printButton.setFocusable(false);
        printButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        printButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        printButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                printPerformed(evt);
            }
        });
        toolBar.add(printButton);

        add(toolBar, java.awt.BorderLayout.PAGE_START);
    }// </editor-fold>//GEN-END:initComponents

private void openWindowPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openWindowPerformed
    if (appletContext != null && documentURL != null) {
        appletContext.showDocument(documentURL);
    }
}//GEN-LAST:event_openWindowPerformed

private void printPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_printPerformed
    if (pdf == null || !isEnabled()) {
        return;
    }

    setEnabled(false);

    GlassPaneProgressView p = new GlassPaneProgressView("Print PDF Document", null, true);
    JRootPane rp = SwingUtilities.getRootPane(this);
    if (rp != null) {
        rp.setGlassPane(p);
        p.setVisible(true);
    }
    PDFPrintPage pp = new PDFPrintPage(pdf);
    try {
        pp.printFile(false, p);
    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        p.close();
        setEnabled(true);
    }

}//GEN-LAST:event_printPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton fitPageButton;
    private javax.swing.JButton fitWidthButton;
    private javax.swing.JButton nextPageButton;
    private javax.swing.JButton openWindowButton;
    private javax.swing.JLabel pageCountLabel;
    private javax.swing.JTextField pageNumberField;
    private ch.randelshofer.pdf.JPDFPagePanel pagePanel;
    private javax.swing.JScrollPane pageScrollPane;
    private javax.swing.JButton previousPageButton;
    private javax.swing.JButton printButton;
    private javax.swing.JButton rotatePageButton;
    private javax.swing.JToolBar.Separator separator1;
    private javax.swing.JToolBar.Separator separator2;
    private javax.swing.JSplitPane splitPane;
    private ch.randelshofer.pdf.JPDFThumbnailsPanel thumbnailsPanel;
    private javax.swing.JScrollPane thumbnailsScrollPane;
    private javax.swing.JToolBar toolBar;
    private javax.swing.JTextField zoomFactorField;
    private javax.swing.JLabel zoomFactorLabel;
    private javax.swing.JSlider zoomFactorSlider;
    // End of variables declaration//GEN-END:variables
}
