]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graphviz.ui/src/org/simantics/graphviz/ui/GraphvizComponent.java
Sync git svn branch with SVN repository r33144.
[simantics/platform.git] / bundles / org.simantics.graphviz.ui / src / org / simantics / graphviz / ui / GraphvizComponent.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.graphviz.ui;\r
13 \r
14 import java.awt.Canvas;\r
15 import java.awt.Frame;\r
16 import java.awt.event.WindowAdapter;\r
17 import java.awt.event.WindowEvent;\r
18 import java.io.File;\r
19 import java.io.IOException;\r
20 import java.lang.reflect.InvocationTargetException;\r
21 import java.lang.reflect.Method;\r
22 import java.util.concurrent.atomic.AtomicBoolean;\r
23 \r
24 import javax.swing.SwingUtilities;\r
25 \r
26 import org.eclipse.swt.SWT;\r
27 import org.eclipse.swt.awt.SWT_AWT;\r
28 import org.eclipse.swt.widgets.Composite;\r
29 import org.eclipse.swt.widgets.Control;\r
30 import org.eclipse.swt.widgets.Shell;\r
31 import org.simantics.graphviz.Graph;\r
32 import org.simantics.graphviz.Graphs;\r
33 import org.simantics.graphviz.continuation.Computation;\r
34 import org.simantics.graphviz.continuation.Continuation;\r
35 import org.simantics.graphviz.drawable.GraphDrawable;\r
36 import org.simantics.graphviz.drawable.ViewerCanvas;\r
37 import org.simantics.utils.ui.SWTUtils;\r
38 \r
39 public class GraphvizComponent extends Composite {\r
40 \r
41     Canvas canvas;\r
42     GraphDrawable drawable;\r
43     Graph graph;\r
44     AtomicBoolean initialized = new AtomicBoolean(false);\r
45 \r
46     public GraphvizComponent(Composite parent, int style) {\r
47         super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);\r
48 \r
49         final Frame frame = SWT_AWT.new_Frame(this);\r
50         workaroundJava7FocusProblem(frame);\r
51         \r
52         SwingUtilities.invokeLater(new Runnable() {\r
53 \r
54             @Override\r
55             public void run() {\r
56                 try {\r
57                     drawable = new GraphDrawable();\r
58                     canvas = new ViewerCanvas(drawable);\r
59                     frame.add(canvas);\r
60                 } finally {\r
61                     synchronized (initialized) {\r
62                         initialized.set(true);\r
63                         initialized.notifyAll();\r
64                     }\r
65                 }\r
66             }\r
67 \r
68         });\r
69     }\r
70     \r
71     private void workaroundJava7FocusProblem(Frame frame) {\r
72         String ver = System.getProperty("java.version");\r
73         if (ver.startsWith("1.7") || ver.startsWith("1.8")) {\r
74             try {\r
75                 frame.addWindowListener(new Java7FocusFixListener(this, frame));\r
76             } catch (SecurityException e) {\r
77                 e.printStackTrace();\r
78                 //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
79             } catch (NoSuchMethodException e) {\r
80                 e.printStackTrace();\r
81                 //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
82             }\r
83         }\r
84     }\r
85 \r
86     static class Java7FocusFixListener extends WindowAdapter {\r
87 \r
88         Method shellSetActiveControl;\r
89         Control control;\r
90         Frame frame;\r
91 \r
92         public Java7FocusFixListener(Control control, Frame frame) throws NoSuchMethodException, SecurityException {\r
93             this.shellSetActiveControl = Shell.class.getDeclaredMethod("setActiveControl", Control.class);\r
94             this.frame = frame;\r
95             this.control = control;\r
96         }\r
97 \r
98         @Override\r
99         public void windowActivated(WindowEvent e) {\r
100             SWTUtils.asyncExec(control, new Runnable() {\r
101                 @Override\r
102                 public void run() {\r
103                     if (control.isDisposed())\r
104                         return;\r
105                     if (control.getDisplay().getFocusControl() == control) {\r
106                         try {\r
107                             boolean accessible = shellSetActiveControl.isAccessible();\r
108                             if (!accessible)\r
109                                 shellSetActiveControl.setAccessible(true);\r
110                             shellSetActiveControl.invoke(control.getShell(), control);\r
111                             if (!accessible)\r
112                                 shellSetActiveControl.setAccessible(false);\r
113                         } catch (SecurityException e) {\r
114                             e.printStackTrace();\r
115                             //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
116                         } catch (IllegalArgumentException e) {\r
117                             e.printStackTrace();\r
118                             //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
119                         } catch (IllegalAccessException e) {\r
120                             e.printStackTrace();\r
121                             //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
122                         } catch (InvocationTargetException e) {\r
123                             e.getCause().printStackTrace();\r
124                             //Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
125                         }\r
126                     }\r
127                 }\r
128             });\r
129         }\r
130 \r
131     }\r
132 \r
133     public void waitUntilInitialized() {\r
134         try {\r
135             synchronized (initialized) {\r
136                 while (!initialized.get())\r
137                     initialized.wait();\r
138             }\r
139         } catch (InterruptedException e) {\r
140             throw new Error("GraphvizComponent AWT population interrupted for class " + this, e);\r
141         }\r
142     }\r
143 \r
144     /**\r
145      * Sets a new graph to be drawn. This operation may take a while. It can\r
146      * be called from any thread. Automatically redraws the component.\r
147      * @param graph\r
148      */\r
149     public void setGraph(Graph graph) {\r
150         setGraph(graph, "dot");\r
151     }\r
152 \r
153     /**\r
154      * Sets a new graph to be drawn. This operation may take a while. It can\r
155      * be called from any thread. Automatically redraws the component.\r
156      * @param graph\r
157      */\r
158     public Computation<Graph> setGraph(Graph graph, String algorithm) {\r
159         waitUntilInitialized();\r
160         Computation<Graph> computation = drawable.setGraph(graph, algorithm);\r
161         computation.addContinuation(new Continuation<Graph>() {\r
162 \r
163             @Override\r
164             public void succeeded(Graph result) {\r
165                 if (isDisposed())\r
166                     return;\r
167                 \r
168                 fit();\r
169             }\r
170 \r
171             @Override\r
172             public void failed(Exception exception) {\r
173             }\r
174 \r
175         });\r
176         return computation;\r
177     }\r
178 \r
179     /**\r
180      * Fits the content of the canvas to the component.\r
181      * Can be called from any thread.\r
182      */\r
183     public void fit() {\r
184         ((ViewerCanvas)canvas).fit();\r
185         getDisplay().asyncExec(new Runnable() {\r
186 \r
187             @Override\r
188             public void run() {\r
189                 if (!isDisposed())\r
190                     redraw();\r
191             }\r
192 \r
193         });\r
194         SwingUtilities.invokeLater(new Runnable() {\r
195 \r
196             @Override\r
197             public void run() {\r
198                 canvas.repaint();\r
199             }\r
200 \r
201         });\r
202 \r
203 \r
204     }\r
205 \r
206     public void requestFocus() {\r
207         if(canvas != null)\r
208             canvas.requestFocus();\r
209     }\r
210     \r
211     public void save(File file) throws IOException {\r
212         if (drawable == null) {\r
213                         throw new IOException("Nothing to save");\r
214                 }\r
215                 Graph graph = drawable.getGraph();\r
216                 String algo = drawable.getAlgorithm();\r
217         \r
218                 String type = getExtension(file);\r
219                 if (type == null)\r
220                         return;\r
221                 Graphs.createImage(graph, algo, type, file);\r
222     }\r
223     \r
224     public String[] getFileExtensions() {\r
225         return new String[]{"*.svg","*.dot","*.eps", "*.jpg", "*.jpeg","*.pdf","*.png","*.ps"};\r
226     }\r
227     \r
228     public String[] getFileNames() {\r
229         return new String[]{"Scalable Vector Graphics Image",  "DOT Image", "Encapsulated PostScript Image","JPG Image","JPG Image","Portable Document Format Image","Portable Network Graphics Image","PostScript Image"};\r
230     }\r
231     \r
232     public static String getExtension(File file) {\r
233                 String filename = file.getName();\r
234                 int index = filename.lastIndexOf(".");\r
235                 if (index < 0)\r
236                         return null;\r
237                 return filename.substring(index+1).toLowerCase();\r
238         }\r
239 \r
240 }\r