Skip to content
Snippets Groups Projects
Commit 528fb978 authored by Simon Barner's avatar Simon Barner
Browse files

Enable editing of multi-valued EAttribute annotations

* Add new classes
  * MultiValueAnnotationTextEditingSupport, an editing support that
    allows for textual editing of multi-value annotation.
  * MultiValueAnnotationTextEditingDialog, a dialog to that allows to
    edit multiple values
* Adapt
  * EditingSupportFactory to instantiate
    MultiValueAnnotationTextEditingSupport instead of throwning an
    exception about an unsupported case
  * EStructuralFeatureValueProviderBase to set values using the new
    method setAnnotationValueFromString(Collection<String>, T)

Issue-Ref: 3578
Issue-Url: https://af3-developer.fortiss.org/issues/3578



Signed-off-by: default avatarSimon Barner <barner@fortiss.org>
parent c2125803
No related branches found
No related tags found
1 merge request!423267: Support for multivalued (non-EReference) annotations
AnnotationEditingSupportBase.java a5ecf54616b50f947d251f45cbb5789df5234170 GREEN
CheckBoxEditingSupport.java 1d8d9dd444f0e52767c65fd2711321438d3a9b29 GREEN
ComboBoxEditingSupport.java 6b6a23be327ebdea9bdaf007304bd3d7c14b2cef GREEN
EditingSupportFactory.java db05c9f4c1d48f9858827051b0e9e58214645c0a YELLOW
EditingSupportFactory.java e42347692ef23a8cb71532edadcf176ae49e992d YELLOW
ElementCommentEditingSupport.java 4be366924a040caf3f80e35b383e796e84aedcac GREEN
ElementEditingSupportBase.java a6360f99ee149276f0fbd299820ebd1c9731ea97 GREEN
ElementNameEditingSupport.java 0dcaecf4ba5f8ddefa3ccb7d6f4e4506f7f09b26 GREEN
......@@ -12,4 +12,6 @@ MultiValueAnnotationDialogBase.java 910a7e1203f84e462d25d4063264fbd19b5ae22e YEL
MultiValueAnnotationEditingSupportBase.java ac228c1a4dec5d7035729585c2dcb9799da6aba9 YELLOW
MultiValueAnnotationSelectionDialog.java d5639aee0d5b4220d5dae92df0d87062dfe17bd6 YELLOW
MultiValueAnnotationSelectionEditingSupport.java a4c3c3f9c3cc4f43f27c95f9ba676b4bef01e157 YELLOW
MultiValueAnnotationTextEditingDialog.java 8d8ee46724f52175233e74ec7f0a5bed4f7d3636 YELLOW
MultiValueAnnotationTextEditingSupport.java 38c780819396fc75d10fbb660832652d89d59378 YELLOW
TextEditingSupport.java e761ea393816f23ca41157f2a9a9a8d8ef30b858 GREEN
......@@ -117,8 +117,8 @@ public class EditingSupportFactory {
specification, eStructuralFeatureDescriptor);
}
throw new Exception(
"For feature multiplicity > 1, EStructuralValueProvider has been implemented for EReferences and EEnumns, only .");
return new MultiValueAnnotationTextEditingSupport<String>(viewer, clazz, specification,
eStructuralFeatureDescriptor);
}
/**
......
/*-------------------------------------------------------------------------+
| Copyright 2018 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.ui.annotation.editingsupport;
import static java.lang.Integer.compare;
import static java.lang.Math.min;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import java.util.Collection;
import java.util.OptionalInt;
import java.util.stream.IntStream;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SegmentEvent;
import org.eclipse.swt.events.SegmentListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Text;
/**
* Dialog to that allows to edit multiple values
*
* @author barner
*/
public class MultiValueAnnotationTextEditingDialog<T> extends MultiValueAnnotationDialogBase<T> {
/** The {@link Text} into which input is entered. */
private Text textInput;
/** {@link List} containing the current input. */
private List list;
/** {@link Button} to add the current value of {@link #textInput} to {@link #list}. */
private Button addButton;
/** {@link Button} to remove the currently selected item from {@link #list}. */
private Button removeButton;
/** {@link Button} to move up the currently selected item of {@link #list}. */
private Button upButton;
/** {@link Button} to move down the currently selected item of {@link #list}. */
private Button downButton;
/** Flag if dialog is currently set up in {@link #createDialogArea(Composite)}. */
private boolean isCreateDialogArea;
/** Underlying {@link EAttribute}. */
private EAttribute eAttribute;
/** The {@link Collection} of initial values. */
private Collection<T> initialValues;
/** Constructs a new {@link MultiValueAnnotationTextEditingDialog}. */
public MultiValueAnnotationTextEditingDialog(EAttribute eAttribute,
Collection<T> initialValues) {
super("Add", eAttribute.getLowerBound(), eAttribute.getUpperBound());
this.eAttribute = eAttribute;
this.initialValues = initialValues;
}
/** Returns the {@link EFactory} for the underlying {@link #eAttribute}. */
protected EFactory getEFactory() {
return eAttribute.getEType().getEPackage().getEFactoryInstance();
}
/** Refreshes the status of the dialog's UI elements. */
protected void refresh() {
if(isCreateDialogArea) {
return;
}
boolean isValidText = true;
try {
EFactory eFactory = getEFactory();
eFactory.createFromString(eAttribute.getEAttributeType(), textInput.getText());
} catch(Exception e) {
isValidText = false;
}
addButton.setEnabled(isValidText);
OptionalInt min = stream(list.getSelectionIndices()).reduce(Integer::min);
OptionalInt max = stream(list.getSelectionIndices()).reduce(Integer::max);
removeButton.setEnabled(min.isPresent());
upButton.setEnabled(min.isPresent() && min.getAsInt() > 0);
downButton.setEnabled(max.isPresent() && max.getAsInt() < list.getItemCount() - 1);
}
/** {@inheritDoc} */
@Override
protected Composite createDialogArea(Composite parent) {
isCreateDialogArea = true;
Composite area = (Composite)super.createDialogArea(parent);
area.setLayout(new GridLayout(2, false));
textInput = new Text(area, SWT.BORDER | SWT.LEFT);
GridData gd_Text = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
gd_Text.widthHint = 300;
gd_Text.minimumWidth = 300;
textInput.setLayoutData(gd_Text);
textInput.addSegmentListener(new SegmentListener() {
/** {@inheritDoc} */
@Override
public void getSegments(SegmentEvent event) {
refresh();
}
});
addButton = new Button(area, SWT.PUSH);
GridData gd_Buttons = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_Buttons.widthHint = 100;
gd_Buttons.minimumWidth = 100;
addButton.setLayoutData(gd_Buttons);
addButton.setText("Add");
addButton.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
list.add(textInput.getText());
textInput.setText("");
refresh();
}
});
list = new List(area, SWT.BORDER | SWT.LEFT | SWT.MULTI);
GridData gd_List = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 4);
gd_List.minimumWidth = 310;
gd_List.heightHint = 310;
list.setLayoutData(gd_List);
list.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
refresh();
}
});
for(Object value : initialValues) {
EFactory eFactory = getEFactory();
String valueLabel = eFactory.convertToString(eAttribute.getEAttributeType(), value);
list.add(valueLabel);
}
removeButton = new Button(area, SWT.PUSH);
removeButton.setLayoutData(gd_Buttons);
removeButton.setText("Remove");
removeButton.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
int[] selectionIndices = list.getSelectionIndices();
int index = -1;
if(selectionIndices.length == 1) {
index = selectionIndices[0];
}
for(int i : selectionIndices) {
list.remove(i);
}
list.setSelection(min(index, list.getItemCount()));
refresh();
}
});
upButton = new Button(area, SWT.PUSH);
upButton.setLayoutData(gd_Buttons);
upButton.setText("Up");
upButton.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
stream(list.getSelectionIndices()).sorted().forEach(i -> {
String swap = list.getItem(i - 1);
list.setItem(i - 1, list.getItem(i));
list.setItem(i, swap);
});
IntStream oldIndices = stream(list.getSelectionIndices());
list.deselectAll();
list.select(oldIndices.map(i -> i - 1).toArray());
refresh();
}
});
downButton = new Button(area, SWT.PUSH);
downButton.setLayoutData(gd_Buttons);
downButton.setText("Down");
downButton.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
stream(list.getSelectionIndices()).boxed().sorted((i1, i2) -> compare(i2, i1))
.forEach(i -> {
String swap = list.getItem(i + 1);
list.setItem(i + 1, list.getItem(i));
list.setItem(i, swap);
});
IntStream oldIndices = stream(list.getSelectionIndices());
list.deselectAll();
list.select(oldIndices.map(i -> i + 1).toArray());
refresh();
}
});
isCreateDialogArea = false;
refresh();
return area;
}
/** {@inheritDoc} */
@Override
public void create() {
super.create();
getShell().setDefaultButton(addButton);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
protected Collection<T> getElementsFromDialog() {
return (Collection<T>)asList(list.getItems());
}
}
/*-------------------------------------------------------------------------+
| Copyright 2018 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.ui.annotation.editingsupport;
import java.util.Collection;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.swt.widgets.Composite;
import org.fortiss.tooling.base.annotation.valueprovider.EStructuralFeatureDescriptor;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement;
/**
* {@link EditingSupport} for textual editing of multi-value annotations.
*
* @author barner
*/
public class MultiValueAnnotationTextEditingSupport<T>
extends MultiValueAnnotationEditingSupportBase<T> {
/** Constructs a new {@link MultiValueAnnotationTextEditingSupport}. */
public MultiValueAnnotationTextEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, IAnnotatedSpecification specification,
EStructuralFeatureDescriptor eStructuralFeatureDescriptor) {
super(viewer, clazz, specification, eStructuralFeatureDescriptor);
}
/** {@inheritDoc} */
@Override
public IMultiValueAnnotationDialog<T> createMultiEditingDialog(Composite parent,
IModelElement modelElement, Collection<T> values) {
EStructuralFeature eStructuralFeature =
eStructuralFeatureDescriptor.getEStructuralFeature(specification);
return new MultiValueAnnotationTextEditingDialog<T>((EAttribute)eStructuralFeature, values);
}
}
AnnotationInstSpec.java b4f2ed47a8984e751e04049de5bdb3cad2c0a933 GREEN
DerivedAnnotationValueProviderBase.java 15da44b7b92b7fd351aa48422ff5957a2ce34e35 GREEN
EStructuralFeatureDescriptor.java 2e14df3830d854bc1693382727b2033b23d0051c GREEN
EStructuralFeatureValueProviderBase.java 1077fa87bfb21dc3041a1695a4247b50b0409fd1 YELLOW
EStructuralFeatureValueProviderBase.java 7e3f41a7e5c22fda63058fb5cd1c8036df0e8a3f YELLOW
IAnnotationValueProvider.java d093cb522e7c484420331f0c77690bebe7e131b4 GREEN
ValueProviderBase.java e4e866840845346ec99a4304048f5327c4890996 GREEN
......@@ -15,9 +15,14 @@
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.annotation.valueprovider;
import static java.util.Collections.emptyList;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
......@@ -25,6 +30,7 @@ import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.fortiss.tooling.base.ToolingBaseActivator;
import org.fortiss.tooling.base.annotation.valueprovider.EStructuralFeatureDescriptor.EReferenceScope;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement;
......@@ -161,7 +167,39 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
}
} else {
throw new Exception(
"setAnnotationValueFromString() is only availabe for EAttributes. Use setAnnotationValue(U value, T specification) instead.");
"setAnnotationValueFromString(String, T) is only availabe for EAttributes. Use setAnnotationValue(U value, T specification) instead.");
}
}
/**
* Sets a value for a {@link IAnnotatedSpecification} from a {@code Collection<String>}
* representation of the input.
*/
private void setAnnotationValueFromString(Collection<String> collection, T specification)
throws Exception {
EStructuralFeature structuralFeature =
getEStructuralFeatureDescriptor().getEStructuralFeature(specification);
if(structuralFeature instanceof EAttribute) {
EFactory eFactory = getEFactory(structuralFeature);
EDataType eAttributeType = ((EAttribute)structuralFeature).getEAttributeType();
EList<Object> values = new BasicEList<>();
for(String s : collection) {
Object o = null;
try {
o = eFactory.createFromString(eAttributeType, s);
} catch(Exception e) {
error(ToolingBaseActivator.getDefault(), "Could not convert " +
(s != null ? s : "<null>") + " to datatype " + eAttributeType + ".", e);
}
if(o != null) {
values.add(o);
}
}
specification.eSet(structuralFeature, values);
} else {
throw new Exception(
"setAnnotationValueFromString(Collection<String>, T) is only availabe for EAttributes.");
}
}
......@@ -175,6 +213,8 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
@SuppressWarnings("unchecked")
@Override
public <U> void setAnnotationValue(U value, T specification) throws Exception {
final EStructuralFeature eStructuralFeature =
getEStructuralFeatureDescriptor().getEStructuralFeature(specification);
if(value instanceof String) {
// In case the input choice is presented in dynamically managed combo box (i.e., where
// new value choices can be entered by the user), the empty String indicates that the
......@@ -190,9 +230,18 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
}
setAnnotationValueFromString((String)value, specification);
} else if(value instanceof Collection<?>) {
Collection<?> collection = (Collection<?>)value;
if(collection.isEmpty()) {
specification.eSet(eStructuralFeature, emptyList());
} else {
if(collection.iterator().next() instanceof String) {
setAnnotationValueFromString((Collection<String>)value, specification);
} else {
specification.eSet(eStructuralFeature, value);
}
}
} else {
final EStructuralFeature eStructuralFeature =
getEStructuralFeatureDescriptor().getEStructuralFeature(specification);
if(value != null) {
specification.eSet(eStructuralFeature, value);
} else {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment