]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
e7284fc1db298ee0a8ddec1eb49b0c7037546370
[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.sysdyn.ui.trend.chart.properties;\r
13 \r
14 import java.util.Iterator;\r
15 import java.util.LinkedHashMap;\r
16 import java.util.List;\r
17 import java.util.Map;\r
18 \r
19 import org.eclipse.jface.layout.GridDataFactory;\r
20 import org.eclipse.jface.layout.GridLayoutFactory;\r
21 import org.eclipse.swt.SWT;\r
22 import org.eclipse.swt.custom.ScrolledComposite;\r
23 import org.eclipse.swt.graphics.Point;\r
24 import org.eclipse.swt.layout.GridLayout;\r
25 import org.eclipse.swt.widgets.Composite;\r
26 import org.eclipse.swt.widgets.Control;\r
27 import org.eclipse.swt.widgets.Label;\r
28 import org.simantics.browsing.ui.swt.widgets.TrackedCombo;\r
29 import org.simantics.browsing.ui.swt.widgets.impl.ComboModifyListenerImpl;\r
30 import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl;\r
31 import org.simantics.browsing.ui.swt.widgets.impl.Widget;\r
32 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;\r
33 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl;\r
34 import org.simantics.databoard.Bindings;\r
35 import org.simantics.db.ReadGraph;\r
36 import org.simantics.db.Resource;\r
37 import org.simantics.db.WriteGraph;\r
38 import org.simantics.db.common.utils.NameUtils;\r
39 import org.simantics.db.common.utils.OrderedSetUtils;\r
40 import org.simantics.db.exception.DatabaseException;\r
41 import org.simantics.db.layer0.variable.Variable;\r
42 import org.simantics.db.layer0.variable.Variables;\r
43 import org.simantics.db.management.ISessionContext;\r
44 import org.simantics.db.procedure.Listener;\r
45 import org.simantics.db.request.Read;\r
46 import org.simantics.sysdyn.JFreeChartResource;\r
47 import org.simantics.sysdyn.SysdynResource;\r
48 import org.simantics.sysdyn.ui.trend.chart.ChartUtils;\r
49 import org.simantics.ui.utils.AdaptionUtils;\r
50 import org.simantics.utils.RunnableWithObject;\r
51 import org.simantics.utils.datastructures.Quad;\r
52 import org.simantics.utils.datastructures.Triple;\r
53 \r
54 /**\r
55  * Composite for range controls in chart series properties\r
56  * @author Teemu Lempinen\r
57  *\r
58  */\r
59 public class RangeComposite extends Composite implements Widget {\r
60 \r
61     private Composite composite;\r
62     \r
63     public RangeComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) {\r
64         super(parent, style);\r
65         support.register(this);\r
66         GridLayoutFactory.fillDefaults().spacing(3, 0).margins(3, 3).applyTo(this);\r
67         GridDataFactory.fillDefaults().grab(true, false).applyTo(this);\r
68         composite = this;\r
69     }\r
70 \r
71     @Override\r
72     public void setInput(final ISessionContext context, final Object input) {\r
73         if(composite == null || composite.isDisposed())\r
74             return;\r
75 \r
76         final Resource series = AdaptionUtils.adaptToSingle(input, Resource.class);\r
77 \r
78         /*\r
79          *  Listen to the enumerations assigned to the variable in this series.\r
80          *  Listener is needed because the user can change the variableRVI for the series\r
81          *  and that changes the options for range\r
82          */\r
83         context.getSession().asyncRequest(new Read<LinkedHashMap<String, Resource>>() {\r
84 \r
85             @Override\r
86             public LinkedHashMap<String, Resource> perform(ReadGraph graph) throws DatabaseException {\r
87                 JFreeChartResource jfree = JFreeChartResource.getInstance(graph);\r
88                 SysdynResource sr = SysdynResource.getInstance(graph);\r
89 \r
90                 String realizationURI = ChartUtils.getCurrentRealizationURI(graph, series);\r
91                 String rvi = graph.getPossibleRelatedValue(series, jfree.variableRVI);\r
92                 if(rvi == null)\r
93                     return null;\r
94                 \r
95                 try {\r
96                     // Find the variable for the current variableRVI\r
97                     Variable v = Variables.getVariable(graph, realizationURI + rvi.trim());\r
98                     if(v == null)\r
99                         return null;\r
100                     Resource variable = v.getRepresents(graph);\r
101                     \r
102                     // Return the enumerations assigned to that variable\r
103                     Resource arrayIndexes = graph.getPossibleObject(variable, sr.Variable_arrayIndexes);\r
104                     if(arrayIndexes != null) {\r
105                         LinkedHashMap<String, Resource> result = new LinkedHashMap<String, Resource>();\r
106                         for(Resource enumeration : OrderedSetUtils.toList(graph, arrayIndexes)) {\r
107                             String enumerationName = NameUtils.getSafeName(graph, enumeration);\r
108                             result.put(enumerationName, enumeration);\r
109                         }\r
110                         return result;\r
111                     }\r
112                 } catch (DatabaseException e) {\r
113                     // No variable was found, return null\r
114                 }\r
115                 return null;\r
116             }\r
117 \r
118         }, new Listener<LinkedHashMap<String, Resource>>() {\r
119 \r
120             @Override\r
121             public void execute(LinkedHashMap<String, Resource> result) {\r
122                 if(isDisposed())\r
123                     return;\r
124 \r
125                 // Always modify the composite, even with null result\r
126                 composite.getDisplay().asyncExec(new RunnableWithObject(result) {\r
127                     @Override\r
128                     public void run() {\r
129                         if(composite == null || composite.isDisposed())\r
130                             return;\r
131 \r
132                         // Remove all content (even with null result)\r
133                         for(Control child : composite.getChildren())\r
134                             child.dispose();\r
135 \r
136                         if(getObject() == null)\r
137                             return;\r
138 \r
139                         // New widgetSupport for the combos\r
140                         WidgetSupportImpl support = new WidgetSupportImpl();\r
141 \r
142                         Label label;\r
143                         TrackedCombo combo;\r
144                         LinkedHashMap<?, ?> result = (LinkedHashMap<?, ?>)getObject();\r
145                         Iterator<?> iterator = result.keySet().iterator();\r
146                         \r
147                         // For each array index (enumeration), create a label and a combo \r
148                         int index = 0;\r
149                         while(iterator.hasNext()) {\r
150                             Object key = iterator.next();\r
151                             Composite c = new Composite(composite, SWT.NONE);\r
152                             GridDataFactory.fillDefaults().applyTo(c);\r
153                             GridLayoutFactory.fillDefaults().applyTo(c);\r
154                             \r
155                             label = new Label(c, SWT.NONE);\r
156                             label.setText((String)key);\r
157                             GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.END).applyTo(label);\r
158 \r
159                             combo = new TrackedCombo(c, support, SWT.READ_ONLY);\r
160                             combo.setItemFactory(new RangeItemFactory(index, (Resource)result.get(key)));\r
161                             combo.setSelectionFactory(new RangeSelectionFactory(index));\r
162                             combo.addModifyListener(new RangeModifyListener(index, result.size()));\r
163                             GridDataFactory.fillDefaults().applyTo(combo.getWidget());\r
164                             index++;\r
165                         }\r
166                         \r
167                         // Set the width of the combo \r
168                         GridLayout gl = (GridLayout)composite.getLayout();\r
169                         gl.numColumns = index;\r
170                         \r
171                         // Set input for the combos\r
172                         support.fireInput(context, input);\r
173                         \r
174                         /*\r
175                          *  Find out if this composite is located in a scrolled composite. \r
176                          *  If it is, resize the scrolled composite\r
177                          */\r
178                         Composite previousParent = composite.getParent();\r
179                         for(int i = 0; i < 5; i++) {\r
180                             if(previousParent.getParent() instanceof ScrolledComposite) {\r
181                                 previousParent.layout();\r
182                                 ScrolledComposite sc = (ScrolledComposite) previousParent.getParent();\r
183                                 Point size = previousParent.computeSize(SWT.DEFAULT, SWT.DEFAULT);\r
184                                 sc.setMinSize(size);\r
185                                 break;\r
186                             }\r
187                             previousParent = previousParent.getParent();\r
188                         }\r
189                     }\r
190                 });                    \r
191             }\r
192 \r
193             @Override\r
194             public void exception(Throwable t) {\r
195                 t.printStackTrace();\r
196             }\r
197 \r
198             @Override\r
199             public boolean isDisposed() {\r
200                 return composite == null || composite.isDisposed();\r
201             }\r
202         });\r
203     }\r
204 \r
205     /**\r
206      * \r
207      * @author Teemu Lempinen\r
208      *\r
209      */\r
210     private class RangeSelectionFactory extends ReadFactoryImpl<Resource, String> {\r
211 \r
212         int index;\r
213 \r
214         /**\r
215          * \r
216          * @param index Index of the enumeration in the variable\r
217          */\r
218         public RangeSelectionFactory(int index) {\r
219             this.index = index;\r
220         }\r
221 \r
222         public Object getIdentity(Object inputContents) {\r
223             return new Triple<Object, Integer, Class<?>>(inputContents, index, getClass());\r
224         }\r
225 \r
226         @Override\r
227         public String perform(ReadGraph graph, Resource series) throws DatabaseException {\r
228             JFreeChartResource jfree = JFreeChartResource.getInstance(graph);\r
229             String[] filter = graph.getPossibleRelatedValue(series, jfree.variableFilter, Bindings.STRING_ARRAY);\r
230             \r
231             /*\r
232              * If no filter was found or the index is not applicable, return "All"\r
233              */\r
234             if(filter == null)\r
235                 return "All";\r
236             else if(filter.length < index)\r
237                 return "All";\r
238             else\r
239                 return filter[index];\r
240         }\r
241 \r
242     }\r
243 \r
244     /**\r
245      * RangeItemFactory finds all inexes of a given enumeration \r
246      * and adds "Sum" and "All" to the returned indexes\r
247      * @author Teemu Lempinen\r
248      *\r
249      */\r
250     private class RangeItemFactory extends ReadFactoryImpl<Resource, Map<String, Object>> {\r
251 \r
252         private int index;\r
253         private Resource enumeration;\r
254 \r
255         /**\r
256          * \r
257          * @param index Index of the enumeration in the variable\r
258          * @param enumeration The enumeration\r
259          */\r
260         public RangeItemFactory(int index, Resource enumeration) {\r
261             this.index = index;\r
262             this.enumeration = enumeration;\r
263         }\r
264 \r
265         public Object getIdentity(Object inputContents) {\r
266             return new Quad<Object, Integer, Resource, Class<?>>(inputContents, index, enumeration, getClass());\r
267         }\r
268         @Override\r
269         public Map<String, Object> perform(ReadGraph graph, Resource series) throws DatabaseException {\r
270             SysdynResource sr = SysdynResource.getInstance(graph);\r
271             LinkedHashMap<String, Object> result = new LinkedHashMap<String, Object>();\r
272             Resource enumerationIndexes = graph.getPossibleObject(enumeration, sr.Enumeration_enumerationIndexes);\r
273             List<Resource> indexes = OrderedSetUtils.toList(graph, enumerationIndexes);\r
274             // First add "All" and "Sum", then all of the enumeration indexes in order\r
275             result.put("All", "All");\r
276             result.put("Sum", "Sum");\r
277             for(Resource index : indexes) {\r
278                 String name = NameUtils.getSafeName(graph, index);\r
279                 result.put(name, name);\r
280             }\r
281             return result;\r
282         }\r
283     }\r
284 \r
285     /**\r
286      * RangeModifyListener for modifying a range filter in chart series \r
287      * @author Teemu Lempinen\r
288      *\r
289      */\r
290     private class RangeModifyListener  extends ComboModifyListenerImpl<Resource> {\r
291         \r
292         private int index, size;\r
293 \r
294         /**\r
295          * \r
296          * @param index Index of the modified range filter\r
297          * @param size Size of the whole filter (for situations where there is no filter)\r
298          */\r
299         public RangeModifyListener(int index, int size) {\r
300             this.index = index;\r
301             this.size = size;\r
302         }\r
303 \r
304         @Override\r
305         public void applyText(WriteGraph graph, Resource series, String text) throws DatabaseException {\r
306             JFreeChartResource jfree = JFreeChartResource.getInstance(graph);\r
307             String[] filter = graph.getPossibleRelatedValue(series, jfree.variableFilter, Bindings.STRING_ARRAY);\r
308             \r
309             // If there is no filter, create a default filter with all indexes "All"\r
310             if(filter == null) {\r
311                 filter = new String[size];\r
312                 for(int i = 0; i < filter.length; i++) {\r
313                     filter[i] = "All";\r
314                 }\r
315             }\r
316             \r
317             // Modify the filter index\r
318             filter[index] = text;\r
319             graph.claimLiteral(series, jfree.variableFilter, filter, Bindings.STRING_ARRAY);\r
320         }\r
321     }\r
322 }\r