/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org>, Patick J. McSweeney <pjmcswee@syr.edu> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.ui.components; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.WindowConstants; import javax.swing.text.View; import org.apache.commons.codec.binary.Base64; import org.openide.awt.StatusDisplayer; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; import org.openide.windows.WindowManager; /** * * @author Mathieu Bastian * @author Patick J. McSweeney */ class ReportSelection implements Transferable { private static ArrayList flavors = new ArrayList(); static { try { flavors.add(new DataFlavor("text/html;class=java.lang.String")); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } } private String html; /** * * @param html */ public ReportSelection(String html) { this.html = html; String newHTML = new String(); String[] result = html.split("file:"); boolean first = true; for (int i = 0; i < result.length; i++) { if (result[i].contains("</IMG>")) { String next = result[i]; //System.out.println("> " + next); String[] elements = next.split("\""); String filename = elements[0]; ByteArrayOutputStream out = new ByteArrayOutputStream(); File file = new File(filename); try { BufferedImage image = ImageIO.read(file); ImageIO.write((RenderedImage) image, "PNG", out); } catch (Exception e) { e.printStackTrace(); } byte[] imageBytes = out.toByteArray(); String base64String = Base64.encodeBase64String(imageBytes); if (!first) { newHTML += "\""; } first = false; newHTML += "data:image/png;base64," + base64String; for (int j = 1; j < elements.length; j++) { newHTML += "\"" + elements[j]; } } else { newHTML += result[i]; } } this.html = newHTML; } /** * * @return */ public DataFlavor[] getTransferDataFlavors() { return (DataFlavor[]) flavors.toArray(new DataFlavor[flavors.size()]); } /** * * @param flavor * @return */ public boolean isDataFlavorSupported(DataFlavor flavor) { return flavors.contains(flavor); } /** * * @param flavor * @return * @throws java.awt.datatransfer.UnsupportedFlavorException */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (String.class.equals(flavor.getRepresentationClass())) { return html; } throw new UnsupportedFlavorException(flavor); } } /** * * @author pjmcswee */ public class SimpleHTMLReport extends javax.swing.JDialog implements Printable { private String mHTMLReport; public SimpleHTMLReport(java.awt.Frame parent, String html) { super(parent, false); mHTMLReport = html; initComponents(); displayPane.setContentType("text/html;"); displayPane.setText(this.mHTMLReport); Dimension dimension = new Dimension(700, 600); setPreferredSize(dimension); displayPane.setCaretPosition(0); setTitle("HTML Report"); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); pack(); setLocationRelativeTo(parent); setVisible(true); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); displayPane = (javax.swing.JEditorPane)(new JHTMLEditorPane()); closeButton = new javax.swing.JButton(); jToolBar1 = new javax.swing.JToolBar(); printButton = new javax.swing.JButton(); copyButton = new javax.swing.JButton(); saveButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle(org.openide.util.NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.title")); // NOI18N jScrollPane1.setViewportView(displayPane); closeButton.setText(org.openide.util.NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.closeButton.text")); // NOI18N closeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { closeButtonActionPerformed(evt); } }); jToolBar1.setFloatable(false); jToolBar1.setRollover(true); printButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/ui/components/resources/print.png"))); // NOI18N printButton.setText(org.openide.util.NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.printButton.text")); // NOI18N printButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { printButtonActionPerformed(evt); } }); jToolBar1.add(printButton); copyButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/ui/components/resources/copy.gif"))); // NOI18N copyButton.setText(org.openide.util.NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.copyButton.text")); // NOI18N copyButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { copyButtonActionPerformed(evt); } }); jToolBar1.add(copyButton); saveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/ui/components/resources/save.png"))); // NOI18N saveButton.setText(org.openide.util.NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.saveButton.text")); // NOI18N saveButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveButtonActionPerformed(evt); } }); jToolBar1.add(saveButton); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(closeButton) .addContainerGap()) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 279, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(closeButton) .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents private void printButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_printButtonActionPerformed PrinterJob pjob = PrinterJob.getPrinterJob(); PageFormat pf = pjob.defaultPage(); pjob.setPrintable(this, pf); try { if (pjob.printDialog()) { pjob.print(); } } catch (PrinterException e) { e.printStackTrace(); } }//GEN-LAST:event_printButtonActionPerformed private final String LAST_PATH = "SimpleHTMLReport_Save_Last_Path"; private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed final String html = this.mHTMLReport; final String path = NbPreferences.forModule(SimpleHTMLReport.class).get(LAST_PATH, null); JFileChooser fileChooser = new JFileChooser(path); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int result = fileChooser.showOpenDialog(WindowManager.getDefault().getMainWindow()); if (result == JFileChooser.APPROVE_OPTION) { final File destinationFolder = fileChooser.getSelectedFile(); NbPreferences.forModule(SimpleHTMLReport.class).put(LAST_PATH, destinationFolder.getAbsolutePath()); Thread saveReportThread = new Thread(new Runnable() { public void run() { try { saveReport(html, destinationFolder); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(SimpleHTMLReport.class, "SimpleHTMLReport.status.saveSuccess", destinationFolder.getName())); } catch (IOException e) { e.printStackTrace(); } } }, "SaveReportTask"); saveReportThread.start(); } }//GEN-LAST:event_saveButtonActionPerformed private void saveReport(String html, File destinationFolder) throws IOException { if (!destinationFolder.exists()) { destinationFolder.mkdir(); } //Find images location String imgRegex = "<img[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>"; Pattern pattern = Pattern.compile(imgRegex, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(html); StringBuffer replaceBuffer = new StringBuffer(); while (matcher.find()) { String fileAbsolutePath = matcher.group(1); if (fileAbsolutePath.startsWith("file:")) { fileAbsolutePath = fileAbsolutePath.replaceFirst("file:", ""); } File file = new File(fileAbsolutePath); if (file.exists()) { copy(file, destinationFolder); } //Replace temp path matcher.appendReplacement(replaceBuffer, "<IMG SRC=\"" + file.getName() + "\">"); } matcher.appendTail(replaceBuffer); //Write HTML file File htmlFile = new File(destinationFolder, "report.html"); FileOutputStream outputStream = new FileOutputStream(htmlFile); OutputStreamWriter out = new OutputStreamWriter(outputStream, "UTF-8"); out.append(replaceBuffer.toString()); out.flush(); out.close(); outputStream.close(); } private void copyButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_copyButtonActionPerformed Toolkit toolkit = Toolkit.getDefaultToolkit(); try { toolkit.getSystemClipboard().setContents(new ReportSelection(this.mHTMLReport), null); } catch (Exception e) { e.printStackTrace(); } }//GEN-LAST:event_copyButtonActionPerformed /** * * @param evt */ private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed dispose(); // TODO add your handling code here: }//GEN-LAST:event_closeButtonActionPerformed /** * @param args the command line arguments public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { SimpleHTMLReport dialog = new SimpleHTMLReport(new javax.swing.JFrame(), true); dialog.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); dialog.setVisible(true); } }); } * */ // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; private javax.swing.JButton copyButton; private javax.swing.JEditorPane displayPane; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JToolBar jToolBar1; private javax.swing.JButton printButton; private javax.swing.JButton saveButton; // End of variables declaration//GEN-END:variables /** * * @param graphics * @param pageFormat * @param pageIndex * @return */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { boolean last = false; try { View rootView = displayPane.getUI().getRootView(displayPane); double scaleX = pageFormat.getImageableWidth() / displayPane.getMinimumSize().getWidth(); scaleX = Math.min(scaleX, 1.0); double scaleY = scaleX; int end = (int) (pageIndex * ((1.0f / scaleY) * (double) pageFormat.getImageableHeight())); Rectangle allocation = new Rectangle(0, -end, (int) pageFormat.getImageableWidth(), (int) pageFormat.getImageableHeight()); ((Graphics2D) graphics).scale(scaleX, scaleY); graphics.setClip((int) (pageFormat.getImageableX() / scaleX), (int) (pageFormat.getImageableY() / scaleY), (int) (pageFormat.getImageableWidth() / scaleX), (int) (pageFormat.getImageableHeight() / scaleY)); ((Graphics2D) graphics).translate(((Graphics2D) graphics).getClipBounds().getX(), ((Graphics2D) graphics).getClipBounds().getY()); rootView.paint(graphics, allocation); last = end > displayPane.getUI().getPreferredSize(displayPane).getHeight(); if ((last)) { return Printable.NO_SUCH_PAGE; } } catch (Exception e) { e.printStackTrace(); } return Printable.PAGE_EXISTS; } public void copy(File source, File dest) throws IOException { FileChannel in = null, out = null; try { if (dest.isDirectory()) { dest = new File(dest, source.getName()); } in = new FileInputStream(source).getChannel(); out = new FileOutputStream(dest).getChannel(); long size = in.size(); MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size); out.write(buf); } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } }