]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
e5f003f8d12514a1b0eb333b81217a7147fd56d6
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
3  * 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.jfreechart.chart.properties;\r
13 \r
14 import org.eclipse.jface.layout.GridDataFactory;\r
15 import org.eclipse.jface.layout.GridLayoutFactory;\r
16 import org.eclipse.jface.resource.ImageDescriptor;\r
17 import org.eclipse.jface.resource.JFaceResources;\r
18 import org.eclipse.jface.resource.LocalResourceManager;\r
19 import org.eclipse.swt.SWT;\r
20 import org.eclipse.swt.events.SelectionEvent;\r
21 import org.eclipse.swt.graphics.Point;\r
22 import org.eclipse.swt.graphics.RGB;\r
23 import org.eclipse.swt.widgets.ColorDialog;\r
24 import org.eclipse.swt.widgets.Composite;\r
25 import org.eclipse.swt.widgets.Display;\r
26 import org.eclipse.swt.widgets.Shell;\r
27 import org.simantics.browsing.ui.swt.widgets.Button;\r
28 import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl;\r
29 import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl;\r
30 import org.simantics.browsing.ui.swt.widgets.impl.Widget;\r
31 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;\r
32 import org.simantics.db.ReadGraph;\r
33 import org.simantics.db.Resource;\r
34 import org.simantics.db.WriteGraph;\r
35 import org.simantics.db.common.request.WriteRequest;\r
36 import org.simantics.db.exception.DatabaseException;\r
37 import org.simantics.db.management.ISessionContext;\r
38 import org.simantics.db.procedure.Listener;\r
39 import org.simantics.db.request.Read;\r
40 import org.simantics.diagram.stubs.G2DResource;\r
41 import org.simantics.sysdyn.JFreeChartResource;\r
42 import org.simantics.ui.SimanticsUI;\r
43 import org.simantics.utils.RunnableWithObject;\r
44 import org.simantics.utils.datastructures.Triple;\r
45 import org.simantics.utils.ui.AdaptionUtils;\r
46 import org.simantics.utils.ui.gfx.ColorImageDescriptor;\r
47 \r
48 /**\r
49  * Composite for selecting a color for a chart component\r
50  * \r
51  * @author Teemu Lempinen\r
52  *\r
53  */\r
54 public class ColorPicker extends Composite implements Widget {\r
55 \r
56     Button defaultColor, customColor, color;\r
57     \r
58     /**\r
59      * Create a composite containing radio buttons for default or custom color. Color chooser button is active\r
60      * when the custom radio button is selected. Color chooser uses {@link ColorDialog} to select a color \r
61      * \r
62      * @param parent Composite\r
63      * @param context ISessionContext\r
64      * @param support WidgetSupport\r
65      * @param style SWT style\r
66      */\r
67     public ColorPicker(Composite parent, ISessionContext context, WidgetSupport support, int style) {\r
68         this(parent, context, support, style, true);\r
69     }\r
70 \r
71     /**\r
72      * Create a composite containing radio buttons for default or custom color. Color chooser button is active\r
73      * when the custom radio button is selected. Color chooser uses {@link ColorDialog} to select a color \r
74      * \r
75      * @param parent Composite\r
76      * @param context ISessionContext\r
77      * @param support WidgetSupport\r
78      * @param style SWT style\r
79      * @param defaultColor provide default color widget?\r
80      */\r
81     public ColorPicker(Composite parent, ISessionContext context, WidgetSupport support, int style, boolean defaultColor) {\r
82         super(parent, style);\r
83         support.register(this);\r
84         \r
85         if(support.getParameter(WidgetSupport.RESOURCE_MANAGER) == null) {\r
86             LocalResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources(), this);\r
87             support.setParameter(WidgetSupport.RESOURCE_MANAGER, resourceManager);\r
88         }\r
89         \r
90         if(defaultColor) {\r
91             GridLayoutFactory.fillDefaults().numColumns(4).applyTo(this);\r
92 \r
93             this.defaultColor = new Button(this, support, SWT.RADIO);\r
94             this.defaultColor.setText("default");\r
95             this.defaultColor.setSelectionFactory(new DefaultColorSelectionFactory(false));\r
96             this.defaultColor.addSelectionListener(new DefaultColorSelectionListener(context));\r
97             GridDataFactory.fillDefaults().applyTo(this.defaultColor.getWidget());\r
98 \r
99             customColor = new Button(this, support, SWT.RADIO);\r
100             customColor.setText("custom");\r
101             customColor.setSelectionFactory(new DefaultColorSelectionFactory(true));\r
102             customColor.addSelectionListener(new DefaultColorSelectionListener(context));\r
103 \r
104             GridDataFactory.fillDefaults().applyTo(customColor.getWidget());\r
105         } else {\r
106             GridLayoutFactory.fillDefaults().applyTo(this);\r
107         }\r
108         \r
109         \r
110         color = new Button(this, support, SWT.PUSH);\r
111         color.setImageFactory(new ColorImageFactoryFactory(this));\r
112         color.addSelectionListener(new ColorSelectionListener(context));\r
113         color.getWidget().setEnabled(false);\r
114         GridDataFactory.fillDefaults().applyTo(color.getWidget());\r
115     }\r
116 \r
117     /**\r
118      * Method for finding the resource for which the color is selected. \r
119      * \r
120      * @param graph ReadGraph\r
121      * @param input input from WidgetSupport\r
122      * @return\r
123      * @throws DatabaseException\r
124      */\r
125     protected Resource getResource(ReadGraph graph, Resource input) throws DatabaseException {\r
126         return input;\r
127     }\r
128     \r
129     /**\r
130      * Method for getting the relation with which the g2d.Color is related to a resource\r
131      * \r
132      * @param graph ReadGraph\r
133      * @return Color relation\r
134      * @throws DatabaseException\r
135      */\r
136     protected Resource getColorRelation(ReadGraph graph) throws DatabaseException {\r
137         JFreeChartResource jfree = JFreeChartResource.getInstance(graph);\r
138         return jfree.color;\r
139     }\r
140     \r
141     \r
142     @Override\r
143     public void setInput(ISessionContext context, Object input) {\r
144         final Resource resource = AdaptionUtils.adaptToSingle(input, Resource.class);\r
145         \r
146         // Create a listener to define the enabled state of the color chooser button\r
147         context.getSession().asyncRequest(new Read<Float[]>() {\r
148 \r
149             @Override\r
150             public Float[] perform(ReadGraph graph) throws DatabaseException {\r
151                 if(graph.hasStatement(getResource(graph, resource), getColorRelation(graph))) {\r
152                     float[] components = graph.getPossibleRelatedValue(getResource(graph, resource), getColorRelation(graph));\r
153                     Float[] result = new Float[components.length];\r
154                     for(int i = 0; i < components.length; i++) result[i] = components[i];\r
155                     return result;\r
156                 } else {\r
157                     return null;\r
158                 }\r
159             }\r
160             \r
161         }, new Listener<Float[]>() {\r
162 \r
163             @Override\r
164             public void execute(Float[] result) {\r
165                 if(!color.getWidget().isDisposed()) {\r
166                     color.getWidget().getDisplay().asyncExec(new RunnableWithObject(result != null ? true : false) {\r
167                         @Override\r
168                         public void run() {\r
169                             if(!color.getWidget().isDisposed()) {\r
170                                 if(!Boolean.TRUE.equals(getObject()))\r
171                                     color.getWidget().setEnabled(false);\r
172                                 else\r
173                                     color.getWidget().setEnabled(true);\r
174                             }\r
175                         }\r
176                     });\r
177                 }\r
178             }\r
179 \r
180             @Override\r
181             public void exception(Throwable t) {\r
182                 t.printStackTrace();\r
183             }\r
184 \r
185             @Override\r
186             public boolean isDisposed() {\r
187                 return color.getWidget().isDisposed();\r
188             }\r
189         });\r
190     }\r
191     \r
192 \r
193     /**\r
194      * ImageFactory returning an image for color button\r
195      * @author Teemu Lempinen\r
196      *\r
197      */\r
198     private class ColorImageFactoryFactory extends ReadFactoryImpl<Resource, ImageDescriptor> {\r
199         \r
200         private ColorPicker picker;\r
201         \r
202         public ColorImageFactoryFactory(ColorPicker colorPicker) {\r
203             this.picker = colorPicker;\r
204         }\r
205 \r
206         @Override\r
207         public ImageDescriptor perform(ReadGraph graph, Resource input) throws DatabaseException {\r
208             RGB rgb = getColor(graph, getResource(graph, input));\r
209             return new ColorImageDescriptor(rgb.red, rgb.green, rgb.blue, 20, 20, false);\r
210  \r
211         }\r
212         \r
213         @Override\r
214         public Object getIdentity(Object inputContents) {\r
215             return new Triple<Object, ColorPicker, Class<?>>(inputContents, picker, getClass());\r
216         }\r
217 \r
218     }\r
219 \r
220     /**\r
221      * Get RGB from a color literal resource. If resource is not a color resource, return blue (RGB 0, 0, 255)\r
222      * @param graph ReadGraph\r
223      * @param input Color literal resource (float[4])\r
224      * @return RGB color\r
225      * @throws DatabaseException\r
226      */\r
227     private RGB getColor(ReadGraph graph, Resource input) throws DatabaseException{\r
228         float[] colorComponents = graph.getPossibleRelatedValue(input, getColorRelation(graph));\r
229         RGB rgb;\r
230         if(colorComponents == null)\r
231             rgb = new RGB(0, 0, 255);\r
232         else\r
233             rgb = new RGB((int)(colorComponents[0] * 255.0f), \r
234                     (int)(colorComponents[1] * 255.0f), \r
235                     (int)(colorComponents[2] * 255.0f));\r
236         return rgb;\r
237     }\r
238 \r
239 \r
240     /**\r
241      * SelectionListener for color button. \r
242      * \r
243      * @author Teemu Lempinen\r
244      *\r
245      */\r
246     private class ColorSelectionListener extends SelectionListenerImpl<Resource> {\r
247 \r
248         private SelectionEvent e;\r
249         private RGB rgb;\r
250         \r
251         /**\r
252          * \r
253          * @param context ISessionContext\r
254          */\r
255         public ColorSelectionListener(ISessionContext context) {\r
256             super(context);\r
257         }\r
258 \r
259         @Override\r
260         public void widgetSelected(SelectionEvent e) {\r
261             if(color.getWidget().isDisposed())\r
262                 return;\r
263             // Save the event for coordinates\r
264             this.e = e;\r
265             super.widgetSelected(e);\r
266         }\r
267 \r
268         @Override\r
269         public void apply(WriteGraph graph, Resource input) throws DatabaseException {\r
270             if(color.getWidget().isDisposed())\r
271                 return;\r
272             \r
273             final Resource resource = getResource(graph, input);\r
274             final Display display = color.getWidget().getDisplay();\r
275             final RGB oldRGB = getColor(graph, resource);\r
276             \r
277             display.asyncExec(new RunnableWithObject(oldRGB) {\r
278                 @Override\r
279                 public void run() {\r
280                     // Use color dialog to select a color\r
281                     Shell shell = new Shell(display);\r
282                     ColorDialog cd = new ColorDialog(shell);\r
283                     Point point = color.getWidget().toDisplay(e.x - 150, e.y - 150);\r
284                     cd.getParent().setLocation(point.x, point.y);\r
285                     cd.setText("Select color");\r
286                     cd.setRGB((RGB)getObject());\r
287                     rgb = cd.open();\r
288                     if(rgb == null)\r
289                         return;\r
290                     \r
291                     SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
292                         \r
293                         @Override\r
294                         public void perform(WriteGraph graph) throws DatabaseException {\r
295                             G2DResource g2d = G2DResource.getInstance(graph);\r
296                             float[] components = new float[] {rgb.red / 255.0f,  rgb.green / 255.0f, rgb.blue / 255.0f, 1.0f};\r
297                             graph.claimLiteral(resource, getColorRelation(graph), g2d.Color, components);                            \r
298                         }\r
299                     });\r
300                     \r
301                 }\r
302             });\r
303             \r
304             \r
305 \r
306         }\r
307 \r
308     }\r
309 \r
310     /**\r
311      * SelectionFactory for default and custom color radio buttons\r
312      * @author Teemu Lempinen\r
313      *\r
314      */\r
315     private class DefaultColorSelectionFactory extends ReadFactoryImpl<Resource, Boolean> {\r
316 \r
317         private final Boolean isCustom;\r
318 \r
319         /**\r
320          * \r
321          * @param isCustom Is this custom button?\r
322          */\r
323         public DefaultColorSelectionFactory(Boolean isCustom) {\r
324             super();\r
325             this.isCustom = isCustom;\r
326         }\r
327 \r
328         @Override\r
329         public Object getIdentity(Object inputContents) {\r
330             return new Triple<Resource, Object, Boolean>((Resource) inputContents, getClass(), isCustom);\r
331         }\r
332 \r
333         @Override\r
334         public Boolean perform(ReadGraph graph, Resource input) throws DatabaseException {\r
335             Resource r = graph.getPossibleObject(getResource(graph, input), getColorRelation(graph));\r
336             boolean result = false; // Default == not selected\r
337             if(r == null && !isCustom) {\r
338                 // No color definition and default-button -> selected\r
339                 result =  true;\r
340             } else if(r != null && isCustom) {\r
341                 // color definition and custom button -> selected\r
342                 result =  true;\r
343             }\r
344             return result;\r
345         }\r
346 \r
347     }\r
348 \r
349     /**\r
350      * SelectionListener for default and custom radio buttons\r
351      * \r
352      * @author Teemu Lempinen\r
353      *\r
354      */\r
355     private class DefaultColorSelectionListener extends SelectionListenerImpl<Resource> {\r
356 \r
357         private SelectionEvent e;\r
358 \r
359         public DefaultColorSelectionListener(ISessionContext context) {\r
360             super(context);\r
361         }\r
362 \r
363         @Override\r
364         public void widgetSelected(SelectionEvent e) {\r
365             this.e = e; \r
366             super.widgetSelected(e);\r
367         }\r
368 \r
369         @Override\r
370         public void apply(WriteGraph graph, Resource input) throws DatabaseException {\r
371             Resource resource = getResource(graph, input);\r
372             if(customColor.getWidget().equals(e.widget)) {\r
373                 // Custom selected. If there is no color already, create a default Blue color\r
374                 G2DResource g2d = G2DResource.getInstance(graph);\r
375                 if(graph.getPossibleObject(resource, getColorRelation(graph)) == null) {\r
376                     float[] components = java.awt.Color.BLUE.getColorComponents(new float[4]);\r
377                     components[3] = 1.0f;\r
378                     graph.claimLiteral(resource, getColorRelation(graph), g2d.Color, components);\r
379                 }\r
380             } else {\r
381                 // Default selected, remove color definition\r
382                 graph.deny(resource, getColorRelation(graph));\r
383             }\r
384         }\r
385     }\r
386 \r
387 \r
388 }\r