/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.graphviz.drawable; import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.IOException; import java.util.HashMap; import javax.swing.AbstractAction; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileView; import org.simantics.graphviz.Graph; import org.simantics.graphviz.Graphs; /** * A stand alone frame that shows and makes it * possible to navigate a given Drawable. * * @author Hannu Niemist� */ public class JViewer extends JFrame { private static final HashMap VIEWER_MAP = new HashMap(); private static final long serialVersionUID = 3022682167091092801L; Drawable drawable; ViewerCanvas canvas = new ViewerCanvas(); private String windowName; class ViewerCanvas extends Canvas { private static final long serialVersionUID = -5330090168115281754L; AffineTransform transform; Point prev; Image im; ViewerCanvas() { setBackground(Color.WHITE); addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(e.getKeyChar()=='1') { //System.out.println("a"); canvas.fit(); canvas.repaint(); } else if(e.getKeyCode() == KeyEvent.VK_ESCAPE) { JViewer.this.dispose(); } } }); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { prev = e.getPoint(); } }); addMouseMotionListener(new MouseAdapter() { @Override public void mouseDragged(MouseEvent e) { if(transform == null) return; Point cur = e.getPoint(); if (prev == null) prev = cur; double deltaX = cur.getX()-prev.getX(); double deltaY = cur.getY()-prev.getY(); transform.preConcatenate(AffineTransform.getTranslateInstance(deltaX, deltaY)); repaint(); prev = cur; } }); addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { if(transform == null) return; double scale = Math.exp(-0.1*e.getUnitsToScroll()); Point p = e.getPoint(); AffineTransform mod = new AffineTransform(); mod.translate(p.getX(), p.getY()); mod.scale(scale, scale); mod.translate(-p.getX(), -p.getY()); transform.preConcatenate(mod); repaint(); } }); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { im = createImage(getWidth(), getHeight()); repaint(); } }); } private void fit() { Rectangle2D bounds = drawable.getBounds(); Rectangle2D container = getBounds(); if(bounds == null || container == null) return; double scale = container == null ? 1 : Math.min( container.getWidth() / bounds.getWidth(), container.getHeight() / bounds.getHeight()); transform = new AffineTransform( scale, 0.0, 0.0, scale, container.getX() + container.getWidth() * 0.5 - bounds.getCenterX() * scale, container.getY() + container.getHeight() * 0.5 - bounds.getCenterY() * scale ); } @Override public void paint(Graphics _g) { if(im == null) im = createImage(getWidth(), getHeight()); Graphics2D g = (Graphics2D)im.getGraphics(); g.clearRect(0, 0, im.getWidth(null), im.getHeight(null)); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); if(transform == null) { fit(); if(transform == null) { g.setTransform(new AffineTransform()); g.setColor(Color.BLACK); g.drawString("No data available yet", 20f, 20f); return; } } g.setTransform(transform); drawable.draw(g, null); _g.drawImage(im, 0, 0, this); } @Override public void update(Graphics g) { paint(g); } } public JViewer(Drawable _drawable) { this.drawable = _drawable; setTitle("Image viewer"); setSize(1024, 768); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent we){ dispose(); } @Override public void windowActivated(WindowEvent e) { repaint(0, 0, getWidth(), getHeight()); } @Override public void windowGainedFocus(WindowEvent e) { requestFocus(); } }); getContentPane().add(canvas); JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("File"); menuBar.add(menu); JMenuItem saveItem = new JMenuItem(new SaveAsAction()); JMenuItem exitItem = new JMenuItem(new ExitAction()); menu.add(saveItem); menu.addSeparator(); menu.add(exitItem); setJMenuBar(menuBar); setVisible(true); } public void updateDrawable(Drawable drawable) { this.drawable = drawable; canvas.fit(); canvas.repaint(); } public class ExitAction extends AbstractAction { private static final long serialVersionUID = 5680421985865931443L; public ExitAction() { super("Exit"); } @Override public void actionPerformed(ActionEvent e) { JViewer.this.setVisible(false); JViewer.this.dispose(); } } public class SaveAsAction extends AbstractAction { private static final long serialVersionUID = 4627419396805081199L; public SaveAsAction() { super("Save as"); } @Override public void actionPerformed(ActionEvent e) { if (!(drawable instanceof GraphDrawable)) { JOptionPane.showMessageDialog(JViewer.this, "File saving not supported", "Error",JOptionPane.ERROR_MESSAGE); return; } GraphDrawable gdraw = (GraphDrawable)drawable; Graph graph = gdraw.getGraph(); String algo = gdraw.getAlgorithm(); JFileChooser chooser = new JFileChooser(); chooser.addChoosableFileFilter(new DotImageFilter()); chooser.setAcceptAllFileFilterUsed(false); chooser.setFileView(new DotImageFileView()); int returnval = chooser.showSaveDialog(JViewer.this); if (returnval == JFileChooser.APPROVE_OPTION) { try { File file = chooser.getSelectedFile(); String type = getExtension(file); if (type == null) return; Graphs.createImage(graph, algo, type, file); } catch (IOException err) { err.printStackTrace(); JOptionPane.showMessageDialog(JViewer.this, "File saving failed: " + err.getMessage(), "Error",JOptionPane.ERROR_MESSAGE); } } } } public static String getExtension(File file) { String filename = file.getName(); int index = filename.lastIndexOf("."); if (index < 0) return null; return filename.substring(index+1).toLowerCase(); } public class DotImageFilter extends FileFilter { @Override public boolean accept(File f) { if (f.isDirectory()) return true; String ext = getExtension(f); if (ext == null) return false; if (ext.equals("svg")) return true; if (ext.equals("dot")) return true; if (ext.equals("eps")) return true; if (ext.equals("jpg")) return true; if (ext.equals("jpeg")) return true; if (ext.equals("pdf")) return true; if (ext.equals("png")) return true; if (ext.equals("ps")) return true; return false; } @Override public String getDescription() { return "Image files"; } } public class DotImageFileView extends FileView { @Override public String getTypeDescription(File f) { String ext = getExtension(f); if (ext == null) return null; if (ext.equals("svg")) return "Scalable Vector Graphics Image"; if (ext.equals("dot")) return "DOT Image"; if (ext.equals("eps")) return "Encapsulated PostScript Image"; if (ext.equals("jpg")) return "JPG Image"; if (ext.equals("jpeg")) return "JPG Image"; if (ext.equals("pdf")) return "Portable Document Format Image"; if (ext.equals("png")) return "Portable Network Graphics Image"; if (ext.equals("ps")) return "PostScript Image"; return null; } } public static void getOrCreateViewer(String windowName, GraphDrawable graphDrawable) { JViewer viewer = VIEWER_MAP.get(windowName); if(viewer == null) { viewer = new JViewer(graphDrawable); viewer.setTitle(windowName); viewer.windowName = windowName; VIEWER_MAP.put(windowName, viewer); viewer.toFront(); } else { viewer.updateDrawable(graphDrawable); viewer.toFront(); } } @Override public void dispose() { if(windowName != null) VIEWER_MAP.remove(windowName); super.dispose(); } }