]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.charts/src/org/simantics/charts/editor/AddMilestoneHandler.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / editor / AddMilestoneHandler.java
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.charts.editor;\r
13 \r
14 import org.eclipse.core.commands.AbstractHandler;\r
15 import org.eclipse.core.commands.ExecutionEvent;\r
16 import org.eclipse.core.commands.ExecutionException;\r
17 import org.eclipse.core.expressions.IEvaluationContext;\r
18 import org.eclipse.jface.dialogs.Dialog;\r
19 import org.eclipse.jface.dialogs.IDialogSettings;\r
20 import org.eclipse.jface.dialogs.IInputValidator;\r
21 import org.eclipse.jface.fieldassist.ControlDecoration;\r
22 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;\r
23 import org.eclipse.jface.layout.GridDataFactory;\r
24 import org.eclipse.jface.layout.GridLayoutFactory;\r
25 import org.eclipse.swt.SWT;\r
26 import org.eclipse.swt.events.ModifyEvent;\r
27 import org.eclipse.swt.events.ModifyListener;\r
28 import org.eclipse.swt.graphics.Image;\r
29 import org.eclipse.swt.graphics.Point;\r
30 import org.eclipse.swt.widgets.Button;\r
31 import org.eclipse.swt.widgets.Composite;\r
32 import org.eclipse.swt.widgets.Control;\r
33 import org.eclipse.swt.widgets.Label;\r
34 import org.eclipse.swt.widgets.Shell;\r
35 import org.eclipse.swt.widgets.Text;\r
36 import org.simantics.Simantics;\r
37 import org.simantics.charts.Activator;\r
38 import org.simantics.databoard.Bindings;\r
39 import org.simantics.db.Resource;\r
40 import org.simantics.db.Session;\r
41 import org.simantics.db.VirtualGraph;\r
42 import org.simantics.db.WriteGraph;\r
43 import org.simantics.db.common.request.WriteRequest;\r
44 import org.simantics.db.exception.DatabaseException;\r
45 import org.simantics.db.service.VirtualGraphSupport;\r
46 import org.simantics.event.ontology.EventResource;\r
47 import org.simantics.event.ontology.EventViewResource;\r
48 import org.simantics.event.util.EventWriteData;\r
49 import org.simantics.event.view.handler.CorrectMilestoneLabelsAction;\r
50 import org.simantics.layer0.Layer0;\r
51 import org.simantics.trend.impl.TrendNode;\r
52 import org.simantics.utils.format.TimeFormat;\r
53 \r
54 /**\r
55  * This handler opens a dialog for new milestone.\r
56  * \r
57  * @author toni.kalajainen\r
58  */\r
59 public class AddMilestoneHandler extends AbstractHandler {\r
60 \r
61     @Override\r
62     public Object execute(ExecutionEvent event) throws ExecutionException {\r
63 \r
64         TimeSeriesEditor tse = getTSE(event);\r
65         if (tse == null)\r
66             return null;\r
67         TrendNode tn = tse.trendNode;\r
68         if (tn == null)\r
69             return null;\r
70         final Resource experiment = tse.chartData.run;\r
71         if (experiment == null)\r
72             return null;\r
73 \r
74         EventData data = new EventData();\r
75         data.initialTime = tn.lastMouseHoverTime;\r
76         AddMilestoneDialog d = new AddMilestoneDialog( tse.getSite().getShell(), data );\r
77         int ok = d.open();\r
78         if (ok != Dialog.OK)\r
79             return null;\r
80 \r
81         Session session = Simantics.getSession();\r
82         VirtualGraph vg = session.getService(VirtualGraphSupport.class).getWorkspacePersistent("experiments");\r
83         session.async( new CreateManualEvent(vg, experiment, data) );\r
84 \r
85         return null;\r
86     }\r
87 \r
88     TimeSeriesEditor getTSE(ExecutionEvent event) {\r
89         Object eac = event.getApplicationContext();\r
90         if (eac == null || (eac instanceof IEvaluationContext == false)) return null;\r
91         IEvaluationContext ec = (IEvaluationContext) eac;\r
92         Object editor = ec.getVariable("activeEditor");\r
93         if (editor == null || (editor instanceof TimeSeriesEditor == false)) return null;\r
94         TimeSeriesEditor tse = (TimeSeriesEditor) editor;\r
95         return tse;\r
96     }\r
97 \r
98     static class CreateManualEvent extends WriteRequest {\r
99 \r
100         private final Resource experiment;\r
101         private final EventData eventData;\r
102 \r
103         public CreateManualEvent(VirtualGraph vg, Resource experiment, EventData eventData) {\r
104             super(vg);\r
105             this.experiment = experiment;\r
106             this.eventData = eventData;\r
107         }\r
108 \r
109         @Override\r
110         public void perform(WriteGraph graph) throws DatabaseException {\r
111             Layer0 L0 = Layer0.getInstance(graph);\r
112             EventResource EVENT = EventResource.getInstance(graph);\r
113             EventViewResource EVENTVIEW = EventViewResource.getInstance(graph);\r
114             Resource eventlog = graph.getPossibleObject(experiment, EVENT.IsEventProducerOf);\r
115             if (eventlog == null) return;\r
116 \r
117             EventWriteData data = new EventWriteData(graph, eventlog, getProvider());\r
118             data.prepareToWrite(graph);\r
119 \r
120             Resource event = graph.newResource(); \r
121             graph.claim(event, L0.InstanceOf, EVENT.Event);\r
122             graph.claimLiteral(event, L0.HasName, L0.String, ""+data.targetPos, Bindings.STRING);\r
123             graph.claimLiteral(event, L0.HasLabel, L0.HasLabel_Inverse, L0.String, eventData.description, Bindings.STRING);\r
124             graph.claimLiteral(event, L0.HasDescription, L0.HasDescription_Inverse, L0.String, eventData.description, Bindings.STRING);\r
125             graph.claimLiteral(event, EVENT.HasTimestamp, EVENT.HasTimestamp_Inverse, EVENT.TimeStamp, eventData.parsedTime, Bindings.DOUBLE);\r
126             if (eventData.isMilestone)\r
127                 graph.claim(event, EVENT.Milestone, event);\r
128             if (eventData.isBaseline) {\r
129                 graph.deny(eventlog, EVENT.EventLog_HasBaselineEvent);\r
130                 graph.claim(eventlog, EVENT.EventLog_HasBaselineEvent, event);\r
131             }\r
132             graph.claim(event, EVENT.Event_type, null, EVENTVIEW.ManualEventType);\r
133             graph.claimLiteral(event, EVENT.Event_message, EVENT.Event_message_Inverse, L0.String, eventData.message, Bindings.STRING);\r
134             graph.claimLiteral(event, EVENT.Event_tag, EVENT.Event_tag_Inverse, L0.String, eventData.tag, Bindings.STRING);\r
135             graph.claim(event, EVENT.NoReturn, EVENT.NoReturn, event);\r
136             graph.claim(data.targetSlice, L0.ConsistsOf, L0.PartOf, event);\r
137 \r
138             data.written();\r
139             data.commit(graph);\r
140 \r
141             graph.syncRequest( new CorrectMilestoneLabelsAction(eventlog, getProvider()) );\r
142         }\r
143     }\r
144 \r
145 }\r
146 \r
147 \r
148 class AddMilestoneDialog extends Dialog {\r
149 \r
150     private static final String DIALOG = "AddMilestoneDialog"; //$NON-NLS-1$\r
151 \r
152     IInputValidator timeValidator = new IInputValidator() {\r
153         @Override\r
154         public String isValid(String text) {\r
155             if (text.trim().isEmpty())\r
156                 return null;\r
157             return TimeInputValidator.INSTANCE.isValid(text);\r
158         }\r
159     };  \r
160 \r
161     Label nameLabel, descLabel, tagLabel, timeLabel, baselineLabel;\r
162     Text nameText, descText, tagText, timeText;\r
163     Button baselineButt;\r
164     ControlDecoration timeDecor;\r
165 \r
166     EventData data;\r
167 \r
168     private IDialogSettings dialogBoundsSettings;\r
169 \r
170     protected AddMilestoneDialog(Shell parentShell, EventData data) {\r
171         super(parentShell);\r
172         this.data = data;\r
173 \r
174         IDialogSettings settings = Activator.getDefault().getDialogSettings();\r
175         dialogBoundsSettings = settings.getSection(DIALOG);\r
176         if (dialogBoundsSettings == null)\r
177             dialogBoundsSettings = settings.addNewSection(DIALOG);\r
178     }\r
179 \r
180     @Override\r
181     protected IDialogSettings getDialogBoundsSettings() {\r
182         return dialogBoundsSettings;\r
183     }\r
184 \r
185     @Override\r
186     protected int getShellStyle() {\r
187         return SWT.RESIZE | SWT.MODELESS | SWT.TITLE | SWT.CLOSE | SWT.BORDER;\r
188     }\r
189 \r
190     @Override\r
191     protected void configureShell(Shell newShell) {\r
192         super.configureShell(newShell);\r
193         newShell.setText("Add new milestone");\r
194     }\r
195 \r
196     @Override\r
197     protected Point getInitialSize() {\r
198         return super.getInitialSize();\r
199     }\r
200 \r
201     @Override\r
202     protected Control createDialogArea(Composite parent) \r
203     {\r
204         Composite composite = (Composite) super.createDialogArea(parent);\r
205         GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(4).applyTo(composite);\r
206 \r
207         // In this dialog there are fields for:\r
208         //   Message:\r
209         //   Tag:\r
210         //   Description:\r
211         //   Time:\r
212         //   [x] Baseline\r
213 \r
214         GridDataFactory gd1 = GridDataFactory.fillDefaults().span(1, 1);\r
215         GridDataFactory gd2 = GridDataFactory.fillDefaults().minSize(300, SWT.DEFAULT).indent(10, 0).span(3, 1).grab(true, false);\r
216 \r
217         nameLabel = new Label(composite, 0);\r
218         nameLabel.setText("Message:");\r
219         gd1.applyTo(nameLabel);\r
220         nameText = new Text(composite, SWT.BORDER);\r
221         nameText.setText("My Milestone");\r
222         gd2.applyTo(nameText);\r
223 \r
224         tagLabel = new Label(composite, 0);\r
225         tagLabel.setText("Tag:");\r
226         gd1.applyTo(tagLabel);\r
227         tagText = new Text(composite, SWT.BORDER);\r
228         tagText.setText("");\r
229         gd2.applyTo(tagText);\r
230 \r
231         descLabel = new Label(composite, 0);\r
232         descLabel.setText("Description:");\r
233         gd1.applyTo(descLabel);\r
234         descText = new Text(composite, SWT.BORDER);\r
235         gd2.applyTo(descText);\r
236 \r
237         timeLabel = new Label(composite, 0);\r
238         timeLabel.setText("Time:");\r
239         gd1.applyTo(timeLabel);\r
240         timeText = new Text(composite, SWT.BORDER);\r
241         TimeFormat tf = new TimeFormat(data.initialTime, 3);\r
242         String time = tf.format( data.initialTime );\r
243         timeText.setText( time );\r
244         gd2.applyTo(timeText);\r
245         timeText.addModifyListener(new ModifyListener() {\r
246             @Override\r
247             public void modifyText(ModifyEvent e) {\r
248                 validateInput();\r
249             }\r
250         });\r
251 \r
252         baselineLabel = new Label(composite, 0);\r
253         baselineLabel.setText("Is baseline:");\r
254         gd1.applyTo(baselineLabel);\r
255         baselineButt = new Button(composite, SWT.CHECK);\r
256         gd2.applyTo(baselineButt);\r
257 \r
258         // Error decorations\r
259         Image image = FieldDecorationRegistry.getDefault()\r
260                 .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)\r
261                 .getImage();\r
262 \r
263         timeDecor = createDecoration(timeText, SWT.LEFT | SWT.CENTER, image);\r
264 \r
265         validateInput();\r
266 \r
267         return composite;\r
268     }\r
269 \r
270     protected ControlDecoration createDecoration(Control control, int position, Image image) {\r
271         ControlDecoration d = new ControlDecoration(control, position);\r
272         d.setMarginWidth(2);\r
273         d.setImage(image);\r
274         d.hide();\r
275         return d;\r
276     }\r
277 \r
278     protected void validateInput() {\r
279         boolean ok = true;\r
280 \r
281         // Read data from widgets.\r
282         data.time = timeText.getText();\r
283 \r
284         // Validate data.\r
285         Double parsedTime = TimeInputValidator.INSTANCE.parse( data.time );\r
286         if (parsedTime == null) {\r
287             ok = false;\r
288             data.parsedTime = 0.0;\r
289         } else {\r
290             data.parsedTime = parsedTime;\r
291         }\r
292         setDecoration(timeDecor, parsedTime == null ? "Invalid time value" : null);\r
293 \r
294         setFinishable(ok);\r
295     }\r
296 \r
297     private void setDecoration(ControlDecoration decor, String desc) {\r
298         if (decor == null)\r
299             return;\r
300         if (desc != null) {\r
301             decor.setDescriptionText(desc);\r
302             decor.show();\r
303         } else {\r
304             decor.hide();\r
305         }\r
306     }\r
307 \r
308     @Override\r
309     protected void okPressed() {\r
310         data.message = nameText.getText();\r
311         data.tag = tagText.getText();\r
312         data.description = descText.getText();\r
313         data.time = timeText.getText();\r
314         data.isBaseline = baselineButt.getSelection();\r
315         data.isMilestone = true;\r
316         super.okPressed();\r
317     }\r
318 \r
319     protected void setFinishable(boolean ok) {\r
320         Button b = getButton(OK);\r
321         if (b != null)\r
322             b.setEnabled(ok);\r
323     }\r
324 \r
325 }\r
326 \r
327 class EventData {\r
328     double initialTime;\r
329 \r
330     String message;\r
331     String tag;\r
332     String description;\r
333     String time;\r
334     double parsedTime;\r
335     boolean isBaseline;\r
336     boolean isMilestone;\r
337 }\r