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