]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graphviz/src/org/simantics/graphviz/drawable/JViewer.java
(refs #7272) Support updating named Graphviz windows
[simantics/platform.git] / bundles / org.simantics.graphviz / src / org / simantics / graphviz / drawable / JViewer.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.graphviz.drawable;
13
14 import java.awt.Canvas;
15 import java.awt.Color;
16 import java.awt.Graphics;
17 import java.awt.Graphics2D;
18 import java.awt.Image;
19 import java.awt.Point;
20 import java.awt.RenderingHints;
21 import java.awt.event.ActionEvent;
22 import java.awt.event.ComponentAdapter;
23 import java.awt.event.ComponentEvent;
24 import java.awt.event.KeyAdapter;
25 import java.awt.event.KeyEvent;
26 import java.awt.event.MouseAdapter;
27 import java.awt.event.MouseEvent;
28 import java.awt.event.MouseWheelEvent;
29 import java.awt.event.MouseWheelListener;
30 import java.awt.event.WindowAdapter;
31 import java.awt.event.WindowEvent;
32 import java.awt.geom.AffineTransform;
33 import java.awt.geom.Rectangle2D;
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.HashMap;
37
38 import javax.swing.AbstractAction;
39 import javax.swing.JFileChooser;
40 import javax.swing.JFrame;
41 import javax.swing.JMenu;
42 import javax.swing.JMenuBar;
43 import javax.swing.JMenuItem;
44 import javax.swing.JOptionPane;
45 import javax.swing.SwingUtilities;
46 import javax.swing.filechooser.FileFilter;
47 import javax.swing.filechooser.FileView;
48
49 import org.simantics.graphviz.Graph;
50 import org.simantics.graphviz.Graphs;
51
52 /**
53  * A stand alone frame that shows and makes it
54  * possible to navigate a given Drawable.
55  * 
56  * @author Hannu Niemist�
57  */
58 public class JViewer extends JFrame {
59     private static final HashMap<String, JViewer> VIEWER_MAP = new HashMap<String, JViewer>(); 
60     
61         private static final long serialVersionUID = 3022682167091092801L;
62         Drawable drawable;
63         ViewerCanvas canvas = new ViewerCanvas();
64
65     private String windowName;
66         
67         class ViewerCanvas extends Canvas {
68                 private static final long serialVersionUID = -5330090168115281754L;
69                 AffineTransform transform;
70         Point prev;
71         Image im;
72                 
73         ViewerCanvas() {                
74                 setBackground(Color.WHITE);    
75                 addKeyListener(new KeyAdapter() {
76                         
77                         @Override
78                         public void keyPressed(KeyEvent e) {
79                                 if(e.getKeyChar()=='1') {
80                                         //System.out.println("a");
81                                         canvas.fit();
82                                         canvas.repaint();
83                                 }
84                                 else if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
85                                         JViewer.this.dispose();
86                                 }
87                         }
88                         
89                 });
90                 addMouseListener(new MouseAdapter() {
91                         
92                         @Override
93                         public void mousePressed(MouseEvent e) {
94                                 prev = e.getPoint();
95                         }                       
96                 });
97                 addMouseMotionListener(new MouseAdapter() {
98                         @Override
99                         public void mouseDragged(MouseEvent e) {
100                                 Point cur = e.getPoint();
101                                 if (prev == null)
102                                     prev = cur;
103                                 double deltaX = cur.getX()-prev.getX();
104                                 double deltaY = cur.getY()-prev.getY();
105                                 transform.preConcatenate(AffineTransform.getTranslateInstance(deltaX, deltaY));                                         
106                                 repaint();
107                                 prev = cur;
108                         }
109                 });
110                 addMouseWheelListener(new MouseWheelListener() {
111
112                                 @Override
113                                 public void mouseWheelMoved(MouseWheelEvent e) {
114                                         if(transform != null) {
115                                                 double scale = Math.exp(-0.1*e.getUnitsToScroll());
116                                                 Point p = e.getPoint();
117                                                 AffineTransform mod = new AffineTransform();
118                                                 mod.translate(p.getX(), p.getY());
119                                                 mod.scale(scale, scale);
120                                                 mod.translate(-p.getX(), -p.getY());
121                                                 transform.preConcatenate(mod);                                          
122                                                 repaint();
123                                         }
124                                 }
125                         
126                 });
127                 addComponentListener(new ComponentAdapter() {
128                         @Override
129                         public void componentResized(ComponentEvent e) {
130                                 im = createImage(getWidth(), getHeight());
131                                 repaint();
132                         }
133                 });
134         }
135                 
136         private void fit() {
137                 Rectangle2D bounds = drawable.getBounds();
138                 
139                 Rectangle2D container = getBounds();
140                 double scale = container == null ? 1 : Math.min(
141                                 container.getWidth() / bounds.getWidth(), 
142                                 container.getHeight() / bounds.getHeight());
143                 
144                 transform = new AffineTransform(
145                                 scale, 0.0,
146                                 0.0, scale,
147                                 container.getX() + container.getWidth() * 0.5 - bounds.getCenterX() * scale,
148                                 container.getY() + container.getHeight() * 0.5 - bounds.getCenterY() * scale
149                                 );
150         }
151         
152         @Override
153         public void paint(Graphics _g) {
154                 if(im == null)
155                         im = createImage(getWidth(), getHeight());
156                 Graphics2D g = (Graphics2D)im.getGraphics();
157                 
158                 g.clearRect(0, 0, im.getWidth(null), im.getHeight(null));
159                 
160                 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
161                 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
162                 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
163                                 
164                 if(transform == null)
165                         fit();
166                 g.setTransform(transform);
167                 
168                 drawable.draw(g, null);
169                 
170                 _g.drawImage(im, 0, 0, this);
171         }
172         
173         @Override
174         public void update(Graphics g) {
175                 paint(g);
176         }
177         
178     }
179         
180         public JViewer(Drawable _drawable) {
181                 this.drawable = _drawable;
182                 setTitle("Image viewer");
183                 setSize(1024, 768);
184             addWindowListener(new WindowAdapter(){
185                 public void windowClosing(WindowEvent we){
186                         dispose();
187                 }               
188                 @Override
189                 public void windowActivated(WindowEvent e) {
190                         repaint(0, 0, getWidth(), getHeight());             
191                 }
192                 @Override
193                 public void windowGainedFocus(WindowEvent e) {
194                     requestFocus();
195                 }
196             });
197             getContentPane().add(canvas);
198             
199             JMenuBar menuBar = new JMenuBar();
200             
201             JMenu menu = new JMenu("File");
202             menuBar.add(menu);
203             
204             JMenuItem saveItem = new JMenuItem(new SaveAsAction());
205             JMenuItem exitItem = new JMenuItem(new ExitAction());
206             menu.add(saveItem);
207             menu.addSeparator();
208             menu.add(exitItem);
209             setJMenuBar(menuBar);
210             
211             setVisible(true);
212         }
213         
214         public void updateDrawable(Drawable drawable) {
215             this.drawable = drawable;
216             canvas.fit();
217             canvas.repaint();
218         }
219         
220         public class ExitAction extends AbstractAction {
221
222                 private static final long serialVersionUID = 5680421985865931443L;
223
224                 public ExitAction() {
225                         super("Exit");
226                 }
227                 
228                 @Override
229                 public void actionPerformed(ActionEvent e) {
230                         JViewer.this.setVisible(false);
231                         JViewer.this.dispose();
232                 }
233         }
234         
235         public class SaveAsAction extends AbstractAction {
236                 
237                 private static final long serialVersionUID = 4627419396805081199L;
238
239                 public SaveAsAction() {
240                         super("Save as");
241                 }
242                 
243                 @Override
244                 public void actionPerformed(ActionEvent e) {
245                         if (!(drawable instanceof GraphDrawable)) {
246                                 JOptionPane.showMessageDialog(JViewer.this, "File saving not supported", "Error",JOptionPane.ERROR_MESSAGE);
247                                 return;
248                         }
249                         GraphDrawable gdraw = (GraphDrawable)drawable;
250                         Graph graph = gdraw.getGraph();
251                         String algo = gdraw.getAlgorithm();
252                         JFileChooser chooser = new JFileChooser();
253                         chooser.addChoosableFileFilter(new DotImageFilter());
254                         chooser.setAcceptAllFileFilterUsed(false);
255                         chooser.setFileView(new DotImageFileView());
256                         int returnval = chooser.showSaveDialog(JViewer.this);
257                         if (returnval == JFileChooser.APPROVE_OPTION) {
258                                 try {
259                                         File file = chooser.getSelectedFile();
260                                 
261                                         String type = getExtension(file);
262                                         if (type == null)
263                                                 return;
264                                         Graphs.createImage(graph, algo, type, file);
265                                 } catch (IOException err) {
266                                         err.printStackTrace();
267                                         JOptionPane.showMessageDialog(JViewer.this, "File saving failed: " + err.getMessage(), "Error",JOptionPane.ERROR_MESSAGE);
268                                 }
269                         }
270                 }
271         }
272         
273         public static String getExtension(File file) {
274                 String filename = file.getName();
275                 int index = filename.lastIndexOf(".");
276                 if (index < 0)
277                         return null;
278                 return filename.substring(index+1).toLowerCase();
279         }
280         
281         public class DotImageFilter extends FileFilter {
282                 @Override
283                 public boolean accept(File f) {
284                         if (f.isDirectory())
285                                 return true;
286                         String ext = getExtension(f);
287                         if (ext == null)
288                                 return false;
289                         if (ext.equals("svg"))
290                                 return true;
291                         if (ext.equals("dot"))
292                                 return true;
293                         if (ext.equals("eps"))
294                                 return true;
295                         if (ext.equals("jpg"))
296                                 return true;
297                         if (ext.equals("jpeg"))
298                                 return true;
299                         if (ext.equals("pdf"))
300                                 return true;
301                         if (ext.equals("png"))
302                                 return true;
303                         if (ext.equals("ps"))
304                                 return true;
305                         return false;
306                 }
307                 
308                 @Override
309                 public String getDescription() {
310                         return "Image files";
311                 }
312         }
313         
314         public class DotImageFileView extends FileView {
315                 @Override
316                 public String getTypeDescription(File f) {
317                         String ext = getExtension(f);
318                         if (ext == null)
319                                 return null;
320                         if (ext.equals("svg"))
321                                 return "Scalable Vector Graphics Image";
322                         if (ext.equals("dot"))
323                                 return "DOT Image";
324                         if (ext.equals("eps"))
325                                 return "Encapsulated PostScript Image";
326                         if (ext.equals("jpg"))
327                                 return "JPG Image";
328                         if (ext.equals("jpeg"))
329                                 return "JPG Image";
330                         if (ext.equals("pdf"))
331                                 return "Portable Document Format Image";
332                         if (ext.equals("png"))
333                                 return "Portable Network Graphics Image";
334                         if (ext.equals("ps"))
335                                 return "PostScript Image";
336                         return null;
337                 }
338         }
339
340     public static void getOrCreateViewer(String windowName, GraphDrawable graphDrawable) {
341         JViewer viewer = VIEWER_MAP.get(windowName);
342         if(viewer == null) {
343             viewer = new JViewer(graphDrawable);
344             viewer.setTitle(windowName);
345             viewer.windowName = windowName;
346             VIEWER_MAP.put(windowName, viewer);
347             viewer.toFront();
348         }
349         else {
350             viewer.updateDrawable(graphDrawable);
351             viewer.toFront();
352         }
353     }
354     
355     @Override
356     public void dispose() {
357         if(windowName != null)
358             VIEWER_MAP.remove(windowName);
359         super.dispose();
360     }
361 }