]> gerrit.simantics Code Review - simantics/platform.git/blob
0312cc48f9c169198d02064d0bd970b2fe4e3bc3
[simantics/platform.git] /
1 package org.simantics.views.swt.client.base;\r
2 \r
3 import java.lang.reflect.Field;\r
4 import java.lang.reflect.InvocationTargetException;\r
5 import java.lang.reflect.Method;\r
6 import java.util.HashMap;\r
7 import java.util.Map;\r
8 \r
9 import org.eclipse.jface.resource.ColorDescriptor;\r
10 import org.eclipse.jface.resource.FontDescriptor;\r
11 import org.eclipse.jface.resource.ResourceManager;\r
12 import org.eclipse.swt.widgets.Control;\r
13 import org.simantics.databoard.Bindings;\r
14 import org.simantics.databoard.binding.ArrayBinding;\r
15 import org.simantics.databoard.binding.Binding;\r
16 import org.simantics.databoard.binding.error.BindingConstructionException;\r
17 import org.simantics.databoard.binding.error.BindingException;\r
18 import org.simantics.databoard.binding.reflection.BindingRequest;\r
19 import org.simantics.datatypes.literal.Font;\r
20 import org.simantics.datatypes.literal.RGB;\r
21 import org.simantics.scenegraph.LoaderNode;\r
22 import org.simantics.scenegraph.loader.ScenegraphLoaderUtils;\r
23 import org.simantics.scl.runtime.function.Function1;\r
24 import org.simantics.scl.runtime.function.Function2;\r
25 import org.simantics.scl.runtime.function.FunctionImpl1;\r
26 import org.simantics.ui.colors.Colors;\r
27 import org.simantics.ui.fonts.Fonts;\r
28 import org.simantics.utils.threads.IThreadWorkQueue;\r
29 import org.simantics.utils.threads.SWTThread;\r
30 import org.simantics.views.ViewUtils.GridDataBean;\r
31 \r
32 abstract public class SingleSWTViewNode<T extends Control> extends SWTParentNode implements LoaderNode {\r
33         \r
34         private static final long serialVersionUID = -5810308021930769003L;\r
35         \r
36         private Map<String, Object> genericProperties = new HashMap<String, Object>();\r
37         \r
38         public Function2<String, Object, Boolean> propertyCallback;\r
39         public GridDataBean layoutData;\r
40         public int style;\r
41         public String text;\r
42         public RGB.Integer background;\r
43         public RGB.Integer foreground;\r
44         public Font font;\r
45         protected transient ColorDescriptor backgroundDesc;\r
46         protected transient ColorDescriptor foregroundDesc;\r
47         protected transient FontDescriptor fontDesc;\r
48 \r
49         protected T control;\r
50         \r
51         @Override\r
52         public Control getControl() {\r
53                 return control;\r
54         }\r
55         \r
56         @Override\r
57         public void reset() {\r
58                 control = null;\r
59         }\r
60 \r
61         final protected boolean isDisposed() {\r
62                 Control c = getControl();\r
63                 return c == null ? false : c.isDisposed();\r
64         }\r
65 \r
66         final protected void dispatch(final Runnable runnable) {\r
67             if(isNodeDisposed()) return;\r
68                 IThreadWorkQueue thread = SWTThread.getThreadAccess();\r
69                 if(thread.currentThreadAccess()) runnable.run();\r
70                 else thread.asyncExec(new Runnable() {\r
71 \r
72                         @Override\r
73                         public void run() {\r
74                                 if(isDisposed()) return;\r
75                                 Control c = control;\r
76                                 if(c == null || c.isDisposed()) return;\r
77                                 runnable.run();\r
78                         }\r
79                         \r
80                 });\r
81         }\r
82         \r
83         private Field getPropertyField(String propertyName) {\r
84                 assert(!isNodeDisposed());\r
85                 return ScenegraphLoaderUtils.getPropertyField(this, propertyName);\r
86         }\r
87 \r
88         private Class<?> getPropertyType(Field field) {\r
89                 return field.getType();\r
90         }\r
91         \r
92         private Binding getPropertyBinding(Field field) {\r
93                 try {\r
94                         Binding b = Bindings.getBinding( BindingRequest.create( field ) );\r
95 \r
96                         // Safety checks for unusable bindings.\r
97                         if (b instanceof ArrayBinding && ((ArrayBinding) b).type().componentType() == null)\r
98                                 return null;\r
99 \r
100                         return b;\r
101                 } catch (BindingConstructionException e) {\r
102                         return null;\r
103                 } catch (Throwable t) {\r
104                         return null;\r
105                 }\r
106         }\r
107         \r
108         /**\r
109          * Convert binding to generic binding \r
110          * @param binding\r
111          * @return\r
112          */\r
113         private Binding getGenericPropertyBinding(Binding binding) {\r
114                 if (binding == null) return null;\r
115                 return Bindings.getBinding(binding.type());\r
116         }\r
117 \r
118         @Override\r
119         public Function1<Object, Boolean> getPropertyFunction(final String propertyName) {\r
120 \r
121             if(isNodeDisposed()) return null;\r
122             \r
123 //              assert(!isNodeDisposed());\r
124 \r
125                 final Field field = getPropertyField(propertyName);\r
126                 if(field != null) {\r
127 \r
128                         return new FunctionImpl1<Object, Boolean>() {\r
129 \r
130                                 final Method method = ScenegraphLoaderUtils.getSynchronizeMethod(SingleSWTViewNode.this, propertyName);\r
131                                 final Class<?> type = getPropertyType(field);\r
132                                 final Binding binding = getPropertyBinding(field);\r
133                                 final Binding genericBinding = getGenericPropertyBinding(binding);\r
134 \r
135                                 private Object setField(Object value) {\r
136 \r
137                                         try {\r
138                                                 if(type.isPrimitive() || (value == null) || type.isInstance(value) || type.isArray()) {\r
139                                                         field.set(SingleSWTViewNode.this, value);\r
140                                                         return value;\r
141                                                 } else {\r
142                                                         Object instance = binding.createDefaultUnchecked();\r
143                                                         binding.readFrom(genericBinding, value, instance);\r
144                                                         field.set(SingleSWTViewNode.this, instance);\r
145                                                         return instance;\r
146                                                 }\r
147                                         } catch (IllegalArgumentException e1) {\r
148                                                 e1.printStackTrace();\r
149                                         } catch (IllegalAccessException e1) {\r
150                                                 e1.printStackTrace();\r
151                                         } catch (BindingException e) {\r
152                                                 e.printStackTrace();\r
153                                         } catch (Throwable t) {\r
154                                                 t.printStackTrace();\r
155                                         }\r
156 \r
157                                         return null;\r
158 \r
159                                 }\r
160 \r
161                                 @Override\r
162                                 public Boolean apply(Object value) {\r
163 \r
164                                         if(isNodeDisposed()) return true;\r
165 \r
166                                         final Object translated = setField(value);\r
167 \r
168                                         if(method != null) {\r
169                                                 dispatch(new Runnable() {\r
170         \r
171                                                         @Override\r
172                                                         public void run() {\r
173         \r
174                                                                 try {\r
175                                                                         method.invoke(SingleSWTViewNode.this, translated);\r
176                                                                 } catch (IllegalArgumentException e) {\r
177                                                                         e.printStackTrace();\r
178                                                                 } catch (IllegalAccessException e) {\r
179                                                                         e.printStackTrace();\r
180                                                                 } catch (InvocationTargetException e) {\r
181                                                                         e.printStackTrace();\r
182                                                                 }\r
183                                                         }\r
184         \r
185                                                 });\r
186                                         }\r
187                                         return isDisposed();\r
188                                 }\r
189 \r
190                         };\r
191 \r
192                 } else {\r
193 \r
194                         return new FunctionImpl1<Object, Boolean>() {\r
195 \r
196                                 @Override\r
197                                 public Boolean apply(Object p0) {\r
198                                         assert(!isNodeDisposed());\r
199                                         genericProperties.put(propertyName, p0);\r
200                                         return isDisposed();\r
201                                 }\r
202 \r
203                         };\r
204 \r
205                 }\r
206 \r
207         }\r
208 \r
209         @Override\r
210         public void setPropertyCallback(Function2<String, Object, Boolean> callback) {\r
211                 this.propertyCallback = callback;\r
212         }\r
213         \r
214         @SuppressWarnings("unchecked")\r
215         @Override\r
216         public <T2> T2 getProperty(String propertyName) {\r
217 \r
218                 Method m = ScenegraphLoaderUtils.getReadMethod(this, propertyName);\r
219                 if(m != null) {\r
220 \r
221                         try {\r
222                                 return (T2)m.invoke(this);\r
223                         } catch (IllegalArgumentException e) {\r
224                                 throw new RuntimeException("Failed to get property '" + propertyName + "' for " + getClass().getName(), e);\r
225                         } catch (IllegalAccessException e) {\r
226                                 throw new RuntimeException("Failed to get property '" + propertyName + "' for " + getClass().getName(), e);\r
227                         } catch (InvocationTargetException e) {\r
228                                 throw new RuntimeException("Failed to get property '" + propertyName + "' for " + getClass().getName(), e);\r
229                         }\r
230                         \r
231                 } else {\r
232                         return (T2)genericProperties.get(propertyName);\r
233                 }\r
234                 \r
235         }\r
236         \r
237         protected void setProperties() {\r
238                 for(Method m : getClass().getMethods()) {\r
239                         if(m.getName().startsWith("synchronize")) {\r
240                                 String upperFieldName = m.getName().substring("synchronize".length());\r
241                                 String fieldName = upperFieldName.substring(0,1).toLowerCase() + upperFieldName.substring(1);\r
242                                 Field f = ScenegraphLoaderUtils.getPropertyField(this, fieldName);\r
243                                 try {\r
244                                         m.invoke(this, f.get(this));\r
245                                 } catch (IllegalArgumentException e) {\r
246                                         throw new RuntimeException("Failed to set property '" + fieldName + "' for " + getClass().getName(), e);\r
247                                 } catch (IllegalAccessException e) {\r
248                                         throw new RuntimeException("Failed to set property '" + fieldName + "' for " + getClass().getName(), e);\r
249                                 } catch (InvocationTargetException e) {\r
250                                         throw new RuntimeException("Failed to set property '" + fieldName + "' for " + getClass().getName(), e);\r
251                                 }\r
252                         }\r
253                 }\r
254         }\r
255         \r
256         public void synchronizeText(String text) {\r
257         }\r
258 \r
259         final public void synchronizeFont(Font font) {\r
260                 if (font == null && fontDesc == null)\r
261                         return;\r
262                 ResourceManager rm = getResourceManager();\r
263                 FontDescriptor oldDesc = fontDesc;\r
264                 if (font != null)\r
265                         control.setFont( getResourceManager().createFont( fontDesc = Fonts.swt(font) ) );\r
266                 if (oldDesc != null)\r
267                         rm.destroy(oldDesc);\r
268         }\r
269         \r
270         final public void synchronizeForeground(RGB.Integer foreground) {\r
271                 if (foreground == null && foregroundDesc == null)\r
272                         return;\r
273                 ResourceManager rm = getResourceManager();\r
274                 ColorDescriptor oldDesc = foregroundDesc;\r
275                 if (foreground != null)\r
276                         control.setForeground( getResourceManager().createColor( foregroundDesc = Colors.swt(foreground) ) );\r
277                 if (oldDesc != null)\r
278                         rm.destroy(oldDesc);\r
279         }\r
280 \r
281         final public void synchronizeBackground(RGB.Integer background) {\r
282                 if (background == null && backgroundDesc == null)\r
283                         return;\r
284                 ResourceManager rm = getResourceManager();\r
285                 ColorDescriptor oldDesc = backgroundDesc;\r
286                 if (background != null)\r
287                         control.setBackground( getResourceManager().createColor( backgroundDesc = Colors.swt(background) ) );\r
288                 if (oldDesc != null)\r
289                         rm.destroy(oldDesc);\r
290         }\r
291 \r
292         final public void synchronizeStyle(int style) {\r
293         }\r
294 \r
295         final public void synchronizeLayoutData(GridDataBean layoutData) {\r
296                 if(layoutData != null) control.setLayoutData(SWTViewUtils.toGridData(layoutData));\r
297         }\r
298         \r
299 }\r