KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > render > awt > viewer > PreviewPanel


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: PreviewPanel.java 473976 2006-11-12 15:38:45Z jeremias $ */
19
20 package org.apache.fop.render.awt.viewer;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.Dimension JavaDoc;
24 import java.awt.GridLayout JavaDoc;
25 import java.awt.Point JavaDoc;
26 import java.awt.event.MouseEvent JavaDoc;
27 import java.awt.event.MouseListener JavaDoc;
28 import java.awt.event.MouseMotionListener JavaDoc;
29 import java.awt.geom.Rectangle2D JavaDoc;
30
31 import javax.swing.JLabel JavaDoc;
32 import javax.swing.JOptionPane JavaDoc;
33 import javax.swing.JPanel JavaDoc;
34 import javax.swing.JScrollPane JavaDoc;
35 import javax.swing.JViewport JavaDoc;
36 import javax.swing.SwingUtilities JavaDoc;
37 import javax.swing.border.EmptyBorder JavaDoc;
38
39 import org.apache.fop.apps.FOPException;
40 import org.apache.fop.apps.FOUserAgent;
41 import org.apache.fop.apps.MimeConstants;
42 import org.apache.fop.area.PageViewport;
43
44 import org.apache.fop.render.awt.AWTRenderer;
45
46
47 /**
48  * <p>Holds a scrollpane with the rendered page(s) and handles actions performed
49  * to alter the display of the page.
50  * </p>
51  * <p>Use PreviewPanel when you want to embed a preview in your own application
52  * with your own controls. Use PreviewDialog when you want to use the standard
53  * Fop controls.
54  * </p>
55  * <p>In order to embed a PreviewPanel in your own app, create your own renderer,
56  * and your own agent. In order to support reloads, you may also implement your
57  * own Renderable extension or the default InputHandler. Setting the Renderable
58  * to null works fine though.
59  * Then call setPreviewDialogDisplayed(false) to hide the
60  * default dialog. Finally create a preview panel with the agent, renderable and
61  * renderer and add it to your gui:
62  * </p>
63  * <pre>
64  * FopFactory fopFactory = FopFactory.newInstance();
65  * AWTRenderer renderer = new AWTRenderer();
66  * FOUserAgent agent = fopFactory.newFOUserAgent();
67  * agent.setRendererOverride(renderer);
68  * renderer.setPreviewDialogDisplayed(false);
69  * renderer.setUserAgent(agent);
70  * renderer.setUserAgent(agent);
71  * previewPanel = new PreviewPanel(agent, null, renderer);
72  * previewPanel = new PreviewPanel(ua);
73  * myGui.add(previewPanel);
74  * </pre>
75  *
76  * In order to set options and display a page do:
77  * <pre>
78  * renderer.clearViewportList();
79  * // build report xml here
80  * reload(); // optional if setting changed
81  * </pre>
82  *
83  * If you wan't to change settings, don't call reload. A good example is
84  * to set the page to fill the screen and set the scrolling mode:
85  * <pre>
86  * double scale = previewPanel.getScaleToFitWindow();
87  * previewPanel.setScaleFactor(scale);
88  * previewPanel.setDisplayMode(PreviewPanel.CONTINUOUS);
89  * </pre>
90  */

91 public class PreviewPanel extends JPanel JavaDoc {
92
93     /** Constant for setting single page display. */
94     public static final int SINGLE = 1;
95     /** Constant for setting continuous page display. */
96     public static final int CONTINUOUS = 2;
97     /** Constant for displaying even/odd pages side by side in continuous form. */
98     public static final int CONT_FACING = 3;
99
100     /** The number of pixels left empty at the top bottom and sides of the page. */
101     private static final int BORDER_SPACING = 10;
102
103     /** The main display area */
104     private JScrollPane JavaDoc previewArea;
105
106     /** The AWT renderer - often shared with PreviewDialog */
107     private AWTRenderer renderer;
108
109     /** The FOUserAgent associated with this panel - often shared with PreviewDialog */
110     protected FOUserAgent foUserAgent;
111     /**
112      * Renderable instance that can be used to reload and re-render a document after
113      * modifications.
114      */

115     protected Renderable renderable;
116     /** The number of the page which is currently selected */
117     private int currentPage = 0;
118
119     /** The index of the first page displayed on screen. */
120     private int firstPage = 0;
121
122     /** The number of pages concurrently displayed on screen. */
123     private int pageRange = 1;
124
125     /** The display mode. One of SINGLE, CONTINUOUS or CONT_FACING. */
126     private int displayMode = SINGLE;
127
128     /** The component(s) that hold the rendered page(s) */
129     private ImageProxyPanel[] pagePanels = null;
130
131     /**
132      * Panel showing the page panels in a grid. Usually the dimensions
133      * of the grid are 1x1, nx1 or nx2.
134      */

135     private JPanel JavaDoc gridPanel = null;
136
137     /** Asynchronous reloader thread, used when reload() method is called. */
138     private Reloader reloader;
139
140     /**
141      * Allows any mouse drag on the page area to scroll the display window.
142      */

143     private ViewportScroller scroller;
144
145         
146     /**
147      * Creates a new PreviewPanel instance.
148      * @param foUserAgent the user agent
149      * @param renderable the Renderable instance that is used to reload/re-render a document
150      * after modifications.
151      * @param renderer the AWT Renderer instance to paint with
152      */

153     public PreviewPanel(FOUserAgent foUserAgent, Renderable renderable, AWTRenderer renderer) {
154         super(new GridLayout JavaDoc(1, 1));
155         this.renderable = renderable;
156         this.renderer = renderer;
157         this.foUserAgent = foUserAgent;
158
159         gridPanel = new JPanel JavaDoc();
160         gridPanel.setLayout(new GridLayout JavaDoc(0, 1)); // rows, cols
161

162         previewArea = new JScrollPane JavaDoc(gridPanel);
163         previewArea.getViewport().setBackground(Color.gray);
164
165         // FIXME should add scroll wheel support here at some point.
166
scroller = new ViewportScroller(previewArea.getViewport());
167         previewArea.addMouseListener(scroller);
168         previewArea.addMouseMotionListener(scroller);
169
170         previewArea.setMinimumSize(new Dimension JavaDoc(50, 50));
171         add(previewArea);
172     }
173         
174     /**
175      * @return the currently visible page
176      */

177     public int getPage() {
178         return currentPage;
179     }
180
181     /**
182      * Selects the given page, displays it on screen and notifies
183      * listeners about the change in selection.
184      * @param number the page number
185      */

186     public void setPage(int number) {
187         if (displayMode == CONTINUOUS || displayMode == CONT_FACING) {
188             currentPage = number;
189             gridPanel.scrollRectToVisible(pagePanels[currentPage].getBounds());
190         } else { // single page mode
191
currentPage = number;
192             firstPage = currentPage;
193         }
194         showPage();
195     }
196
197     /**
198      * Sets the display mode.
199      * @param mode One of SINGLE, CONTINUOUS or CONT_FACING.
200      */

201     public void setDisplayMode(int mode) {
202         if (mode != displayMode) {
203             displayMode = mode;
204             gridPanel.setLayout(new GridLayout JavaDoc(0, displayMode == CONT_FACING ? 2 : 1));
205             reload();
206         }
207     }
208
209     /**
210      * Returns the display mode.
211      * @return mode One of SINGLE, CONTINUOUS or CONT_FACING.
212      */

213     public int getDisplayMode() {
214         return displayMode;
215     }
216
217     /**
218      * Reloads and reformats document.
219      */

220     public synchronized void reload() {
221         if (reloader == null || !reloader.isAlive()) {
222             reloader = new Reloader();
223             reloader.start();
224         }
225     }
226
227     /**
228      * Allows a (yet) simple visual debug of the document.
229      */

230     void debug() {
231         renderer.debug = !renderer.debug;
232         reload();
233     }
234
235     /**
236      * Allows any mouse drag on the page area to scroll the display window.
237      */

238     private class ViewportScroller implements MouseListener JavaDoc, MouseMotionListener JavaDoc {
239         /** The viewport to be scrolled */
240         private final JViewport JavaDoc viewport;
241         /** Starting position of a mouse drag - X co-ordinate */
242         private int startPosX = 0;
243         /** Starting position of a mouse drag - Y co-ordinate */
244         private int startPosY = 0;
245         
246         ViewportScroller(JViewport JavaDoc vp) {
247             viewport = vp;
248         }
249
250         // ***** MouseMotionListener *****
251

252         public synchronized void mouseDragged(MouseEvent JavaDoc e) {
253             if (viewport == null) {
254                 return;
255             }
256             int x = e.getX();
257             int y = e.getY();
258             int xmove = x - startPosX;
259             int ymove = y - startPosY;
260             int viewWidth = viewport.getExtentSize().width;
261             int viewHeight = viewport.getExtentSize().height;
262             int imageWidth = viewport.getViewSize().width;
263             int imageHeight = viewport.getViewSize().height;
264             
265             Point JavaDoc viewPoint = viewport.getViewPosition();
266             int viewX = Math.max(0, Math.min(imageWidth - viewWidth, viewPoint.x - xmove));
267             int viewY = Math.max(0, Math.min(imageHeight - viewHeight, viewPoint.y - ymove));
268
269             viewport.setViewPosition(new Point JavaDoc(viewX, viewY));
270
271             startPosX = x;
272             startPosY = y;
273         }
274
275         public void mouseMoved(MouseEvent JavaDoc e) { }
276
277         // ***** MouseListener *****
278

279         public void mousePressed(MouseEvent JavaDoc e) {
280             startPosX = e.getX();
281             startPosY = e.getY();
282         }
283
284         public void mouseExited(MouseEvent JavaDoc e) { }
285         public void mouseEntered(MouseEvent JavaDoc e) { }
286         public void mouseClicked(MouseEvent JavaDoc e) { }
287         public void mouseReleased(MouseEvent JavaDoc e) { }
288     }
289
290     /**
291      * This class is used to reload document in a thread safe way.
292      */

293     private class Reloader extends Thread JavaDoc {
294
295         public void run() {
296             if (!renderer.isRenderingDone()) {
297                 // do not allow the reloading while FOP is still rendering
298
JOptionPane.showMessageDialog(previewArea,
299                         "Cannot perform the requested operation until "
300                                 + "all page are rendered. Please wait",
301                         "Please wait ", 1 /* INFORMATION_MESSAGE */);
302                 return;
303             }
304
305             pagePanels = null;
306
307             int savedCurrentPage = currentPage;
308             currentPage = 0;
309
310             gridPanel.removeAll();
311             switch(displayMode) {
312                 case CONT_FACING:
313                     // This page intentionally left blank
314
// Makes 0th/1st page on rhs
315
gridPanel.add(new JLabel JavaDoc(""));
316                 case CONTINUOUS:
317                     currentPage = 0;
318                     firstPage = 0;
319                     pageRange = renderer.getNumberOfPages();
320                     break;
321                 case SINGLE:
322                 default:
323                     currentPage = 0;
324                     firstPage = 0;
325                     pageRange = 1;
326                     break;
327             }
328
329             pagePanels = new ImageProxyPanel[pageRange];
330             for (int pg = 0; pg < pageRange; pg++) {
331                 pagePanels[pg] = new ImageProxyPanel(renderer, pg + firstPage);
332                 pagePanels[pg].setBorder(new EmptyBorder JavaDoc(
333                         BORDER_SPACING, BORDER_SPACING, BORDER_SPACING, BORDER_SPACING));
334                 gridPanel.add(pagePanels[pg]);
335             }
336
337             try {
338                 if (renderable != null) {
339                     renderer.clearViewportList();
340                     renderable.renderTo(foUserAgent, MimeConstants.MIME_FOP_AWT_PREVIEW);
341                 }
342             } catch (FOPException e) {
343                 e.printStackTrace();
344                 // FIXME Should show exception in gui - was reportException(e);
345
}
346
347             setPage(savedCurrentPage);
348         }
349     }
350
351     /**
352      * Scales page image
353      * @param scale [0;1]
354      */

355     public void setScaleFactor(double scale) {
356         renderer.setScaleFactor(scale);
357         reload();
358     }
359
360     /**
361      * Returns the scale factor required in order to fit either the current
362      * page within the current window or to fit two adjacent pages within
363      * the display if the displaymode is continuous.
364      * @return the requested scale factor
365      * @throws FOPException in case of an error while fetching the PageViewport
366      */

367     public double getScaleToFitWindow() throws FOPException {
368         Dimension JavaDoc extents = previewArea.getViewport().getExtentSize();
369         return getScaleToFit(extents.getWidth() - 2 * BORDER_SPACING,
370                     extents.getHeight() - 2 * BORDER_SPACING);
371     }
372
373     /**
374      * As getScaleToFitWindow, but ignoring the Y axis.
375      * @return the requested scale factor
376      * @throws FOPException in case of an error while fetching the PageViewport
377      */

378     public double getScaleToFitWidth() throws FOPException {
379         Dimension JavaDoc extents = previewArea.getViewport().getExtentSize();
380         return getScaleToFit(extents.getWidth() - 2 * BORDER_SPACING, Double.MAX_VALUE);
381     }
382
383     /**
384      * Returns the scale factor required in order to fit either the current page or
385      * two adjacent pages within a window of the given height and width, depending
386      * on the display mode. In order to ignore either dimension,
387      * just specify it as Double.MAX_VALUE.
388      * @param viewWidth width of the view
389      * @param viewHeight height of the view
390      * @return the requested scale factor
391      * @throws FOPException in case of an error while fetching the PageViewport
392      */

393     public double getScaleToFit(double viewWidth, double viewHeight) throws FOPException {
394         PageViewport pageViewport = renderer.getPageViewport(currentPage);
395         Rectangle2D JavaDoc pageSize = pageViewport.getViewArea();
396         double widthScale = viewWidth / (pageSize.getWidth() / 1000f);
397         double heightScale = viewHeight / (pageSize.getHeight() / 1000f);
398         return Math.min(displayMode == CONT_FACING ? widthScale / 2 : widthScale, heightScale);
399     }
400
401     /** Starts rendering process and shows the current page. */
402     public synchronized void showPage() {
403         ShowPageImage viewer = new ShowPageImage();
404
405         if (SwingUtilities.isEventDispatchThread()) {
406             viewer.run();
407         } else {
408             SwingUtilities.invokeLater(viewer);
409         }
410     }
411
412     /** This class is used to render the page image in a thread safe way. */
413     private class ShowPageImage implements Runnable JavaDoc {
414
415         /**
416          * The run method that does the actual rendering of the viewed page
417          */

418         public void run() {
419             for (int pg = firstPage; pg < firstPage + pageRange; pg++) {
420                 pagePanels[pg - firstPage].setPage(pg);
421             }
422             revalidate();
423         }
424     }
425 }
426
Popular Tags