--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.charts.editor;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.core.expressions.IEvaluationContext;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.dialogs.IDialogSettings;\r
+import org.eclipse.jface.dialogs.IInputValidator;\r
+import org.eclipse.jface.fieldassist.ControlDecoration;\r
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.Simantics;\r
+import org.simantics.charts.Activator;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.VirtualGraphSupport;\r
+import org.simantics.event.ontology.EventResource;\r
+import org.simantics.event.ontology.EventViewResource;\r
+import org.simantics.event.util.EventWriteData;\r
+import org.simantics.event.view.handler.CorrectMilestoneLabelsAction;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.trend.impl.TrendNode;\r
+import org.simantics.utils.format.TimeFormat;\r
+\r
+/**\r
+ * This handler opens a dialog for new milestone.\r
+ * \r
+ * @author toni.kalajainen\r
+ */\r
+public class AddMilestoneHandler extends AbstractHandler {\r
+\r
+ @Override\r
+ public Object execute(ExecutionEvent event) throws ExecutionException {\r
+\r
+ TimeSeriesEditor tse = getTSE(event);\r
+ if (tse == null)\r
+ return null;\r
+ TrendNode tn = tse.trendNode;\r
+ if (tn == null)\r
+ return null;\r
+ final Resource experiment = tse.chartData.run;\r
+ if (experiment == null)\r
+ return null;\r
+\r
+ EventData data = new EventData();\r
+ data.initialTime = tn.lastMouseHoverTime;\r
+ AddMilestoneDialog d = new AddMilestoneDialog( tse.getSite().getShell(), data );\r
+ int ok = d.open();\r
+ if (ok != Dialog.OK)\r
+ return null;\r
+\r
+ Session session = Simantics.getSession();\r
+ VirtualGraph vg = session.getService(VirtualGraphSupport.class).getWorkspacePersistent("experiments");\r
+ session.async( new CreateManualEvent(vg, experiment, data) );\r
+\r
+ return null;\r
+ }\r
+\r
+ TimeSeriesEditor getTSE(ExecutionEvent event) {\r
+ Object eac = event.getApplicationContext();\r
+ if (eac == null || (eac instanceof IEvaluationContext == false)) return null;\r
+ IEvaluationContext ec = (IEvaluationContext) eac;\r
+ Object editor = ec.getVariable("activeEditor");\r
+ if (editor == null || (editor instanceof TimeSeriesEditor == false)) return null;\r
+ TimeSeriesEditor tse = (TimeSeriesEditor) editor;\r
+ return tse;\r
+ }\r
+\r
+ static class CreateManualEvent extends WriteRequest {\r
+\r
+ private final Resource experiment;\r
+ private final EventData eventData;\r
+\r
+ public CreateManualEvent(VirtualGraph vg, Resource experiment, EventData eventData) {\r
+ super(vg);\r
+ this.experiment = experiment;\r
+ this.eventData = eventData;\r
+ }\r
+\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ EventResource EVENT = EventResource.getInstance(graph);\r
+ EventViewResource EVENTVIEW = EventViewResource.getInstance(graph);\r
+ Resource eventlog = graph.getPossibleObject(experiment, EVENT.IsEventProducerOf);\r
+ if (eventlog == null) return;\r
+\r
+ EventWriteData data = new EventWriteData(graph, eventlog, getProvider());\r
+ data.prepareToWrite(graph);\r
+\r
+ Resource event = graph.newResource(); \r
+ graph.claim(event, L0.InstanceOf, EVENT.Event);\r
+ graph.claimLiteral(event, L0.HasName, L0.String, ""+data.targetPos, Bindings.STRING);\r
+ graph.claimLiteral(event, L0.HasLabel, L0.HasLabel_Inverse, L0.String, eventData.description, Bindings.STRING);\r
+ graph.claimLiteral(event, L0.HasDescription, L0.HasDescription_Inverse, L0.String, eventData.description, Bindings.STRING);\r
+ graph.claimLiteral(event, EVENT.HasTimestamp, EVENT.HasTimestamp_Inverse, EVENT.TimeStamp, eventData.parsedTime, Bindings.DOUBLE);\r
+ if (eventData.isMilestone)\r
+ graph.claim(event, EVENT.Milestone, event);\r
+ if (eventData.isBaseline) {\r
+ graph.deny(eventlog, EVENT.EventLog_HasBaselineEvent);\r
+ graph.claim(eventlog, EVENT.EventLog_HasBaselineEvent, event);\r
+ }\r
+ graph.claim(event, EVENT.Event_type, null, EVENTVIEW.ManualEventType);\r
+ graph.claimLiteral(event, EVENT.Event_message, EVENT.Event_message_Inverse, L0.String, eventData.message, Bindings.STRING);\r
+ graph.claimLiteral(event, EVENT.Event_tag, EVENT.Event_tag_Inverse, L0.String, eventData.tag, Bindings.STRING);\r
+ graph.claim(event, EVENT.NoReturn, EVENT.NoReturn, event);\r
+ graph.claim(data.targetSlice, L0.ConsistsOf, L0.PartOf, event);\r
+\r
+ data.written();\r
+ data.commit(graph);\r
+\r
+ graph.syncRequest( new CorrectMilestoneLabelsAction(eventlog, getProvider()) );\r
+ }\r
+ }\r
+\r
+}\r
+\r
+\r
+class AddMilestoneDialog extends Dialog {\r
+\r
+ private static final String DIALOG = "AddMilestoneDialog"; //$NON-NLS-1$\r
+\r
+ IInputValidator timeValidator = new IInputValidator() {\r
+ @Override\r
+ public String isValid(String text) {\r
+ if (text.trim().isEmpty())\r
+ return null;\r
+ return TimeInputValidator.INSTANCE.isValid(text);\r
+ }\r
+ }; \r
+\r
+ Label nameLabel, descLabel, tagLabel, timeLabel, baselineLabel;\r
+ Text nameText, descText, tagText, timeText;\r
+ Button baselineButt;\r
+ ControlDecoration timeDecor;\r
+\r
+ EventData data;\r
+\r
+ private IDialogSettings dialogBoundsSettings;\r
+\r
+ protected AddMilestoneDialog(Shell parentShell, EventData data) {\r
+ super(parentShell);\r
+ this.data = data;\r
+\r
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();\r
+ dialogBoundsSettings = settings.getSection(DIALOG);\r
+ if (dialogBoundsSettings == null)\r
+ dialogBoundsSettings = settings.addNewSection(DIALOG);\r
+ }\r
+\r
+ @Override\r
+ protected IDialogSettings getDialogBoundsSettings() {\r
+ return dialogBoundsSettings;\r
+ }\r
+\r
+ @Override\r
+ protected int getShellStyle() {\r
+ return SWT.RESIZE | SWT.MODELESS | SWT.TITLE | SWT.CLOSE | SWT.BORDER;\r
+ }\r
+\r
+ @Override\r
+ protected void configureShell(Shell newShell) {\r
+ super.configureShell(newShell);\r
+ newShell.setText("Add new milestone");\r
+ }\r
+\r
+ @Override\r
+ protected Point getInitialSize() {\r
+ return super.getInitialSize();\r
+ }\r
+\r
+ @Override\r
+ protected Control createDialogArea(Composite parent) \r
+ {\r
+ Composite composite = (Composite) super.createDialogArea(parent);\r
+ GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(4).applyTo(composite);\r
+\r
+ // In this dialog there are fields for:\r
+ // Message:\r
+ // Tag:\r
+ // Description:\r
+ // Time:\r
+ // [x] Baseline\r
+\r
+ GridDataFactory gd1 = GridDataFactory.fillDefaults().span(1, 1);\r
+ GridDataFactory gd2 = GridDataFactory.fillDefaults().minSize(300, SWT.DEFAULT).indent(10, 0).span(3, 1).grab(true, false);\r
+\r
+ nameLabel = new Label(composite, 0);\r
+ nameLabel.setText("Message:");\r
+ gd1.applyTo(nameLabel);\r
+ nameText = new Text(composite, SWT.BORDER);\r
+ nameText.setText("My Milestone");\r
+ gd2.applyTo(nameText);\r
+\r
+ tagLabel = new Label(composite, 0);\r
+ tagLabel.setText("Tag:");\r
+ gd1.applyTo(tagLabel);\r
+ tagText = new Text(composite, SWT.BORDER);\r
+ tagText.setText("");\r
+ gd2.applyTo(tagText);\r
+\r
+ descLabel = new Label(composite, 0);\r
+ descLabel.setText("Description:");\r
+ gd1.applyTo(descLabel);\r
+ descText = new Text(composite, SWT.BORDER);\r
+ gd2.applyTo(descText);\r
+\r
+ timeLabel = new Label(composite, 0);\r
+ timeLabel.setText("Time:");\r
+ gd1.applyTo(timeLabel);\r
+ timeText = new Text(composite, SWT.BORDER);\r
+ TimeFormat tf = new TimeFormat(data.initialTime, 3);\r
+ String time = tf.format( data.initialTime );\r
+ timeText.setText( time );\r
+ gd2.applyTo(timeText);\r
+ timeText.addModifyListener(new ModifyListener() {\r
+ @Override\r
+ public void modifyText(ModifyEvent e) {\r
+ validateInput();\r
+ }\r
+ });\r
+\r
+ baselineLabel = new Label(composite, 0);\r
+ baselineLabel.setText("Is baseline:");\r
+ gd1.applyTo(baselineLabel);\r
+ baselineButt = new Button(composite, SWT.CHECK);\r
+ gd2.applyTo(baselineButt);\r
+\r
+ // Error decorations\r
+ Image image = FieldDecorationRegistry.getDefault()\r
+ .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)\r
+ .getImage();\r
+\r
+ timeDecor = createDecoration(timeText, SWT.LEFT | SWT.CENTER, image);\r
+\r
+ validateInput();\r
+\r
+ return composite;\r
+ }\r
+\r
+ protected ControlDecoration createDecoration(Control control, int position, Image image) {\r
+ ControlDecoration d = new ControlDecoration(control, position);\r
+ d.setMarginWidth(2);\r
+ d.setImage(image);\r
+ d.hide();\r
+ return d;\r
+ }\r
+\r
+ protected void validateInput() {\r
+ boolean ok = true;\r
+\r
+ // Read data from widgets.\r
+ data.time = timeText.getText();\r
+\r
+ // Validate data.\r
+ Double parsedTime = TimeInputValidator.INSTANCE.parse( data.time );\r
+ if (parsedTime == null) {\r
+ ok = false;\r
+ data.parsedTime = 0.0;\r
+ } else {\r
+ data.parsedTime = parsedTime;\r
+ }\r
+ setDecoration(timeDecor, parsedTime == null ? "Invalid time value" : null);\r
+\r
+ setFinishable(ok);\r
+ }\r
+\r
+ private void setDecoration(ControlDecoration decor, String desc) {\r
+ if (decor == null)\r
+ return;\r
+ if (desc != null) {\r
+ decor.setDescriptionText(desc);\r
+ decor.show();\r
+ } else {\r
+ decor.hide();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected void okPressed() {\r
+ data.message = nameText.getText();\r
+ data.tag = tagText.getText();\r
+ data.description = descText.getText();\r
+ data.time = timeText.getText();\r
+ data.isBaseline = baselineButt.getSelection();\r
+ data.isMilestone = true;\r
+ super.okPressed();\r
+ }\r
+\r
+ protected void setFinishable(boolean ok) {\r
+ Button b = getButton(OK);\r
+ if (b != null)\r
+ b.setEnabled(ok);\r
+ }\r
+\r
+}\r
+\r
+class EventData {\r
+ double initialTime;\r
+\r
+ String message;\r
+ String tag;\r
+ String description;\r
+ String time;\r
+ double parsedTime;\r
+ boolean isBaseline;\r
+ boolean isMilestone;\r
+}\r