]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graphviz/src/org/simantics/graphviz/drawable/JViewer.java
Prevent some NPEs in Graphviz plugin
[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                             if(transform == null)
101                                 return;
102                                 Point cur = e.getPoint();
103                                 if (prev == null)
104                                     prev = cur;
105                                 double deltaX = cur.getX()-prev.getX();
106                                 double deltaY = cur.getY()-prev.getY();
107                                 transform.preConcatenate(AffineTransform.getTranslateInstance(deltaX, deltaY));                                         
108                                 repaint();
109                                 prev = cur;
110                         }
111                 });
112                 addMouseWheelListener(new MouseWheelListener() {
113
114                                 @Override
115                                 public void mouseWheelMoved(MouseWheelEvent e) {
116                                         if(transform == null)
117                                             return;
118                                         double scale = Math.exp(-0.1*e.getUnitsToScroll());
119                                         Point p = e.getPoint();
120                                         AffineTransform mod = new AffineTransform();
121                                         mod.translate(p.getX(), p.getY());
122                                         mod.scale(scale, scale);
123                                         mod.translate(-p.getX(), -p.getY());
124                                         transform.preConcatenate(mod);
125                                         repaint();
126                                 }
127                         
128                 });
129                 addComponentListener(new ComponentAdapter() {
130                         @Override
131                         public void componentResized(ComponentEvent e) {
132                                 im = createImage(getWidth(), getHeight());
133                                 repaint();
134                         }
135                 });
136         }
137                 
138         private void fit() {
139                 Rectangle2D bounds = drawable.getBounds();
140                 Rectangle2D container = getBounds();
141                 
142                 if(bounds == null || container == null)
143                     return;
144                 
145                 double scale = container == null ? 1 : Math.min(
146                                 container.getWidth() / bounds.getWidth(), 
147                                 container.getHeight() / bounds.getHeight());
148                 
149                 transform = new AffineTransform(
150                                 scale, 0.0,
151                                 0.0, scale,
152                                 container.getX() + container.getWidth() * 0.5 - bounds.getCenterX() * scale,
153                                 container.getY() + container.getHeight() * 0.5 - bounds.getCenterY() * scale
154                                 );
155         }
156         
157         @Override
158         public void paint(Graphics _g) {
159                 if(im == null)
160                         im = createImage(getWidth(), getHeight());
161                 Graphics2D g = (Graphics2D)im.getGraphics();
162                 
163                 g.clearRect(0, 0, im.getWidth(null), im.getHeight(null));
164                 
165                 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
166                 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
167                 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
168                                 
169                 if(transform == null) {
170                         fit();
171                         if(transform == null) {
172                             g.setTransform(new AffineTransform());
173                             g.setColor(Color.BLACK);
174                             g.drawString("No data available yet", 20f, 20f);
175                             return;
176                         }
177                 }
178                 g.setTransform(transform);
179                 
180                 drawable.draw(g, null);
181                 
182                 _g.drawImage(im, 0, 0, this);
183         }
184         
185         @Override
186         public void update(Graphics g) {
187                 paint(g);
188         }
189         
190     }
191         
192         public JViewer(Drawable _drawable) {
193                 this.drawable = _drawable;
194                 setTitle("Image viewer");
195                 setSize(1024, 768);
196             addWindowListener(new WindowAdapter(){
197                 public void windowClosing(WindowEvent we){
198                         dispose();
199                 }               
200                 @Override
201                 public void windowActivated(WindowEvent e) {
202                         repaint(0, 0, getWidth(), getHeight());             
203                 }
204                 @Override
205                 public void windowGainedFocus(WindowEvent e) {
206                     requestFocus();
207                 }
208             });
209             getContentPane().add(canvas);
210             
211             JMenuBar menuBar = new JMenuBar();
212             
213             JMenu menu = new JMenu("File");
214             menuBar.add(menu);
215             
216             JMenuItem saveItem = new JMenuItem(new SaveAsAction());
217             JMenuItem exitItem = new JMenuItem(new ExitAction());
218             menu.add(saveItem);
219             menu.addSeparator();
220             menu.add(exitItem);
221             setJMenuBar(menuBar);
222             
223             setVisible(true);
224         }
225         
226         public void updateDrawable(Drawable drawable) {
227             this.drawable = drawable;
228             canvas.fit();
229             canvas.repaint();
230         }
231         
232         public class ExitAction extends AbstractAction {
233
234                 private static final long serialVersionUID = 5680421985865931443L;
235
236                 public ExitAction() {
237                         super("Exit");
238                 }
239                 
240                 @Override
241                 public void actionPerformed(ActionEvent e) {
242                         JViewer.this.setVisible(false);
243                         JViewer.this.dispose();
244                 }
245         }
246         
247         public class SaveAsAction extends AbstractAction {
248                 
249                 private static final long serialVersionUID = 4627419396805081199L;
250
251                 public SaveAsAction() {
252                         super("Save as");
253                 }
254                 
255                 @Override
256                 public void actionPerformed(ActionEvent e) {
257                         if (!(drawable instanceof GraphDrawable)) {
258                                 JOptionPane.showMessageDialog(JViewer.this, "File saving not supported", "Error",JOptionPane.ERROR_MESSAGE);
259                                 return;
260                         }
261                         GraphDrawable gdraw = (GraphDrawable)drawable;
262                         Graph graph = gdraw.getGraph();
263                         String algo = gdraw.getAlgorithm();
264                         JFileChooser chooser = new JFileChooser();
265                         chooser.addChoosableFileFilter(new DotImageFilter());
266                         chooser.setAcceptAllFileFilterUsed(false);
267                         chooser.setFileView(new DotImageFileView());
268                         int returnval = chooser.showSaveDialog(JViewer.this);
269                         if (returnval == JFileChooser.APPROVE_OPTION) {
270                                 try {
271                                         File file = chooser.getSelectedFile();
272                                 
273                                         String type = getExtension(file);
274                                         if (type == null)
275                                                 return;
276                                         Graphs.createImage(graph, algo, type, file);
277                                 } catch (IOException err) {
278                                         err.printStackTrace();
279                                         JOptionPane.showMessageDialog(JViewer.this, "File saving failed: " + err.getMessage(), "Error",JOptionPane.ERROR_MESSAGE);
280                                 }
281                         }
282                 }
283         }
284         
285         public static String getExtension(File file) {
286                 String filename = file.getName();
287                 int index = filename.lastIndexOf(".");
288                 if (index < 0)
289                         return null;
290                 return filename.substring(index+1).toLowerCase();
291         }
292         
293         public class DotImageFilter extends FileFilter {
294                 @Override
295                 public boolean accept(File f) {
296                         if (f.isDirectory())
297                                 return true;
298                         String ext = getExtension(f);
299                         if (ext == null)
300                                 return false;
301                         if (ext.equals("svg"))
302                                 return true;
303                         if (ext.equals("dot"))
304                                 return true;
305                         if (ext.equals("eps"))
306                                 return true;
307                         if (ext.equals("jpg"))
308                                 return true;
309                         if (ext.equals("jpeg"))
310                                 return true;
311                         if (ext.equals("pdf"))
312                                 return true;
313                         if (ext.equals("png"))
314                                 return true;
315                         if (ext.equals("ps"))
316                                 return true;
317                         return false;
318                 }
319                 
320                 @Override
321                 public String getDescription() {
322                         return "Image files";
323                 }
324         }
325         
326         public class DotImageFileView extends FileView {
327                 @Override
328                 public String getTypeDescription(File f) {
329                         String ext = getExtension(f);
330                         if (ext == null)
331                                 return null;
332                         if (ext.equals("svg"))
333                                 return "Scalable Vector Graphics Image";
334                         if (ext.equals("dot"))
335                                 return "DOT Image";
336                         if (ext.equals("eps"))
337                                 return "Encapsulated PostScript Image";
338                         if (ext.equals("jpg"))
339                                 return "JPG Image";
340                         if (ext.equals("jpeg"))
341                                 return "JPG Image";
342                         if (ext.equals("pdf"))
343                                 return "Portable Document Format Image";
344                         if (ext.equals("png"))
345                                 return "Portable Network Graphics Image";
346                         if (ext.equals("ps"))
347                                 return "PostScript Image";
348                         return null;
349                 }
350         }
351
352     public static void getOrCreateViewer(String windowName, GraphDrawable graphDrawable) {
353         JViewer viewer = VIEWER_MAP.get(windowName);
354         if(viewer == null) {
355             viewer = new JViewer(graphDrawable);
356             viewer.setTitle(windowName);
357             viewer.windowName = windowName;
358             VIEWER_MAP.put(windowName, viewer);
359             viewer.toFront();
360         }
361         else {
362             viewer.updateDrawable(graphDrawable);
363             viewer.toFront();
364         }
365     }
366     
367     @Override
368     public void dispose() {
369         if(windowName != null)
370             VIEWER_MAP.remove(windowName);
371         super.dispose();
372     }
373 }