/* * PrintPreviewDialog.java * Copyright 2011 Connor Petty <cpmeister@users.sourceforge.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created on Nov 7, 2011, 9:17:28 PM */ package pcgen.gui2.dialog; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.print.Pageable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FilenameFilter; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.net.URI; import java.text.NumberFormat; import java.util.Collection; import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.SwingWorker; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.render.awt.AWTRenderer; import org.apache.fop.render.awt.viewer.PreviewPanel; import pcgen.cdom.base.Constants; import pcgen.facade.core.CharacterFacade; import pcgen.gui2.PCGenFrame; import pcgen.gui2.tools.Icons; import pcgen.gui2.tools.Utility; import pcgen.system.BatchExporter; import pcgen.system.ConfigurationSettings; import pcgen.util.Logging; import pcgen.util.fop.FopTask; /** * Dialog to allow the preview of character export. * * @author Connor Petty <cpmeister@users.sourceforge.net> */ @SuppressWarnings("serial") public final class PrintPreviewDialog extends JDialog implements ActionListener { public static void showPrintPreviewDialog(PCGenFrame frame) { JDialog dialog = new PrintPreviewDialog(frame); Utility.setComponentRelativeLocation(frame, dialog); dialog.setVisible(true); } private static final String SHEET_COMMAND = "sheet"; private static final String PAGE_COMMAND = "page"; private static final String ZOOM_COMMAND = "zoom"; private static final String ZOOM_IN_COMMAND = "zoomin"; private static final String ZOOM_OUT_COMMAND = "zoomout"; private static final String PRINT_COMMAND = "print"; private static final String CANCEL_COMMAND = "cancel"; private static final double ZOOM_MULTIPLIER = Math.pow(2, 0.125); private final CharacterFacade character; private final JComboBox sheetBox; private final JComboBox pageBox; private final JComboBox zoomBox; private final JButton zoomInButton; private final JButton zoomOutButton; private final JButton printButton; private final JButton cancelButton; private final JPanel previewPanelParent; private PreviewPanel previewPanel; private final JProgressBar progressBar; private final PCGenFrame frame; private Pageable pageable; private PrintPreviewDialog(PCGenFrame frame) { super(frame, true); this.frame = frame; this.character = frame.getSelectedCharacterRef().get(); this.previewPanelParent = new JPanel(new GridLayout(1, 1)); this.sheetBox = new JComboBox(); this.progressBar = new JProgressBar(); this.pageBox = new JComboBox(); this.zoomBox = new JComboBox(); this.zoomInButton = new JButton(); this.zoomOutButton = new JButton(); this.printButton = new JButton(); this.cancelButton = new JButton(); initComponents(); initLayout(); pack(); new SheetLoader().execute(); } private void initComponents() { setTitle("Print Preview"); sheetBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value != null) { setToolTipText(value.toString()); } return this; } }); sheetBox.setActionCommand(SHEET_COMMAND); sheetBox.addActionListener(this); pageBox.addItem("0 of 0"); pageBox.setActionCommand(PAGE_COMMAND); pageBox.addActionListener(this); zoomBox.addItem(0.25); zoomBox.addItem(0.50); zoomBox.addItem(0.75); zoomBox.addItem(1.00); zoomBox.setSelectedItem(0.75); zoomBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { NumberFormat format = NumberFormat.getPercentInstance(); value = format.format(value); return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } }); zoomBox.setEditable(true); zoomBox.setEditor(new PercentEditor(zoomBox)); zoomBox.setActionCommand(ZOOM_COMMAND); zoomBox.addActionListener(this); zoomInButton.setIcon(Icons.ZoomIn16.getImageIcon()); zoomInButton.setActionCommand(ZOOM_IN_COMMAND); zoomInButton.addActionListener(this); zoomOutButton.setIcon(Icons.ZoomOut16.getImageIcon()); zoomOutButton.setActionCommand(ZOOM_OUT_COMMAND); zoomOutButton.addActionListener(this); printButton.setText("Print"); printButton.setActionCommand(PRINT_COMMAND); printButton.addActionListener(this); cancelButton.setText("Cancel"); cancelButton.setActionCommand(CANCEL_COMMAND); cancelButton.addActionListener(this); enableEditGroup(false); Utility.installEscapeCloseOperation(this); } private void enableEditGroup(boolean enable) { pageBox.setEnabled(enable); zoomBox.setEnabled(enable); zoomInButton.setEnabled(enable); zoomOutButton.setEnabled(enable); printButton.setEnabled(enable); } private void setPreviewPanel(PreviewPanel previewPanel) { previewPanelParent.removeAll(); this.previewPanel = previewPanel; previewPanelParent.add(previewPanel); previewPanel.reload(); } @Override public void actionPerformed(ActionEvent e) { if (SHEET_COMMAND.equals(e.getActionCommand())) { new PreviewLoader((URI) sheetBox.getSelectedItem()).execute(); } else if (PAGE_COMMAND.equals(e.getActionCommand())) { previewPanel.setPage(pageBox.getSelectedIndex()); } else if (ZOOM_COMMAND.equals(e.getActionCommand())) { Double zoom = (Double) zoomBox.getSelectedItem(); previewPanel.setScaleFactor(zoom); } else if (ZOOM_IN_COMMAND.equals(e.getActionCommand())) { Double zoom = (Double) zoomBox.getSelectedItem(); zoomBox.setSelectedItem(zoom * ZOOM_MULTIPLIER); } else if (ZOOM_OUT_COMMAND.equals(e.getActionCommand())) { Double zoom = (Double) zoomBox.getSelectedItem(); zoomBox.setSelectedItem(zoom / ZOOM_MULTIPLIER); } else if (PRINT_COMMAND.equals(e.getActionCommand())) { PrinterJob printerJob = PrinterJob.getPrinterJob(); printerJob.setPageable(pageable); if (printerJob.printDialog()) { try { printerJob.print(); dispose(); } catch (PrinterException ex) { String message = "Could not print " + character.getNameRef().get(); Logging.errorPrint(message, ex); frame.showErrorMessage(Constants.APPLICATION_NAME, message); } } } else if (CANCEL_COMMAND.equals(e.getActionCommand())) { dispose(); } } private void initLayout() { Container pane = getContentPane(); pane.setLayout(new BorderLayout()); {//layout top bar JPanel bar = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.BASELINE; gbc.insets = new Insets(8, 6, 8, 2); bar.add(new JLabel("Select Template:"), gbc); gbc.insets = new Insets(8, 2, 8, 6); gbc.weightx = 1; bar.add(sheetBox, gbc); pane.add(bar, BorderLayout.NORTH); } { Box vbox = Box.createVerticalBox(); previewPanelParent.setPreferredSize(new Dimension(600, 800)); vbox.add(previewPanelParent); vbox.add(progressBar); pane.add(vbox, BorderLayout.CENTER); } { Box hbox = Box.createHorizontalBox(); hbox.add(new JLabel("Page:")); hbox.add(Box.createHorizontalStrut(4)); hbox.add(pageBox); hbox.add(Box.createHorizontalStrut(10)); hbox.add(new JLabel("Zoom:")); hbox.add(Box.createHorizontalStrut(4)); hbox.add(zoomBox); hbox.add(Box.createHorizontalStrut(5)); hbox.add(zoomInButton); hbox.add(Box.createHorizontalStrut(5)); hbox.add(zoomOutButton); hbox.add(Box.createHorizontalGlue()); hbox.add(printButton); hbox.add(Box.createHorizontalStrut(5)); hbox.add(cancelButton); hbox.setBorder(BorderFactory.createEmptyBorder(8, 5, 8, 5)); pane.add(hbox, BorderLayout.SOUTH); } } private static class PercentEditor extends JFormattedTextField implements ComboBoxEditor, PropertyChangeListener { public PercentEditor(JComboBox comboBox) { super(NumberFormat.getPercentInstance()); addPropertyChangeListener("value", this); //We steal the border from the LAF's editor //Note: this doesn't work for Nimbus JComponent oldEditor = (JComponent) comboBox.getEditor().getEditorComponent(); setBorder(oldEditor.getBorder()); } @Override public Component getEditorComponent() { return this; } @Override public void setItem(Object anObject) { setValue(anObject); } @Override public Object getItem() { return getValue(); } @Override public void propertyChange(PropertyChangeEvent evt) { fireActionPerformed(); } } private class PreviewLoader extends SwingWorker<AWTRenderer, Object> { private URI uri; public PreviewLoader(URI uri) { this.uri = uri; progressBar.setIndeterminate(true); sheetBox.setEnabled(false); enableEditGroup(false); } @Override protected AWTRenderer doInBackground() throws Exception { URI osPath = new File(ConfigurationSettings.getOutputSheetsDir()).toURI(); File xsltFile = new File(osPath.resolve(uri)); FOUserAgent userAgent = FopTask.getFactory().newFOUserAgent(); AWTRenderer renderer = new AWTRenderer(userAgent, null, false, false); PipedOutputStream out = new PipedOutputStream(); FopTask task = FopTask.newFopTask(new PipedInputStream(out), xsltFile, renderer); Thread thread = new Thread(task, "fop-preview"); thread.setDaemon(true); thread.start(); BatchExporter.exportCharacter(character, out); try{ thread.join(); }catch(InterruptedException ex){ //pass on the interrupt and hope it stops thread.interrupt(); } return renderer; } @Override protected void done() { progressBar.setIndeterminate(false); sheetBox.setEnabled(true); enableEditGroup(true); try { AWTRenderer renderer = get(); pageable = renderer; setPreviewPanel(new PreviewPanel(renderer.getUserAgent(), null, renderer)); pageBox.setModel(createPagesModel(renderer.getNumberOfPages())); } catch (InterruptedException ex) { Logging.errorPrint("Could not load sheet", ex); } catch (ExecutionException ex) { Logging.errorPrint("Could not load sheet", ex.getCause()); } } } private static ComboBoxModel createPagesModel(int pages) { String[] pageNumbers = new String[pages]; for (int i = 0; i < pages; i++) { pageNumbers[i] = (i + 1) + " of " + pages; } return new DefaultComboBoxModel(pageNumbers); } private class SheetLoader extends SwingWorker<Object[], Object> implements FilenameFilter { @Override public boolean accept(File dir, String name) { return dir.getName().equalsIgnoreCase("pdf"); } @Override protected Object[] doInBackground() throws Exception { IOFileFilter pdfFilter = FileFilterUtils.asFileFilter(this); IOFileFilter suffixFilter = FileFilterUtils.notFileFilter(new SuffixFileFilter(".fo")); IOFileFilter sheetFilter = FileFilterUtils.prefixFileFilter(Constants.CHARACTER_TEMPLATE_PREFIX); IOFileFilter fileFilter = FileFilterUtils.and(pdfFilter, suffixFilter, sheetFilter); IOFileFilter dirFilter = FileFilterUtils.makeSVNAware(TrueFileFilter.INSTANCE); File dir = new File(ConfigurationSettings.getOutputSheetsDir()); Collection<File> files = FileUtils.listFiles(dir, fileFilter, dirFilter); URI osPath = new File(ConfigurationSettings.getOutputSheetsDir()).toURI(); Object[] uriList = new Object[files.size()]; int i = 0; for (File file : files) { uriList[i] = osPath.relativize(file.toURI()); i++; } return uriList; } @Override protected void done() { try { DefaultComboBoxModel model = new DefaultComboBoxModel(get()); model.setSelectedItem(null); sheetBox.setModel(model); } catch (InterruptedException ex) { Logging.errorPrint("could not load sheets", ex); } catch (ExecutionException ex) { Logging.errorPrint("could not load sheets", ex.getCause()); } } } }