Commit 48c5e513 authored by Ashmi Banerjee's avatar Ashmi Banerjee
Browse files

FTA Editor WIP


Signed-off-by: default avatarAshmi Banerjee <ashmi.banerjee@tum.de>
parents 55c25626 f1a8d629
...@@ -15,259 +15,75 @@ ...@@ -15,259 +15,75 @@
+--------------------------------------------------------------------------*/ +--------------------------------------------------------------------------*/
package org.fortiss.af3.mira.ui.editor; package org.fortiss.af3.mira.ui.editor;
import static org.eclipse.core.runtime.IStatus.ERROR;
import static org.eclipse.jface.dialogs.ErrorDialog.openError;
import static org.fortiss.af3.mira.ui.utils.HighlightUtils.createSourceViewer; import static org.fortiss.af3.mira.ui.utils.HighlightUtils.createSourceViewer;
import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineInputFactory; import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineInputFactory;
import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineLabelFactory; import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineLabelFactory;
import static org.fortiss.tooling.kernel.model.FortissToolingKernelPackage.Literals.INAMED_ELEMENT__NAME; import static org.fortiss.tooling.kernel.model.FortissToolingKernelPackage.Literals.INAMED_ELEMENT__NAME;
import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.bind; import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.bind;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickFirstInstanceOf;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf; import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.conqat.ide.commons.ui.jface.TreeContentProviderBase;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.fortiss.af3.mira.model.Requirement; import org.fortiss.af3.mira.model.Requirement;
import org.fortiss.af3.mira.model.functional.FunctionalFactory;
import org.fortiss.af3.mira.model.functional.Signal;
import org.fortiss.af3.mira.model.safety.FTASolutionRequirementSpecification; import org.fortiss.af3.mira.model.safety.FTASolutionRequirementSpecification;
import org.fortiss.tooling.base.model.element.IModelElementSpecification; import org.fortiss.tooling.base.model.element.IModelElementSpecification;
import org.fortiss.tooling.base.ui.ToolingBaseUIActivator;
import org.fortiss.tooling.base.ui.editor.StyledTextCellEditor;
import org.fortiss.tooling.base.ui.utils.TreeViewerUtils;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.service.IPersistencyService;
import org.fortiss.tooling.kernel.ui.service.IActionService;
import org.fortiss.tooling.kernel.ui.util.SelectionUtils;
/** /**
* *
* @author ashmi * @author ashmi
*/ */
public class FTASolutionRequirementEditor<T extends Requirement> extends AspectEditorBase<T> { public class FTASolutionRequirementEditor<T extends Requirement> extends AspectEditorBase<T> {
/** The edited solution specification. */
private FTASolutionRequirementSpecification spec;
/** Label width. */
public static final int PROPERTIES_LABEL_WIDTH = 150;
/** List of the registered source viewers. We store this in a field because.... */
protected List<SourceViewer> localRegisteredSourceViewers;
/** Default text displayed in the input signals table. */
private static final String CLICK_TO_ADD_A_NEW_SIGNAL = "Click to add a new signal";
/**
* The tree viewer displaying the signals table. Only used as a table, but we use trees
* because it does
* not cost anything.
*/
private TreeViewer viewer;
/** Top level element for the edited object. */
private ITopLevelElement top;
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
protected void createAspectSection() { protected void createAspectSection() {
localRegisteredSourceViewers = new ArrayList<SourceViewer>(); for(IModelElementSpecification spec : editedObject.getSpecifications()) {
EList<IModelElementSpecification> specs = editedObject.getSpecifications(); if(spec instanceof FTASolutionRequirementSpecification) {
spec = pickFirstInstanceOf(FTASolutionRequirementSpecification.class, specs); addFTADefinitionSection((FTASolutionRequirementSpecification)spec);
addFTAHeaderSection(spec); }
addSignalSection(spec); }// TODO Auto-generated method stub
} }
/** /**
* Definition of the Hazard section * Definition of the FTA section
*/ */
private void addFTAHeaderSection(FTASolutionRequirementSpecification spec) { private void addFTADefinitionSection(FTASolutionRequirementSpecification spec) {
Composite headerSection = Composite FTASection =
createNewSection("FTA Solution Requirement", createNewSection("FTA Solution", "This requirement defines FTA parameters:");
"This requirement defines FTA parameters:"); FTASection.setLayout(new GridLayout(2, false));
headerSection.setLayout(new GridLayout(2, false)); Label nameLabel = toolkit.createLabel(FTASection, "FTA Name ", SWT.READ_ONLY);
Label nameLabel = toolkit.createLabel(headerSection, "Name: ", SWT.READ_ONLY);
singleLineLabelFactory.applyTo(nameLabel); singleLineLabelFactory.applyTo(nameLabel);
SourceViewer inputName = createSourceViewer(form, headerSection, SWT.BORDER, analysis); SourceViewer inputName = createSourceViewer(form, FTASection, SWT.BORDER, analysis);
registeredSourceViewers.add(inputName); registeredSourceViewers.add(inputName);
singleLineInputFactory.applyTo(inputName.getControl()); singleLineInputFactory.applyTo(inputName.getControl());
bind(dbc, inputName.getTextWidget(), spec, INAMED_ELEMENT__NAME); bind(dbc, inputName.getTextWidget(), spec, INAMED_ELEMENT__NAME);
Label eventLabel = toolkit.createLabel(FTASection, "FTA Main Event Name ", SWT.READ_ONLY);
singleLineLabelFactory.applyTo(eventLabel);
SourceViewer inputEventName = createSourceViewer(form, FTASection, SWT.BORDER, analysis);
registeredSourceViewers.add(inputEventName);
singleLineInputFactory.applyTo(inputEventName.getControl());
bind(dbc, inputEventName.getTextWidget(), spec, INAMED_ELEMENT__NAME);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
protected List<IModelElementSpecification> getElementsToDelete() { protected List<IModelElementSpecification> getElementsToDelete() {
ArrayList<IModelElementSpecification> res = new ArrayList<>(); ArrayList<IModelElementSpecification> res = new ArrayList<IModelElementSpecification>();
res.addAll(pickInstanceOf(FTASolutionRequirementSpecification.class, res.addAll(pickInstanceOf(FTASolutionRequirementSpecification.class,
editedObject.getSpecifications())); editedObject.getSpecifications()));
return res; return res;
} }
/** Section for signal component. */
private Composite addSignalSection(FTASolutionRequirementSpecification ms) {
Composite ftaSection =
createNewSection("Table of minimum cut sets",
"This requirement defines the table of minimum cut sets ");
ftaSection.setLayout(new GridLayout(1, false));
viewer = new TreeViewer(ftaSection, SWT.BORDER | SWT.FULL_SELECTION);
Tree tree = viewer.getTree();
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).minSize(300, 300)
.applyTo(tree);
tree.setLinesVisible(true);
tree.setHeaderVisible(true);
TreeViewerUtils.allowTabing(viewer);
TreeViewerColumn nameColumn = new TreeViewerColumn(viewer, SWT.NONE);
TreeColumn trclmnMode = nameColumn.getColumn();
trclmnMode.setWidth(300);
trclmnMode.setText("Name");
nameColumn.setLabelProvider(new ColumnLabelProvider() {
/** {@inheritDoc} */
@Override
public String getText(Object element) {
if(element instanceof FakeChild) {
return "Click to add a cut set component";
}
return spec.getMinCutSet().get((Integer)element).getName();
}
});
nameColumn.setEditingSupport(createNameEditingSupport(viewer, nameColumn));
viewer.setContentProvider(new TreeContentProviderBase() {
@Override
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof List<?>) {
List<Object> range = new ArrayList<Object>();
range.add(new FakeChild());
range.addAll(IntStream.rangeClosed(0, ms.getMinCutSet().size() - 1).boxed()
.collect(Collectors.toList()));
return range.toArray();
}
return new Object[0];
}
});
viewer.getControl().addKeyListener(new ViewerKeyAdapter());
viewer.setInput(spec.getMinCutSet());
return ftaSection;
}
/** Fake child used to add new elements. */
private static class FakeChild {
// Nothing to implement: just a marker class
}
/**
* Checks if the name is empty or already exists among current signals, if so displays an error
* message and return true, otherwise returns false.
*/
private boolean emptyOrAlreadyExists(String name) {
if(name.equals("") || name.equals(CLICK_TO_ADD_A_NEW_SIGNAL)) {
Status status =
new Status(ERROR, ToolingBaseUIActivator.PLUGIN_ID, 0,
"Signal name is not valid.", null);
openError(Display.getCurrent().getActiveShell(), "Error", null, status);
return true;
}
List<String> signalNames =
spec.getMinCutSet().stream().map(c -> c.getName().toLowerCase())
.collect(Collectors.toList());
if(signalNames.contains(name.toLowerCase()) ||
name.toLowerCase().equals(CLICK_TO_ADD_A_NEW_SIGNAL)) {
Status status =
new Status(ERROR, ToolingBaseUIActivator.PLUGIN_ID, 0,
"A Signal with this name already exists.", null);
openError(Display.getCurrent().getActiveShell(), "Error", null, status);
return true;
}
return false;
}
/** {@link EditingSupport} for the name column. */
private EditingSupport createNameEditingSupport(TreeViewer viewer,
TreeViewerColumn funcCompColumn) {
top = IPersistencyService.getInstance().getTopLevelElementFor(getEditedObject());
return new EditingSupport(funcCompColumn.getViewer()) {
@Override
protected void setValue(Object element, Object value) {
if(element instanceof FakeChild) {
if(!emptyOrAlreadyExists((String)value)) {
top.runAsCommand(() -> {
Signal newSig = FunctionalFactory.eINSTANCE.createSignal();
newSig.setName((String)value);
spec.getMinCutSet().add(newSig);
viewer.refresh();
});
}
}
}
@Override
protected Object getValue(Object element) {
return element instanceof Signal ? ((Signal)element).getName() : "";
}
@Override
protected CellEditor getCellEditor(Object element) {
return new StyledTextCellEditor(getTextStyledTextActionHandler(),
(Composite)getViewer().getControl());
}
@Override
protected boolean canEdit(Object element) {
return true;
}
};
}
/** Key adapter to deal with copy/paste/delete/... done through the keyboard. */
public class ViewerKeyAdapter extends KeyAdapter {
/** Constructor. */
public ViewerKeyAdapter() {
}
/** {@inheritDoc} */
@Override
public void keyReleased(KeyEvent e) {
if(e.keyCode == SWT.DEL) {
Integer modeIdx =
SelectionUtils.checkAndPickFirst(viewer.getSelection(), Integer.class);
if(modeIdx != null) {
top.runAsCommand(() -> {
spec.getMinCutSet().remove(modeIdx.intValue());
});
viewer.refresh();
}
} else if((e.stateMask & SWT.CTRL) != 0 && e.keyCode == 0x7A) {
IActionService.getInstance().runGlobalUndoAction();
} else if((e.stateMask & SWT.CTRL) != 0 && e.keyCode == 0x79) {
IActionService.getInstance().runGlobalRedoAction();
}
}
}
} }
...@@ -203,7 +203,7 @@ public class AspectBindings { ...@@ -203,7 +203,7 @@ public class AspectBindings {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public String getLabel() { public String getLabel() {
return "FTA Solution definition"; return "FTA Solution";
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
......
...@@ -841,7 +841,12 @@ ...@@ -841,7 +841,12 @@
<eClassifiers xsi:type="ecore:EClass" name="FTASolutionRequirementSpecification" <eClassifiers xsi:type="ecore:EClass" name="FTASolutionRequirementSpecification"
eSuperTypes="platform:/resource/org.fortiss.tooling.base/model/base.ecore#//element/IModelElementSpecification #//INonFunctionalRequirement platform:/resource/org.fortiss.tooling.kernel/model/kernel.ecore#//INamedElement"> eSuperTypes="platform:/resource/org.fortiss.tooling.base/model/base.ecore#//element/IModelElementSpecification #//INonFunctionalRequirement platform:/resource/org.fortiss.tooling.kernel/model/kernel.ecore#//INamedElement">
<eStructuralFeatures xsi:type="ecore:EReference" name="minCutSet" upperBound="-1" <eStructuralFeatures xsi:type="ecore:EReference" name="minCutSet" upperBound="-1"
eType="#//functional/Signal" containment="true"/> eType="#//safety/MinCutSets" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="mainEvent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="MinCutSets">
<eStructuralFeatures xsi:type="ecore:EReference" name="cutSet" upperBound="-1"
eType="ecore:EClass platform:/resource/org.fortiss.tooling.base/model/base.ecore#//element/IModelElement"/>
</eClassifiers> </eClassifiers>
</eSubpackages> </eSubpackages>
</ecore:EPackage> </ecore:EPackage>
...@@ -431,6 +431,11 @@ ...@@ -431,6 +431,11 @@
</genClasses> </genClasses>
<genClasses ecoreClass="mira.ecore#//safety/FTASolutionRequirementSpecification"> <genClasses ecoreClass="mira.ecore#//safety/FTASolutionRequirementSpecification">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference mira.ecore#//safety/FTASolutionRequirementSpecification/minCutSet"/> <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference mira.ecore#//safety/FTASolutionRequirementSpecification/minCutSet"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute mira.ecore#//safety/FTASolutionRequirementSpecification/mainEvent"/>
</genClasses>
<genClasses ecoreClass="mira.ecore#//safety/MinCutSets">
<genFeatures notify="false" createChild="false" propertySortChoices="true"
ecoreFeature="ecore:EReference mira.ecore#//safety/MinCutSets/cutSet"/>
</genClasses> </genClasses>
</nestedGenPackages> </nestedGenPackages>
</genPackages> </genPackages>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment