123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- /*
- * Copyright 1999-2005 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.render.awt.viewer;
-
- import java.awt.Color;
- import java.awt.Dimension;
- import java.awt.GridLayout;
- import java.awt.Point;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseListener;
- import java.awt.event.MouseMotionListener;
- import java.awt.geom.Rectangle2D;
-
- import javax.swing.JLabel;
- import javax.swing.JOptionPane;
- import javax.swing.JPanel;
- import javax.swing.JScrollPane;
- import javax.swing.JViewport;
- import javax.swing.SwingUtilities;
- import javax.swing.border.EmptyBorder;
-
- import org.apache.fop.apps.Fop;
- import org.apache.fop.apps.FOPException;
- import org.apache.fop.apps.FOUserAgent;
- import org.apache.fop.apps.MimeConstants;
- import org.apache.fop.area.PageViewport;
-
- import org.apache.fop.render.awt.AWTRenderer;
-
-
- /**
- * <p>Holds a scrollpane with the rendered page(s) and handles actions performed
- * to alter the display of the page.
- * </p>
- * <p>Use PreviewPanel when you want to embed a preview in your own application
- * with your own controls. Use PreviewDialog when you want to use the standard
- * Fop controls.
- * </p>
- * <p>In order to embed a PreviewPanel in your own app, create your own renderer,
- * and your own agent. In order to support reloads, you may also implement your
- * own Renderable extension or the default InputHandler. Setting the Renderable
- * to null works fine though.
- * Then call setPreviewDialogDisplayed(false) to hide the
- * default dialog. Finally create a preview panel with the agent, renderable and
- * renderer and add it to your gui:
- * </p>
- * <pre>
- * AWTRenderer renderer = new AWTRenderer();
- * FOUserAgent agent = new FOUserAgent();
- * agent.setRendererOverride(renderer);
- * renderer.setPreviewDialogDisplayed(false);
- * renderer.setUserAgent(agent);
- * previewPanel = new PreviewPanel(agent, null, renderer);
- * previewPanel = new PreviewPanel(ua);
- * myGui.add(previewPanel);
- * </pre>
- *
- * In order to set options and display a page do:
- * <pre>
- * renderer.clearViewportList();
- * // build report xml here
- * reload(); // optional if setting changed
- * </pre>
- *
- * If you wan't to change settings, don't call reload. A good example is
- * to set the page to fill the screen and set the scrolling mode:
- * <pre>
- * double scale = previewPanel.getScaleToFitWindow();
- * previewPanel.setScaleFactor(scale);
- * previewPanel.setDisplayMode(PreviewPanel.CONTINUOUS);
- * </pre>
- */
- public class PreviewPanel extends JPanel {
-
- /** Constant for setting single page display. */
- public static final int SINGLE = 1;
- /** Constant for setting continuous page display. */
- public static final int CONTINUOUS = 2;
- /** Constant for displaying even/odd pages side by side in continuous form. */
- public static final int CONT_FACING = 3;
-
- /** The number of pixels left empty at the top bottom and sides of the page. */
- private static final int BORDER_SPACING = 10;
-
- /** The main display area */
- private JScrollPane previewArea;
-
- /** The AWT renderer - often shared with PreviewDialog */
- private AWTRenderer renderer;
-
- /** The FOUserAgent associated with this panel - often shared with PreviewDialog */
- protected FOUserAgent foUserAgent;
- /**
- * Renderable instance that can be used to reload and re-render a document after
- * modifications.
- */
- protected Renderable renderable;
- /** The number of the page which is currently selected */
- private int currentPage = 0;
-
- /** The index of the first page displayed on screen. */
- private int firstPage = 0;
-
- /** The number of pages concurrently displayed on screen. */
- private int pageRange = 1;
-
- /** The display mode. One of SINGLE, CONTINUOUS or CONT_FACING. */
- private int displayMode = SINGLE;
-
- /** The component(s) that hold the rendered page(s) */
- private ImageProxyPanel[] pagePanels = null;
-
- /**
- * Panel showing the page panels in a grid. Usually the dimensions
- * of the grid are 1x1, nx1 or nx2.
- */
- private JPanel gridPanel = null;
-
- /** Asynchronous reloader thread, used when reload() method is called. */
- private Reloader reloader;
-
- /** The Fop object used for refreshing/reloading the view */
- protected Fop fop;
-
- /**
- * Allows any mouse drag on the page area to scroll the display window.
- */
- private ViewportScroller scroller;
-
-
- /**
- * Creates a new PreviewPanel instance.
- * @param foUserAgent the user agent
- * @param renderable the Renderable instance that is used to reload/re-render a document
- * after modifications.
- * @param renderer the AWT Renderer instance to paint with
- */
- public PreviewPanel(FOUserAgent foUserAgent, Renderable renderable, AWTRenderer renderer) {
- super(new GridLayout(1, 1));
- this.renderable = renderable;
- this.renderer = renderer;
- this.foUserAgent = foUserAgent;
-
- gridPanel = new JPanel();
- gridPanel.setLayout(new GridLayout(0, 1)); // rows, cols
-
- previewArea = new JScrollPane(gridPanel);
- previewArea.getViewport().setBackground(Color.gray);
-
- // FIXME should add scroll wheel support here at some point.
- scroller = new ViewportScroller(previewArea.getViewport());
- previewArea.addMouseListener(scroller);
- previewArea.addMouseMotionListener(scroller);
-
- previewArea.setMinimumSize(new Dimension(50, 50));
- add(previewArea);
- }
-
- /**
- * @return the currently visible page
- */
- public int getPage() {
- return currentPage;
- }
-
- /**
- * Selects the given page, displays it on screen and notifies
- * listeners about the change in selection.
- * @param number the page number
- */
- public void setPage(int number) {
- if (displayMode == CONTINUOUS || displayMode == CONT_FACING) {
- // FIXME Should scroll so page is visible
- currentPage = number;
- } else { // single page mode
- currentPage = number;
- firstPage = currentPage;
- }
- showPage();
- }
-
- /**
- * Sets the display mode.
- * @param mode One of SINGLE, CONTINUOUS or CONT_FACING.
- */
- public void setDisplayMode(int mode) {
- if (mode != displayMode) {
- displayMode = mode;
- gridPanel.setLayout(new GridLayout(0, displayMode == CONT_FACING ? 2 : 1));
- reload();
- }
- }
-
- /**
- * Returns the display mode.
- * @return mode One of SINGLE, CONTINUOUS or CONT_FACING.
- */
- public int getDisplayMode() {
- return displayMode;
- }
-
- /**
- * Reloads and reformats document.
- */
- public synchronized void reload() {
- if (reloader == null || !reloader.isAlive()) {
- reloader = new Reloader();
- reloader.start();
- }
- }
-
- /**
- * Allows a (yet) simple visual debug of the document.
- */
- void debug() {
- renderer.debug = !renderer.debug;
- reload();
- }
-
- /**
- * Allows any mouse drag on the page area to scroll the display window.
- */
- private class ViewportScroller implements MouseListener, MouseMotionListener {
- /** The viewport to be scrolled */
- private final JViewport viewport;
- /** Starting position of a mouse drag - X co-ordinate */
- private int startPosX = 0;
- /** Starting position of a mouse drag - Y co-ordinate */
- private int startPosY = 0;
-
- ViewportScroller(JViewport vp) {
- viewport = vp;
- }
-
- // ***** MouseMotionListener *****
-
- public synchronized void mouseDragged(MouseEvent e) {
- if (viewport == null) {
- return;
- }
- int x = e.getX();
- int y = e.getY();
- int xmove = x - startPosX;
- int ymove = y - startPosY;
- int viewWidth = viewport.getExtentSize().width;
- int viewHeight = viewport.getExtentSize().height;
- int imageWidth = viewport.getViewSize().width;
- int imageHeight = viewport.getViewSize().height;
-
- Point viewPoint = viewport.getViewPosition();
- int viewX = Math.max(0, Math.min(imageWidth - viewWidth, viewPoint.x - xmove));
- int viewY = Math.max(0, Math.min(imageHeight - viewHeight, viewPoint.y - ymove));
-
- viewport.setViewPosition(new Point(viewX, viewY));
-
- startPosX = x;
- startPosY = y;
- }
-
- public void mouseMoved(MouseEvent e) { }
-
- // ***** MouseListener *****
-
- public void mousePressed(MouseEvent e) {
- startPosX = e.getX();
- startPosY = e.getY();
- }
-
- public void mouseExited(MouseEvent e) { }
- public void mouseEntered(MouseEvent e) { }
- public void mouseClicked(MouseEvent e) { }
- public void mouseReleased(MouseEvent e) { }
- }
-
- /**
- * This class is used to reload document in a thread safe way.
- */
- private class Reloader extends Thread {
-
- public void run() {
- if (!renderer.renderingDone) {
- // do not allow the reloading while FOP is still rendering
- JOptionPane.showMessageDialog(previewArea,
- "Cannot perform the requested operation until "
- + "all page are rendered. Please wait",
- "Please wait ", 1 /* INFORMATION_MESSAGE */);
- return;
- }
-
- //Always recreate the Fop instance. It is a use-once only.
- fop = new Fop(MimeConstants.MIME_FOP_AWT_PREVIEW, foUserAgent);
-
- pagePanels = null;
-
- int savedCurrentPage = currentPage;
- currentPage = 0;
-
- gridPanel.removeAll();
- switch(displayMode) {
- case CONT_FACING:
- // This page intentionally left blank
- // Makes 0th/1st page on rhs
- gridPanel.add(new JLabel(""));
- case CONTINUOUS:
- currentPage = 0;
- firstPage = 0;
- pageRange = renderer.getNumberOfPages();
- break;
- case SINGLE:
- default:
- currentPage = 0;
- firstPage = 0;
- pageRange = 1;
- break;
- }
-
- pagePanels = new ImageProxyPanel[pageRange];
- for (int pg = 0; pg < pageRange; pg++) {
- pagePanels[pg] = new ImageProxyPanel(renderer, pg + firstPage);
- pagePanels[pg].setBorder(new EmptyBorder(
- BORDER_SPACING, BORDER_SPACING, BORDER_SPACING, BORDER_SPACING));
- gridPanel.add(pagePanels[pg]);
- }
-
- try {
- if (renderable != null) {
- renderer.clearViewportList();
- renderable.render(fop);
- }
- } catch (FOPException e) {
- e.printStackTrace();
- // FIXME Should show exception in gui - was reportException(e);
- }
-
- setPage(savedCurrentPage);
- }
- }
-
- /**
- * Scales page image
- * @param scale [0;1]
- */
- public void setScaleFactor(double scale) {
- renderer.setScaleFactor(scale);
- reload();
- }
-
- /**
- * Returns the scale factor required in order to fit either the current
- * page within the current window or to fit two adjacent pages within
- * the display if the displaymode is continuous.
- * @return the requested scale factor
- * @throws FOPException in case of an error while fetching the PageViewport
- */
- public double getScaleToFitWindow() throws FOPException {
- Dimension extents = previewArea.getViewport().getExtentSize();
- return getScaleToFit(extents.getWidth() - 2 * BORDER_SPACING,
- extents.getHeight() - 2 * BORDER_SPACING);
- }
-
- /**
- * As getScaleToFitWindow, but ignoring the Y axis.
- * @return the requested scale factor
- * @throws FOPException in case of an error while fetching the PageViewport
- */
- public double getScaleToFitWidth() throws FOPException {
- Dimension extents = previewArea.getViewport().getExtentSize();
- return getScaleToFit(extents.getWidth() - 2 * BORDER_SPACING, Double.MAX_VALUE);
- }
-
- /**
- * Returns the scale factor required in order to fit either the current page or
- * two adjacent pages within a window of the given height and width, depending
- * on the display mode. In order to ignore either dimension,
- * just specify it as Double.MAX_VALUE.
- * @param viewWidth width of the view
- * @param viewHeight height of the view
- * @return the requested scale factor
- * @throws FOPException in case of an error while fetching the PageViewport
- */
- public double getScaleToFit(double viewWidth, double viewHeight) throws FOPException {
- PageViewport pageViewport = renderer.getPageViewport(currentPage);
- Rectangle2D pageSize = pageViewport.getViewArea();
- double widthScale = viewWidth / (pageSize.getWidth() / 1000f);
- double heightScale = viewHeight / (pageSize.getHeight() / 1000f);
- return Math.min(displayMode == CONT_FACING ? widthScale / 2 : widthScale, heightScale);
- }
-
- /** Starts rendering process and shows the current page. */
- public synchronized void showPage() {
- ShowPageImage viewer = new ShowPageImage();
-
- if (SwingUtilities.isEventDispatchThread()) {
- viewer.run();
- } else {
- SwingUtilities.invokeLater(viewer);
- }
- }
-
- /** This class is used to render the page image in a thread safe way. */
- private class ShowPageImage implements Runnable {
-
- /**
- * The run method that does the actual rendering of the viewed page
- */
- public void run() {
- for (int pg = firstPage; pg < firstPage + pageRange; pg++) {
- pagePanels[pg - firstPage].setPage(pg);
- }
- revalidate();
- }
- }
- }
|