Java tutorial
/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of DQguru * * DQguru is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * DQguru 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.matchmaker.swingui.action; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import org.apache.log4j.Logger; import ca.sqlpower.matchmaker.MatchMakerVersion; import ca.sqlpower.matchmaker.swingui.MatchMakerSwingSession; import ca.sqlpower.matchmaker.swingui.MungeProcessEditor; import ca.sqlpower.matchmaker.swingui.munge.MungePen; import ca.sqlpower.swingui.SPSUtils; import ca.sqlpower.util.MonitorableImpl; import com.lowagie.text.Document; import com.lowagie.text.Rectangle; import com.lowagie.text.pdf.PdfContentByte; import com.lowagie.text.pdf.PdfWriter; /** * This action will export the currently selected munge pen to a * user defined PDF file. Before the export starts the user will be * prompted to specify a file to export to. * * Note: A munge pen must be selected before running this action * otherwise the munge pen will not exist. */ public class ExportMungePenToPDFAction extends ProgressAction { private static final Logger logger = Logger.getLogger(ExportMungePenToPDFAction.class); /** * A key to denote which file we are exporting to. */ private static final String FILE_KEY = "FILE_KEY"; /** * The padding around the PDF export. */ private static int OUTSIDE_PADDING = 10; /** * This is the paintComponent method on the JComponent * class retrieved through reflection. If this parameter * is null then the {@link #paintComponent(JComponent, Graphics)} * method has not been called yet to initialize this variable. */ private static Method paintComponent; /** * This is the paintBorder method on the JComponent * class retrieved through reflection. If this parameter * is null then the {@link #paintBorder(JComponent, Graphics)} * method has not been called yet to initialize this variable. */ private static Method paintBorder; public ExportMungePenToPDFAction(MatchMakerSwingSession session) { super(session, "Export Playpen to PDF", "Export Playpen to PDF"); } /** * When an action is performed on this it pops up the save dialog * and requests a file to save to. When it gets that it draws the * munge pen to a PDF file on a seperate thread. */ public boolean setup(MonitorableImpl monitor, Map<String, Object> properties) { monitor.setStarted(true); JFileChooser chooser = new JFileChooser(); chooser.addChoosableFileFilter(SPSUtils.PDF_FILE_FILTER); if (!(session.getOldPane() instanceof MungeProcessEditor)) { JOptionPane.showMessageDialog(session.getFrame(), "We only allow PDF exports of the playpen at current.", "Cannot Export Playpen", JOptionPane.WARNING_MESSAGE); return false; } monitor.setJobSize(((MungeProcessEditor) session.getOldPane()).getMungePen().getComponentCount()); File file = null; while (true) { int response = chooser.showSaveDialog(session.getFrame()); if (response != JFileChooser.APPROVE_OPTION) { return false; } file = chooser.getSelectedFile(); String fileName = file.getName(); if (!fileName.endsWith(".pdf")) { file = new File(file.getPath() + ".pdf"); } if (file.exists()) { response = JOptionPane.showConfirmDialog(null, "The file\n" + file.getPath() + "\nalready exists. Do you want to overwrite it?", "File Exists", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.YES_OPTION) { break; } } else { break; } } logger.debug("Saving to file: " + file.getName() + " (" + file.getPath() + ")"); properties.put(FILE_KEY, file); return true; } @Override public void cleanUp(MonitorableImpl monitor) { // TODO might have to cleanup here } @Override public void doStuff(MonitorableImpl monitor, Map<String, Object> properties) { if (!(session.getOldPane() instanceof MungeProcessEditor)) { JOptionPane.showMessageDialog(session.getFrame(), "We only allow PDF exports of the playpen at current.", "Cannot Export Playpen", JOptionPane.WARNING_MESSAGE); return; } MungePen mungePen = ((MungeProcessEditor) session.getOldPane()).getMungePen(); /* We translate the graphics to (OUTSIDE_PADDING, OUTSIDE_PADDING) * so nothing is drawn right on the edge of the document. So * we multiply by 2 so we can accomodate the translate and ensure * nothing gets drawn outside of the document size. */ final int width = mungePen.getBounds().width + 2 * OUTSIDE_PADDING; final int height = mungePen.getBounds().height + 2 * OUTSIDE_PADDING; final Rectangle ppSize = new Rectangle(width, height); OutputStream out = null; Document d = null; try { out = new BufferedOutputStream(new FileOutputStream((File) properties.get(FILE_KEY))); d = new Document(ppSize); d.addTitle("DQguru Transform PDF Export"); d.addAuthor(System.getProperty("user.name")); d.addCreator("DQguru version " + MatchMakerVersion.APP_VERSION); PdfWriter writer = PdfWriter.getInstance(d, out); d.open(); PdfContentByte cb = writer.getDirectContent(); Graphics2D g = cb.createGraphicsShapes(width, height); // ensure a margin g.translate(OUTSIDE_PADDING, OUTSIDE_PADDING); mungePen.paintComponent(g); int j = 0; //paint each component individually to show progress for (int i = mungePen.getComponentCount() - 1; i >= 0; i--) { JComponent mpc = (JComponent) mungePen.getComponent(i); //set text and foreground as paintComponent //does not normally do this g.setColor(mpc.getForeground()); g.setFont(mpc.getFont()); logger.debug("Printing " + mpc.getName() + " to PDF"); paintComponentAndChildren(mpc, g); monitor.setProgress(j); j++; } g.dispose(); } catch (Exception ex) { SPSUtils.showExceptionDialogNoReport(session.getFrame(), "Could not export the playpen", ex); } finally { if (d != null) { try { d.close(); } catch (Exception ex) { SPSUtils.showExceptionDialogNoReport(session.getFrame(), "Could not close document for exporting playpen", ex); } } if (out != null) { try { out.flush(); out.close(); } catch (IOException ex) { SPSUtils.showExceptionDialogNoReport(session.getFrame(), "Could not close pdf file for exporting playpen", ex); } } } } /** * This will paint the given component and all of its children. Painting of * the child components will be done with a recursive call to this method * and painting will be done using reflection to call paintComponent. * <p> * NOTE: This method will not paint any children that are not subclasses * of JComponent. */ private void paintComponentAndChildren(JComponent jc, Graphics g) { g.translate(jc.getLocation().x, jc.getLocation().y); if (logger.isDebugEnabled()) { g.drawRect(0, 0, jc.getWidth(), jc.getHeight()); } paintComponent(jc, g); paintBorder(jc, g); logger.debug("Painting " + jc.getName() + " at location " + jc.getLocation() + " with dimensions " + jc.getWidth() + ", " + jc.getHeight()); for (Component child : jc.getComponents()) { if (child instanceof JComponent) { paintComponentAndChildren((JComponent) child, g.create()); } } logger.debug("Finished Painting " + jc.getName() + " at location " + jc.getLocation() + " with dimensions " + jc.getWidth() + ", " + jc.getHeight()); g.translate(-jc.getLocation().x, -jc.getLocation().y); } @Override public String getDialogMessage() { return "Creating PDF"; } @Override public String getButtonText() { return "Run in Background"; } /** * This method calls the JComponent's paintComponent method * through reflection. This way we can paint any specific * component we need to a graphics object. To increase performance * the paintComponent method is only retrieved once and stored * locally. */ public static void paintComponent(JComponent jc, Graphics g) { try { paintComponent = JComponent.class.getDeclaredMethod("paintComponent", Graphics.class); paintComponent.setAccessible(true); paintComponent.invoke(jc, g); } catch (IllegalArgumentException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (InvocationTargetException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (SecurityException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (NoSuchMethodException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * This method calls the JComponent's paintBorder method * through reflection. This way we can paint any specific * component we need to a graphics object. To increase performance * the paintComponent method is only retrieved once and stored * locally. */ public static void paintBorder(JComponent jc, Graphics g) { try { paintBorder = JComponent.class.getDeclaredMethod("paintBorder", Graphics.class); paintBorder.setAccessible(true); paintBorder.invoke(jc, g); } catch (IllegalArgumentException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (IllegalAccessException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (InvocationTargetException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (SecurityException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (NoSuchMethodException e) { e.printStackTrace(); throw new RuntimeException(e); } } }