1 package org.simantics.views.swt.client.base;
\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
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
32 abstract public class SingleSWTViewNode<T extends Control> extends SWTParentNode implements LoaderNode {
\r
34 private static final long serialVersionUID = -5810308021930769003L;
\r
36 private Map<String, Object> genericProperties = new HashMap<String, Object>();
\r
38 public Function2<String, Object, Boolean> propertyCallback;
\r
39 public GridDataBean layoutData;
\r
42 public RGB.Integer background;
\r
43 public RGB.Integer foreground;
\r
45 protected transient ColorDescriptor backgroundDesc;
\r
46 protected transient ColorDescriptor foregroundDesc;
\r
47 protected transient FontDescriptor fontDesc;
\r
49 protected T control;
\r
52 public Control getControl() {
\r
57 public void reset() {
\r
61 final protected boolean isDisposed() {
\r
62 Control c = getControl();
\r
63 return c == null ? false : c.isDisposed();
\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
74 if(isDisposed()) return;
\r
75 Control c = control;
\r
76 if(c == null || c.isDisposed()) return;
\r
83 private Field getPropertyField(String propertyName) {
\r
84 assert(!isNodeDisposed());
\r
85 return ScenegraphLoaderUtils.getPropertyField(this, propertyName);
\r
88 private Class<?> getPropertyType(Field field) {
\r
89 return field.getType();
\r
92 private Binding getPropertyBinding(Field field) {
\r
94 Binding b = Bindings.getBinding( BindingRequest.create( field ) );
\r
96 // Safety checks for unusable bindings.
\r
97 if (b instanceof ArrayBinding && ((ArrayBinding) b).type().componentType() == null)
\r
101 } catch (BindingConstructionException e) {
\r
103 } catch (Throwable t) {
\r
109 * Convert binding to generic binding
\r
113 private Binding getGenericPropertyBinding(Binding binding) {
\r
114 if (binding == null) return null;
\r
115 return Bindings.getBinding(binding.type());
\r
119 public Function1<Object, Boolean> getPropertyFunction(final String propertyName) {
\r
121 if(isNodeDisposed()) return null;
\r
123 // assert(!isNodeDisposed());
\r
125 final Field field = getPropertyField(propertyName);
\r
126 if(field != null) {
\r
128 return new FunctionImpl1<Object, Boolean>() {
\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
135 private Object setField(Object value) {
\r
138 if(type.isPrimitive() || (value == null) || type.isInstance(value) || type.isArray()) {
\r
139 field.set(SingleSWTViewNode.this, value);
\r
142 Object instance = binding.createDefaultUnchecked();
\r
143 binding.readFrom(genericBinding, value, instance);
\r
144 field.set(SingleSWTViewNode.this, instance);
\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
162 public Boolean apply(Object value) {
\r
164 if(isNodeDisposed()) return true;
\r
166 final Object translated = setField(value);
\r
168 if(method != null) {
\r
169 dispatch(new Runnable() {
\r
172 public void run() {
\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.getCause().printStackTrace();
\r
187 return isDisposed();
\r
194 return new FunctionImpl1<Object, Boolean>() {
\r
197 public Boolean apply(Object p0) {
\r
198 assert(!isNodeDisposed());
\r
199 genericProperties.put(propertyName, p0);
\r
200 return isDisposed();
\r
210 public void setPropertyCallback(Function2<String, Object, Boolean> callback) {
\r
211 this.propertyCallback = callback;
\r
214 @SuppressWarnings("unchecked")
\r
216 public <T2> T2 getProperty(String propertyName) {
\r
218 Method m = ScenegraphLoaderUtils.getReadMethod(this, propertyName);
\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.getCause());
\r
232 return (T2)genericProperties.get(propertyName);
\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
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.getCause());
\r
256 public void synchronizeText(String text) {
\r
259 final public void synchronizeFont(Font font) {
\r
260 if (font == null && fontDesc == null)
\r
262 ResourceManager rm = getResourceManager();
\r
263 FontDescriptor oldDesc = fontDesc;
\r
265 control.setFont( getResourceManager().createFont( fontDesc = Fonts.swt(font) ) );
\r
266 if (oldDesc != null)
\r
267 rm.destroy(oldDesc);
\r
270 final public void synchronizeForeground(RGB.Integer foreground) {
\r
271 if (foreground == null && foregroundDesc == null)
\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
281 final public void synchronizeBackground(RGB.Integer background) {
\r
282 if (background == null && backgroundDesc == null)
\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
292 final public void synchronizeStyle(int style) {
\r
295 final public void synchronizeLayoutData(GridDataBean layoutData) {
\r
296 if(layoutData != null) control.setLayoutData(SWTViewUtils.toGridData(layoutData));
\r