| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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; |
| |
| // Originally contributed by: |
| // Juergen Verwohlt: Juergen.Verwohlt@jCatalog.com, |
| // Rainer Steinkuhle: Rainer.Steinkuhle@jCatalog.com, |
| // Stanislav Gorkhover: Stanislav.Gorkhover@jCatalog.com |
| |
| // Java |
| import java.awt.BorderLayout; |
| import java.awt.Dimension; |
| import java.awt.GridBagConstraints; |
| import java.awt.GridBagLayout; |
| import java.awt.Insets; |
| import java.awt.Point; |
| import java.awt.Toolkit; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.KeyEvent; |
| import java.awt.event.WindowAdapter; |
| import java.awt.event.WindowEvent; |
| import java.awt.print.PrinterException; |
| import java.awt.print.PrinterJob; |
| import java.text.DecimalFormat; |
| import java.text.DecimalFormatSymbols; |
| import java.util.Locale; |
| |
| import javax.swing.ActionMap; |
| import javax.swing.BorderFactory; |
| import javax.swing.ButtonGroup; |
| import javax.swing.InputMap; |
| import javax.swing.JComboBox; |
| import javax.swing.JComponent; |
| import javax.swing.JFrame; |
| import javax.swing.JLabel; |
| import javax.swing.JMenu; |
| import javax.swing.JMenuBar; |
| import javax.swing.JOptionPane; |
| import javax.swing.JPanel; |
| import javax.swing.JRadioButtonMenuItem; |
| import javax.swing.JToolBar; |
| import javax.swing.KeyStroke; |
| import javax.swing.SwingUtilities; |
| |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.render.awt.AWTRenderer; |
| |
| /** |
| * AWT Viewer main window. |
| * Surrounds a PreviewPanel with a bunch of pretty buttons and controls. |
| */ |
| public class PreviewDialog extends JFrame implements StatusListener { |
| |
| /** The Translator for localization */ |
| protected Translator translator; |
| /** The AWT renderer */ |
| protected AWTRenderer renderer; |
| /** The FOUserAgent associated with this window */ |
| protected FOUserAgent foUserAgent; |
| /** The originally configured target resolution */ |
| protected float configuredTargetResolution; |
| /** |
| * Renderable instance that can be used to reload and re-render a document after |
| * modifications. |
| */ |
| protected Renderable renderable; |
| |
| /** The JCombobox to rescale the rendered page view */ |
| private JComboBox scale; |
| |
| /** The JLabel for the process status bar */ |
| private JLabel processStatus; |
| |
| /** The JLabel information status bar */ |
| private JLabel infoStatus; |
| |
| /** The main display area */ |
| private PreviewPanel previewPanel; |
| |
| /** Formats the text in the scale combobox. */ |
| private DecimalFormat percentFormat = new DecimalFormat("###0.0#", |
| new DecimalFormatSymbols(Locale.ENGLISH)); |
| |
| /** |
| * Creates a new PreviewDialog that uses the given renderer. |
| * @param foUserAgent the user agent |
| * @param renderable the Renderable instance that is used to reload/re-render a document |
| * after modifications. |
| */ |
| public PreviewDialog( |
| FOUserAgent foUserAgent, Renderable renderable) { |
| renderer = (AWTRenderer) foUserAgent.getRendererOverride(); |
| this.foUserAgent = foUserAgent; |
| this.configuredTargetResolution = this.foUserAgent.getTargetResolution(); |
| this.renderable = renderable; |
| translator = new Translator(); |
| |
| //Commands aka Actions |
| Command printAction = new Command(translator.getString("Menu.Print"), "Print") { |
| public void doit() { |
| startPrinterJob(true); |
| } |
| }; |
| Command firstPageAction = new Command(translator.getString("Menu.First.page"), |
| "firstpg") { |
| public void doit() { |
| goToFirstPage(); |
| } |
| }; |
| Command previousPageAction = new Command(translator.getString("Menu.Prev.page"), |
| "prevpg") { |
| public void doit() { |
| goToPreviousPage(); |
| } |
| }; |
| Command nextPageAction = new Command(translator.getString("Menu.Next.page"), "nextpg") { |
| public void doit() { |
| goToNextPage(); |
| } |
| |
| }; |
| Command lastPageAction = new Command(translator.getString("Menu.Last.page"), "lastpg") { |
| public void doit() { |
| goToLastPage(); |
| } |
| }; |
| Command reloadAction = new Command(translator.getString("Menu.Reload"), "reload") { |
| public void doit() { |
| previewPanel.reload(); |
| } |
| }; |
| Command debugAction = new Command(translator.getString("Menu.Debug"), "debug") { |
| // TODO use Translator |
| public void doit() { |
| previewPanel.debug(); |
| } |
| }; |
| Command aboutAction = new Command(translator.getString("Menu.About"), "fopLogo") { |
| public void doit() { |
| startHelpAbout(); |
| } |
| }; |
| |
| setTitle("FOP: AWT-" + translator.getString("Title.Preview")); |
| setDefaultCloseOperation(DISPOSE_ON_CLOSE); |
| |
| //Sets size to be 61%x90% of the screen size |
| Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); |
| // Needed due to bug in Sun's JVM 1.5 (6429775) |
| pack(); |
| //Rather frivolous size - fits A4 page width in 1024x768 screen on my desktop |
| setSize(screen.width * 61 / 100, screen.height * 9 / 10); |
| |
| //Page view stuff |
| previewPanel = new PreviewPanel(foUserAgent, renderable, renderer); |
| getContentPane().add(previewPanel, BorderLayout.CENTER); |
| previewPanel.addPageChangeListener(new PageChangeListener() { |
| public void pageChanged(PageChangeEvent pce) { |
| new ShowInfo().run(); |
| } |
| }); |
| |
| // Keyboard shortcuts - pgup/pgdn |
| InputMap im = previewPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); |
| ActionMap am = previewPanel.getActionMap(); |
| im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "nextPage"); |
| im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "prevPage"); |
| im.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), "firstPage"); |
| im.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), "lastPage"); |
| previewPanel.getActionMap().put("nextPage", nextPageAction); |
| previewPanel.getActionMap().put("prevPage", previousPageAction); |
| previewPanel.getActionMap().put("firstPage", firstPageAction); |
| previewPanel.getActionMap().put("lastPage", lastPageAction); |
| |
| //Scaling combobox |
| scale = new JComboBox(); |
| scale.addItem(translator.getString("Menu.Fit.Window")); |
| scale.addItem(translator.getString("Menu.Fit.Width")); |
| scale.addItem("25%"); |
| scale.addItem("50%"); |
| scale.addItem("75%"); |
| scale.addItem("100%"); |
| scale.addItem("150%"); |
| scale.addItem("200%"); |
| scale.setMaximumSize(new Dimension(80, 24)); |
| scale.setPreferredSize(new Dimension(80, 24)); |
| scale.setSelectedItem("100%"); |
| scale.setEditable(true); |
| scale.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| scaleActionPerformed(e); |
| } |
| }); |
| |
| //Menu |
| setJMenuBar(setupMenu()); |
| |
| // Toolbar |
| JToolBar toolBar = new JToolBar(); |
| toolBar.add(printAction); |
| toolBar.add(reloadAction); |
| toolBar.addSeparator(); |
| toolBar.add(firstPageAction); |
| toolBar.add(previousPageAction); |
| toolBar.add(nextPageAction); |
| toolBar.add(lastPageAction); |
| toolBar.addSeparator(new Dimension(20, 0)); |
| toolBar.add(new JLabel(translator.getString("Menu.Zoom") + " ")); |
| toolBar.add(scale); |
| toolBar.addSeparator(); |
| toolBar.add(debugAction); |
| toolBar.addSeparator(); |
| toolBar.add(aboutAction); |
| getContentPane().add(toolBar, BorderLayout.NORTH); |
| |
| // Status bar |
| JPanel statusBar = new JPanel(); |
| processStatus = new JLabel(); |
| processStatus.setBorder(BorderFactory.createCompoundBorder( |
| BorderFactory.createEtchedBorder(), |
| BorderFactory.createEmptyBorder(0, 3, 0, 0))); |
| infoStatus = new JLabel(); |
| infoStatus.setBorder(BorderFactory.createCompoundBorder( |
| BorderFactory.createEtchedBorder(), |
| BorderFactory.createEmptyBorder(0, 3, 0, 0))); |
| |
| statusBar.setLayout(new GridBagLayout()); |
| |
| processStatus.setPreferredSize(new Dimension(200, 21)); |
| processStatus.setMinimumSize(new Dimension(200, 21)); |
| |
| infoStatus.setPreferredSize(new Dimension(100, 21)); |
| infoStatus.setMinimumSize(new Dimension(100, 21)); |
| statusBar.add(processStatus, |
| new GridBagConstraints(0, 0, 1, 0, 2.0, 0.0, |
| GridBagConstraints.CENTER, |
| GridBagConstraints.HORIZONTAL, |
| new Insets(0, 0, 0, 3), 0, 0)); |
| statusBar.add(infoStatus, |
| new GridBagConstraints(1, 0, 1, 0, 1.0, 0.0, |
| GridBagConstraints.CENTER, |
| GridBagConstraints.HORIZONTAL, |
| new Insets(0, 0, 0, 0), 0, 0)); |
| getContentPane().add(statusBar, BorderLayout.SOUTH); |
| } |
| |
| /** |
| * Creates and initialize the AWT Viewer main window. |
| * @param foUserAgent the FO user agent |
| * @param renderable the target for the rendering |
| * @param asMainWindow true if the window shall act as the main application window. |
| * @return the newly initialized preview dialog |
| */ |
| public static PreviewDialog createPreviewDialog(FOUserAgent foUserAgent, |
| Renderable renderable, boolean asMainWindow) { |
| PreviewDialog frame = new PreviewDialog(foUserAgent, renderable); |
| |
| if (asMainWindow) { |
| frame.addWindowListener(new WindowAdapter() { |
| public void windowClosed(WindowEvent we) { |
| System.exit(0); |
| } |
| }); |
| } |
| |
| // Centers the window |
| Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); |
| Dimension frameSize = frame.getSize(); |
| if (frameSize.height > screenSize.height) { |
| frameSize.height = screenSize.height; |
| } |
| if (frameSize.width > screenSize.width) { |
| frameSize.width = screenSize.width; |
| } |
| frame.setLocation((screenSize.width - frameSize.width) / 2, |
| (screenSize.height - frameSize.height) / 2); |
| frame.setStatus(frame.translator.getString("Status.Build.FO.tree")); |
| frame.setVisible(true); |
| return frame; |
| } |
| |
| /** |
| * Creates a new PreviewDialog that uses the given renderer. |
| * @param foUserAgent the user agent |
| */ |
| public PreviewDialog(FOUserAgent foUserAgent) { |
| this(foUserAgent, null); |
| } |
| |
| /** |
| * Creates a new menubar to be shown in this window. |
| * @return the newly created menubar |
| */ |
| private JMenuBar setupMenu() { |
| JMenuBar menuBar = new JMenuBar(); |
| JMenu menu = new JMenu(translator.getString("Menu.File")); |
| menu.setMnemonic(KeyEvent.VK_F); |
| //Adds mostly the same actions, but without icons |
| menu.add(new Command(translator.getString("Menu.Print"), KeyEvent.VK_P) { |
| public void doit() { |
| startPrinterJob(true); |
| } |
| }); |
| // inputHandler must be set to allow reloading |
| if (renderable != null) { |
| menu.add(new Command(translator.getString("Menu.Reload"), KeyEvent.VK_R) { |
| public void doit() { |
| reload(); |
| } |
| }); |
| } |
| menu.addSeparator(); |
| menu.add(new Command(translator.getString("Menu.Exit"), KeyEvent.VK_X) { |
| public void doit() { |
| dispose(); |
| } |
| }); |
| menuBar.add(menu); |
| |
| menu = new JMenu(translator.getString("Menu.View")); |
| menu.setMnemonic(KeyEvent.VK_V); |
| menu.add(new Command(translator.getString("Menu.First.page"), KeyEvent.VK_F) { |
| public void doit() { |
| goToFirstPage(); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Prev.page"), KeyEvent.VK_P) { |
| public void doit() { |
| goToPreviousPage(); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Next.page"), KeyEvent.VK_N) { |
| public void doit() { |
| goToNextPage(); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Last.page"), KeyEvent.VK_L) { |
| public void doit() { |
| goToLastPage(); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Go.to.Page"), KeyEvent.VK_G) { |
| public void doit() { |
| showGoToPageDialog(); |
| } |
| }); |
| menu.addSeparator(); |
| JMenu subMenu = new JMenu(translator.getString("Menu.Zoom")); |
| subMenu.setMnemonic(KeyEvent.VK_Z); |
| subMenu.add(new Command("25%", 0) { |
| public void doit() { |
| setScale(25.0); |
| } |
| }); |
| subMenu.add(new Command("50%", 0) { |
| public void doit() { |
| setScale(50.0); |
| } |
| }); |
| subMenu.add(new Command("75%", 0) { |
| public void doit() { |
| setScale(75.0); |
| } |
| }); |
| subMenu.add(new Command("100%", 0) { |
| public void doit() { |
| setScale(100.0); |
| } |
| }); |
| subMenu.add(new Command("150%", 0) { |
| public void doit() { |
| setScale(150.0); |
| } |
| }); |
| subMenu.add(new Command("200%", 0) { |
| public void doit() { |
| setScale(200.0); |
| } |
| }); |
| menu.add(subMenu); |
| menu.addSeparator(); |
| menu.add(new Command(translator.getString("Menu.Default.zoom"), KeyEvent.VK_D) { |
| public void doit() { |
| setScale(100.0); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Fit.Window"), KeyEvent.VK_F) { |
| public void doit() { |
| setScaleToFitWindow(); |
| } |
| }); |
| menu.add(new Command(translator.getString("Menu.Fit.Width"), KeyEvent.VK_W) { |
| public void doit() { |
| setScaleToFitWidth(); |
| } |
| }); |
| menu.addSeparator(); |
| |
| ButtonGroup group = new ButtonGroup(); |
| JRadioButtonMenuItem single = new JRadioButtonMenuItem( |
| new Command(translator.getString("Menu.Single"), KeyEvent.VK_S) { |
| public void doit() { |
| previewPanel.setDisplayMode(PreviewPanel.SINGLE); |
| } |
| }); |
| JRadioButtonMenuItem cont = new JRadioButtonMenuItem( |
| new Command(translator.getString("Menu.Continuous"), KeyEvent.VK_C) { |
| public void doit() { |
| previewPanel.setDisplayMode(PreviewPanel.CONTINUOUS); |
| } |
| }); |
| JRadioButtonMenuItem facing = new JRadioButtonMenuItem( |
| new Command(translator.getString("Menu.Facing"), 0) { |
| public void doit() { |
| previewPanel.setDisplayMode(PreviewPanel.CONT_FACING); |
| } |
| }); |
| single.setSelected(true); |
| group.add(single); |
| group.add(cont); |
| group.add(facing); |
| menu.add(single); |
| menu.add(cont); |
| menu.add(facing); |
| |
| menuBar.add(menu); |
| |
| menu = new JMenu(translator.getString("Menu.Help")); |
| menu.setMnemonic(KeyEvent.VK_H); |
| menu.add(new Command(translator.getString("Menu.About"), KeyEvent.VK_A) { |
| public void doit() { |
| startHelpAbout(); |
| } |
| }); |
| menuBar.add(menu); |
| return menuBar; |
| } |
| |
| /** {@inheritDoc} */ |
| public void notifyRendererStopped() { |
| reload(); |
| } |
| |
| private void reload() { |
| setStatus(translator.getString("Status.Show")); |
| previewPanel.reload(); |
| } |
| |
| /** |
| * Changes the current visible page |
| * @param number the page number to go to |
| */ |
| public void goToPage(int number) { |
| if (number != previewPanel.getPage()) { |
| previewPanel.setPage(number); |
| notifyPageRendered(); |
| } |
| } |
| |
| /** |
| * Shows the previous page. |
| */ |
| public void goToPreviousPage() { |
| int page = previewPanel.getPage(); |
| if (page > 0) { |
| goToPage(page - 1); |
| } |
| } |
| |
| /** |
| * Shows the next page. |
| */ |
| public void goToNextPage() { |
| int page = previewPanel.getPage(); |
| if (page < renderer.getNumberOfPages() - 1) { |
| goToPage(page + 1); |
| } |
| } |
| |
| /** Shows the first page. */ |
| public void goToFirstPage() { |
| goToPage(0); |
| } |
| |
| /** |
| * Shows the last page. |
| */ |
| public void goToLastPage() { |
| goToPage(renderer.getNumberOfPages() - 1); |
| } |
| |
| /** Shows the About box */ |
| private void startHelpAbout() { |
| PreviewDialogAboutBox dlg = new PreviewDialogAboutBox(this, translator); |
| //Centers the box |
| Dimension dlgSize = dlg.getPreferredSize(); |
| Dimension frmSize = getSize(); |
| Point loc = getLocation(); |
| dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, |
| (frmSize.height - dlgSize.height) / 2 + loc.y); |
| dlg.setVisible(true); |
| } |
| |
| /** |
| * Shows "go to page" dialog and then goes to the selected page |
| */ |
| private void showGoToPageDialog() { |
| int currentPage = previewPanel.getPage(); |
| GoToPageDialog d = new GoToPageDialog(this, |
| translator.getString("Menu.Go.to.Page"), translator); |
| d.setLocation((int)getLocation().getX() + 50, |
| (int)getLocation().getY() + 50); |
| d.setVisible(true); |
| currentPage = d.getPageNumber(); |
| if (currentPage < 1 || currentPage > renderer.getNumberOfPages()) { |
| return; |
| } |
| currentPage--; |
| goToPage(currentPage); |
| } |
| |
| /** |
| * Scales page image. |
| * @param scaleFactor the scale factor |
| */ |
| public void setScale(double scaleFactor) { |
| scale.setSelectedItem(percentFormat.format(scaleFactor) + "%"); |
| previewPanel.setScaleFactor(scaleFactor / 100d); |
| } |
| |
| /** |
| * Sets the scaling so the contents fit into the window. |
| */ |
| public void setScaleToFitWindow() { |
| try { |
| setScale(previewPanel.getScaleToFitWindow() * 100); |
| } catch (FOPException fopEx) { |
| fopEx.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Sets the scaling so the contents are spread over the whole width available. |
| */ |
| public void setScaleToFitWidth() { |
| try { |
| setScale(previewPanel.getScaleToFitWidth() * 100); |
| } catch (FOPException fopEx) { |
| fopEx.printStackTrace(); |
| } |
| } |
| |
| private void scaleActionPerformed(ActionEvent e) { |
| int index = scale.getSelectedIndex(); |
| if (index == 0) { |
| setScaleToFitWindow(); |
| } else if (index == 1) { |
| setScaleToFitWidth(); |
| } else { |
| String item = (String)scale.getSelectedItem(); |
| setScale(Double.parseDouble(item.substring(0, item.indexOf('%')))); |
| } |
| } |
| |
| /** |
| * Prints the document. |
| * @param showDialog true if show dialog |
| */ |
| public void startPrinterJob(boolean showDialog) { |
| //Restore originally configured target resolution |
| float saveResolution = foUserAgent.getTargetResolution(); |
| foUserAgent.setTargetResolution(this.configuredTargetResolution); |
| |
| PrinterJob pj = PrinterJob.getPrinterJob(); |
| pj.setPageable(renderer); |
| if (!showDialog || pj.printDialog()) { |
| try { |
| pj.print(); |
| } catch (PrinterException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| foUserAgent.setTargetResolution(saveResolution); |
| } |
| |
| /** |
| * Sets message to be shown in the status bar in a thread safe way. |
| * @param message the message |
| */ |
| public void setStatus(String message) { |
| SwingUtilities.invokeLater(new ShowStatus(message)); |
| } |
| |
| /** This class is used to show status in a thread safe way. */ |
| private class ShowStatus implements Runnable { |
| |
| /** The message to display */ |
| private String message; |
| |
| /** |
| * Constructs ShowStatus thread |
| * @param message message to display |
| */ |
| public ShowStatus(String message) { |
| this.message = message; |
| } |
| |
| public void run() { |
| processStatus.setText(message); |
| } |
| } |
| |
| /** |
| * Updates the message to be shown in the info bar in a thread safe way. |
| */ |
| public void notifyPageRendered() { |
| SwingUtilities.invokeLater(new ShowInfo()); |
| } |
| |
| /** This class is used to show info in a thread safe way. */ |
| private class ShowInfo implements Runnable { |
| |
| public void run() { |
| String message = translator.getString("Status.Page") + " " |
| + (previewPanel.getPage() + 1) + " " |
| + translator.getString("Status.of") + " " |
| + (renderer.getNumberOfPages()); |
| infoStatus.setText(message); |
| } |
| } |
| |
| /** |
| * Opens standard Swing error dialog box and reports given exception details. |
| * @param e the Exception |
| */ |
| public void reportException(Exception e) { |
| String msg = translator.getString("Exception.Occured"); |
| setStatus(msg); |
| JOptionPane.showMessageDialog( |
| getContentPane(), |
| "<html><b>" + msg + ":</b><br>" |
| + e.getClass().getName() + "<br>" |
| + e.getMessage() + "</html>", |
| translator.getString("Exception.Error"), |
| JOptionPane.ERROR_MESSAGE |
| ); |
| } |
| } |