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

- Polish instantiation of IAnnotationProviders

  - Get factory from EStructuralFeature types
  - Get default values from meta-model
  - Remove EStructuralFeatureDescriptor
  - Enable automatic construction of a EStructuralFeatureValueProviderBase for all features of a given EClass (instance key = field name)
- Unify creation of editing support
  - Merge Enum support into EStructuralFeatureValueProviderBase
  - Enable management of input selectable from ComboBox also in the multi-instance case
refs 1841
parent 70d6cc77
No related branches found
No related tags found
No related merge requests found
Showing
with 234 additions and 305 deletions
......@@ -191,9 +191,11 @@ public final class AnnotationEntry {
/**
* Creates the {@link EditingSupport} element for the {@link IAnnotatedSpecification} of type
* {@code clazz} (for use in the {@link GenericAnnotationView} .
*
* @throws Exception
*/
public EditingSupport createSpecificationEditElement(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) {
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) throws Exception {
for(IAnnotatedSpecification s : specificationsList) {
if(clazz.isInstance(s)) {
return providerSpecMapping.get(clazz).createEditingSupport(viewer, clazz,
......
......@@ -18,7 +18,6 @@ $Id$
package org.fortiss.tooling.base.ui.annotation.valueprovider;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
......@@ -40,9 +39,8 @@ public abstract class DerivedAnnotationValueProviderBase<T extends IDerivedAnnot
* Constructs a {@link IAnnotationValueProvider} for derived annotations (i.e., based on
* {@link IDerivedAnnotation}).
*/
public DerivedAnnotationValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory) {
super(annotatedSpecificationEClass, annotationFactory);
public DerivedAnnotationValueProviderBase(EClass annotatedSpecificationEClass) {
super(annotatedSpecificationEClass);
}
/** {@inheritDoc} */
......
......@@ -74,9 +74,8 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno
* {@link EStructuralFeature}.
*/
public DynamicInstanceAnnotationValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory, EStructuralFeature structuralFeature,
EFactory attributeFactory, EDataType valueDataType, EFactory valueFactory) {
super(annotatedSpecificationEClass, annotationFactory, structuralFeature, attributeFactory);
EStructuralFeature structuralFeature, EDataType valueDataType, EFactory valueFactory) {
super(annotatedSpecificationEClass, structuralFeature);
this.valueDataType = valueDataType;
this.valueFactory = valueFactory;
}
......
/*--------------------------------------------------------------------------+
$Id$
| |
| Copyright 2014 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.valueprovider;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EStructuralFeature;
/**
* Descriptor for a single {@link EStructuralFeature} (used in
* {@link EStructuralFeatureValueProviderBase} to support multiple {@link EStructuralFeature}s
* contained in a single {@link EClass}.
*/
public class EStructuralFeatureDescriptor {
/** Reference to {@link EStructuralFeature}. */
private EStructuralFeature structuralFeature;
/** {@link EFactory} used to initialize {@link EStructuralFeature}. */
EFactory structuralFeatureFactory;
/** Default value used to initialize {@link EStructuralFeature}. */
String structuralFeatureDefaultValue;
/** Generates a descriptor for a single {@link EStructuralFeature}. */
public EStructuralFeatureDescriptor(EStructuralFeature structuralFeature,
EFactory structuralFeatureFactory, String structuralFeatureDefaultValue) {
this.structuralFeature = structuralFeature;
this.structuralFeatureFactory = structuralFeatureFactory;
this.structuralFeatureDefaultValue = structuralFeatureDefaultValue;
}
/** Returns structuralFeature. */
public EStructuralFeature getStructuralFeature() {
return structuralFeature;
}
/** Returns structuralFeatureFactory. */
public EFactory getStructuralFeatureFactory() {
return structuralFeatureFactory;
}
/** Returns structuralFeatureDefaultValue. */
public String getStructuralFeatureDefaultValue() {
return structuralFeatureDefaultValue;
}
}
......@@ -17,18 +17,27 @@ $Id$
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.ui.annotation.valueprovider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.annotation.editingsupport.ComboBoxEditingSupport;
/**
* Base class for {@link IAnnotationValueProvider}s that manages {@link EStructuralFeature}s
......@@ -43,17 +52,11 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
extends ValueProviderBase<T> {
/**
* Default key used in case this {@link IAnnotationValueProvider} is used to manage a single
* {@link EStructuralFeature}, only.
*/
final static String DEFAULT_KEY = null;
/**
* Map: Instance key -> {@link EStructuralFeatureDescriptor}s of the
* {@link IAnnotatedSpecification} managed by
* Map: Instance key -> {@link EStructuralFeature}s of the {@link IAnnotatedSpecification}
* managed by
* this {@link IAnnotationValueProvider}.
*/
final protected Map<String, EStructuralFeatureDescriptor> structuralFeatureDescriptorMap;
final protected Map<String, EStructuralFeature> structuralFeatureMap;
/**
* Flag if multiple {@link EStructuralFeature}s are managed by this
......@@ -63,65 +66,89 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented by a single {@link EStructuralFeature}, and that uses the
* default constructor to construct a new value for the structural feature.
* whose storage is implemented by a single {@link EStructuralFeature}.
*/
public EStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory, EStructuralFeature structuralFeature,
EFactory structuralFeatureFactory) {
this(annotatedSpecificationEClass, annotationFactory, structuralFeature,
structuralFeatureFactory, null);
EStructuralFeature structuralFeature) {
super(annotatedSpecificationEClass);
structuralFeatureMap = new HashMap<String, EStructuralFeature>();
structuralFeatureMap.put(DEFAULT_KEY, structuralFeature);
handlesMultipleEstructuralFeatures = false;
}
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented by a single {@link EStructuralFeature}.
* whose storage is implemented by a number of {@link EStructuralFeature}s contained in a single
* {@link EClass}. The mapping of of instance keys to the corresponding
* {@link EStructuralFeature}s is explicitly provided in a {@link Map}.
*/
public EStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory, EStructuralFeature structuralFeature,
EFactory structuralFeatureFactory, final String structuralFeatureDefaultValue) {
Map<String, EStructuralFeature> structuralFeatureMap) {
super(annotatedSpecificationEClass, annotationFactory);
super(annotatedSpecificationEClass);
structuralFeatureDescriptorMap = new HashMap<String, EStructuralFeatureDescriptor>();
structuralFeatureDescriptorMap.put(DEFAULT_KEY, new EStructuralFeatureDescriptor(
structuralFeature, structuralFeatureFactory, structuralFeatureDefaultValue));
this.structuralFeatureMap = structuralFeatureMap;
handlesMultipleEstructuralFeatures = false;
handlesMultipleEstructuralFeatures = true;
}
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented by a number of {@link EStructuralFeature}s contained in a single
* EClass, and that uses the default constructor to construct a new value for the structural
* features.
* whose storage is implemented all {@link EStructuralFeature}s defined locally in a single
* {@link EClass} (i.e., not considering inherited attributes). The instance keys, and the
* mapping to the corresponding {@link EStructuralFeature}s are automatically derived from the
* underlying {@link EClass} (instance keys = field names of {@link EStructuralFeature}).
*/
public EStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass) {
this(annotatedSpecificationEClass, false);
}
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented all {@link EStructuralFeature}s defined locally in a single
* {@link EClass} (i.e., not considering inherited attributes). The instance keys, and the
* mapping to the corresponding {@link EStructuralFeature}s are automatically derived from the
* underlying {@link EClass} (instance keys = field names of {@link EStructuralFeature}).
*/
public EStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory,
Map<String, EStructuralFeatureDescriptor> structuralFeatureDescriptorMap) {
boolean inheritedFeatures) {
super(annotatedSpecificationEClass, annotationFactory);
super(annotatedSpecificationEClass);
this.structuralFeatureDescriptorMap = structuralFeatureDescriptorMap;
structuralFeatureMap = new HashMap<String, EStructuralFeature>();
for(EStructuralFeature structuralFeature : (inheritedFeatures
? annotatedSpecificationEClass.getEAllStructuralFeatures()
: annotatedSpecificationEClass.getEStructuralFeatures())) {
structuralFeatureMap.put(structuralFeature.getName(), structuralFeature);
}
handlesMultipleEstructuralFeatures = true;
}
/**
* Returns the {@link EStructuralFeatureDescriptor} for a given {@code instanceKey}, or throws
* Returns the {@link EStructuralFeature} for a given {@code instanceKey}, or throws
* an exception, if the key is unknown.
*
*/
protected EStructuralFeatureDescriptor getEStructuralFeatureDescriptor(String instanceKey)
throws Exception {
EStructuralFeatureDescriptor fd = structuralFeatureDescriptorMap.get(instanceKey);
if(fd == null) {
protected EStructuralFeature getEStructuralFeature(String instanceKey) throws Exception {
EStructuralFeature structuralFeature = structuralFeatureMap.get(instanceKey);
if(structuralFeature == null) {
throw new Exception("Instance key " + instanceKey +
" is unknown for annotation provider " +
annotatedSpecificationEClass.getInstanceClassName() + ".");
}
return fd;
return structuralFeature;
}
/** Returns the {@link EFactory} for the given {@link EStructuralFeature}. */
private EFactory getEFactory(EStructuralFeature structuralFeature) {
return structuralFeature.getEType().getEPackage().getEFactoryInstance();
}
/**
......@@ -132,12 +159,11 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
setAnnotationValueFromString(String value, T specification, String instanceKey)
throws Exception {
EStructuralFeatureDescriptor fd = getEStructuralFeatureDescriptor(instanceKey);
EStructuralFeature structuralFeature = getEStructuralFeature(instanceKey);
specification.eSet(
fd.getStructuralFeature(),
fd.getStructuralFeatureFactory().createFromString(
((EAttribute)fd.getStructuralFeature()).getEAttributeType(), value));
structuralFeature,
getEFactory(structuralFeature).createFromString(
((EAttribute)structuralFeature).getEAttributeType(), value));
}
/** {@inheritDoc} */
......@@ -152,7 +178,9 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
// In case the last occurrence of a value choice has been removed, it will be no longer
// be offered in the combo box.
if(((String)value).isEmpty()) {
String rval = getAnnotationValueAndUpdateInputChoice((String)value, specification);
String rval =
getAnnotationValueAndUpdateInputChoice((String)value, specification,
instanceKey);
if(rval != null) {
value = (U)rval;
}
......@@ -160,8 +188,7 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
setAnnotationValueFromString((String)value, specification, instanceKey);
} else {
specification.eSet(getEStructuralFeatureDescriptor(instanceKey).getStructuralFeature(),
value);
specification.eSet(getEStructuralFeature(instanceKey), value);
}
}
......@@ -177,14 +204,13 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
throws Exception {
// See comment in setAnnotationValue(U value, T specification)
if((value == null || value.isEmpty())) {
String rval = getAnnotationValueAndUpdateInputChoice(value, specification);
String rval = getAnnotationValueAndUpdateInputChoice(value, specification, instanceKey);
if(rval != null) {
value = rval;
}
}
EStructuralFeature structuralFeature =
getEStructuralFeatureDescriptor(instanceKey).getStructuralFeature();
EStructuralFeature structuralFeature = getEStructuralFeature(instanceKey);
if(structuralFeature instanceof EAttribute) {
setAnnotationValueFromString(value, specification, instanceKey);
......@@ -207,8 +233,7 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
@SuppressWarnings("unchecked")
@Override
public <U> U getAnnotationValue(T specification, String instanceKey) throws Exception {
return (U)specification.eGet(getEStructuralFeatureDescriptor(instanceKey)
.getStructuralFeature());
return (U)specification.eGet(getEStructuralFeature(instanceKey));
}
/** {@inheritDoc} */
......@@ -217,54 +242,68 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
return getAnnotationValue(specification, DEFAULT_KEY);
}
/** {@inheritDoc} */
@Override
public EditingSupport createEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) throws Exception {
EStructuralFeature structuralFeature = getEStructuralFeature(instanceKey);
if(structuralFeature.getUpperBound() > 1 ||
structuralFeature.getUpperBound() == ETypedElement.UNBOUNDED_MULTIPLICITY) {
throw new Exception(
"EStructuralValueProvider has not been implemented for attribute multiplicity > 1.");
}
EClassifier eType = null;
try {
eType = structuralFeature.getEType();
} catch(Exception e) {
// Ignore
}
if(eType instanceof EEnum) {
List<String> enumValues = new ArrayList<String>();
for(EEnumLiteral e : ((EEnum)eType).getELiterals()) {
enumValues.add(e.getName());
}
return new ComboBoxEditingSupport(viewer, clazz, enumValues, false);
}
return super.createEditingSupport(viewer, clazz, instanceKey);
}
/**
* Creates a new instance of the {@link EStructuralFeature} (use to populate newly created
* annotation instances created in
* {@link #getAnnotatedSpecificationForModelElement(IModelElement)}.
*/
protected Object createStructuralFeatureInstance(String instanceKey) throws Exception {
EStructuralFeatureDescriptor fd = getEStructuralFeatureDescriptor(instanceKey);
EStructuralFeature structuralFeature = getEStructuralFeature(instanceKey);
if(fd.getStructuralFeature() instanceof EAttribute) {
EFactory factory = getEFactory(structuralFeature);
if(structuralFeature instanceof EAttribute) {
EDataType attributeEDataType =
((EAttribute)fd.getStructuralFeature()).getEAttributeType();
EDataType attributeEDataType = ((EAttribute)structuralFeature).getEAttributeType();
if(fd.getStructuralFeatureDefaultValue() != null) {
if(structuralFeature.getDefaultValueLiteral() != null) {
// Use default value if it has been specified
return fd.structuralFeatureFactory.createFromString(attributeEDataType,
fd.getStructuralFeatureDefaultValue());
}
// Return data types default value, if it is non-null.
Object rval = attributeEDataType.getDefaultValue();
if(rval != null) {
return rval;
}
try {
// Try to construct attribute from empty string
rval = fd.getStructuralFeatureFactory().createFromString(attributeEDataType, "");
} catch(NumberFormatException e) {
// Last try: initialize numbers with 0 (throws NumberFormatException if not
// successful).
rval = fd.getStructuralFeatureFactory().createFromString(attributeEDataType, "0");
return factory.createFromString(attributeEDataType,
structuralFeature.getDefaultValueLiteral());
}
return rval;
} else if(fd.getStructuralFeature() instanceof EReference) {
EReference reference = (EReference)fd.getStructuralFeature();
// Return data types default value
return attributeEDataType.getDefaultValue();
} else if(structuralFeature instanceof EReference) {
EReference reference = (EReference)structuralFeature;
if(reference.isContainment()) {
// EClasses attached to contained EReferences are created lazily by the
// corresponding generated code on the first access (i.e., also during get / "read")
return null;
}
return fd.getStructuralFeatureFactory().create(reference.getEReferenceType());
return factory.create(reference.getEReferenceType());
} else {
throw new Exception(
"createStructuralFeatureInstance() is not supported / has not been implemented the annotation type " +
fd.getStructuralFeature().getName() + ".");
structuralFeature.getName() + ".");
}
}
......@@ -276,8 +315,7 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
// Create and set structural feature implementing the annotation
Object structuralFeatureVal = createStructuralFeatureInstance(instanceKey);
if(structuralFeatureVal != null) {
specification.eSet(getEStructuralFeatureDescriptor(instanceKey).getStructuralFeature(),
structuralFeatureVal);
specification.eSet(getEStructuralFeature(instanceKey), structuralFeatureVal);
}
}
......@@ -285,7 +323,7 @@ public abstract class EStructuralFeatureValueProviderBase<T extends IAnnotatedSp
@Override
public Collection<String> getInstanceKeys(T specification) {
if(handlesMultipleEstructuralFeatures) {
return structuralFeatureDescriptorMap.keySet();
return structuralFeatureMap.keySet();
}
return super.getInstanceKeys(specification);
}
......
......@@ -138,9 +138,13 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext
* {@link EditingSupport}. For annotations whose {@link IAnnotationValueProvider}s support
* multiple instances, an {@code instanceKey} to identify the corresponding instance of the
* {@link IAnnotatedSpecification} needs to be provided.
*
* @throws Exception
* If the editing support could not be created for the particular
* {@link IAnnotatedSpecification}.
*/
public EditingSupport createEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, String instanceKey);
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) throws Exception;
/**
* Factory method that creates a new {@link IAnnotatedSpecification} specialization of type T to
......
/*--------------------------------------------------------------------------+
$Id$
| |
| Copyright 2014 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.valueprovider;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.ui.annotation.editingsupport.ComboBoxEditingSupport;
/**
* Base class for {@link IAnnotationValueProvider}s that manages a single enumeration contained in a
* {@link IAnnotatedSpecification}. The provider will provide a {@link ComboBoxEditingSupport} that
* is initialized to the enumeration value names specified in the respective ECore model
* containing the enumeration type.
*
* @author barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating RED Hash:
*/
public abstract class SingleEnumAttributeValueProviderBase<T extends IAnnotatedSpecification>
extends EStructuralFeatureValueProviderBase<T> {
/** Data type of the enumeration managed by this {@link IAnnotationValueProvider} */
private EEnum eEnum;
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* that that manages a single enumeration attribute contained in a
* {@link IAnnotatedSpecification}. The enumeration attribute is initialized to its default
* value.
*/
public SingleEnumAttributeValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory, EAttribute attribute, EEnum eEnum, EFactory attributeFactory) {
this(annotatedSpecificationEClass, annotationFactory, attribute, eEnum, attributeFactory,
null);
}
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* that that manages a single enumeration attribute contained in a
* {@link IAnnotatedSpecification}. The constructor assumes that the
* {@code attributeDefaultValue} matches of the enumeration names.
*/
public SingleEnumAttributeValueProviderBase(EClass annotatedSpecificationEClass,
EFactory annotationFactory, EAttribute attribute, EEnum eEnum,
EFactory attributeFactory, final String attributeDefaultValue) {
super(annotatedSpecificationEClass, annotationFactory, attribute, attributeFactory,
attributeDefaultValue);
this.eEnum = eEnum;
}
/** {@inheritDoc} */
@Override
public EditingSupport createEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) {
List<String> enumValues = new ArrayList<String>();
for(EEnumLiteral e : eEnum.getELiterals()) {
enumValues.add(e.getName());
}
return new ComboBoxEditingSupport(viewer, clazz, enumValues, false);
}
}
......@@ -19,14 +19,16 @@ package org.fortiss.tooling.base.ui.annotation.valueprovider;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
......@@ -50,39 +52,49 @@ import org.fortiss.tooling.kernel.utils.EcoreUtils;
public abstract class ValueProviderBase<T extends IAnnotatedSpecification> implements
IAnnotationValueProvider<T> {
/**
* Default key used in case this {@link IAnnotationValueProvider} is used to manage a single
* instance key only.
*/
protected final static String DEFAULT_KEY = null;
/**
* {@link EClass} of {@link IAnnotatedSpecification} that contains the respective structural
* feature and that is managed by this {@link IAnnotationValueProvider}.
*/
protected final EClass annotatedSpecificationEClass;
/**
* {@link EFactory} of ECore model that contains {@link IAnnotatedSpecification} identified by
* {@code annotatedSpecificationEClass} (used to create new instances of the annotation).
*/
protected final EFactory annotationFactory;
/**
* Fixed input choice to be offered in a combo box. The semantics of this field is as follows:
* Map: instanceKey -> Fixed input choice to be offered in a combo box. The semantics of the map
* value is as follows:
* <ul>
* <li> {@code fixedInputChoice == null} -> do not use fixed values, provide text input cell.</li>
* <li> {@code !fixedInputChoice.isEmpty()} -> provide a fixed set of choices in an input box.
* For enum types, see {@link SingleEnumAttributeValueProviderBase}</li>
* <li> {@code fixedInputChoice.isEmpty()} -> dynamically manage the set of provided values, i.e.
* the combo box is editable and enables the user to add new values and remove existing choices
* (by removing all instances of them).</li>
* <li> {@code fixedInputChoice[key] == null} -> do not use fixed values, provide text input
* cell.</li>
* <li> {@code !fixedInputChoice[key].isEmpty()} -> provide a fixed set of choices in an input
* box.
* <li> {@code fixedInputChoice[key].isEmpty()} -> dynamically manage the set of provided values,
* i.e. the combo box is editable and enables the user to add new values and remove existing
* choices (by removing all instances of them).</li>
* <li>For enum types, the set of inputs is automatically initialized from the underlying
* {@link EEnum} type definition.</li>
*/
private List<String> fixedInputChoice;
private Map<String, List<String>> fixedInputChoiceMap;
/** Current input choice, computed according to the initialization of {@link #fixedInputChoice}. */
private Collection<String> currentInputChoice;
/**
* Map: instanceKey -> Current input choice, computed according to the initialization of
* {@link #fixedInputChoiceMap}.
*/
private Map<String, Collection<String>> currentInputChoiceMap;
/**
* Constructs a new {@link IAnnotationValueProvider} for an annotation specified in a given
* {@link EClass}, and constructed using a given {@link EFactory}.
* {@link EClass}.
*/
public ValueProviderBase(EClass annotatedSpecificationEClass, EFactory annotationFactory) {
public ValueProviderBase(EClass annotatedSpecificationEClass) {
this.annotatedSpecificationEClass = annotatedSpecificationEClass;
this.annotationFactory = annotationFactory;
fixedInputChoiceMap = new HashMap<String, List<String>>();
currentInputChoiceMap = new HashMap<String, Collection<String>>();
}
/** {@inheritDoc} */
......@@ -128,20 +140,24 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
specification.getClass());
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*
* @throws Exception
*/
@Override
public EditingSupport createEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) {
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) throws Exception {
try {
initializeInputChoice(viewer, clazz);
initializeInputChoice(viewer, clazz, instanceKey);
} catch(Exception e) {
// Use standard text editor as fallback
currentInputChoice = null;
currentInputChoiceMap = null;
}
// Input is not restricted -> free editing in text cell
if(currentInputChoice == null) {
if(currentInputChoiceMap.get(instanceKey) == null) {
if(instanceKey == null) {
return new TextEditingSupport(viewer, clazz);
}
......@@ -153,8 +169,8 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
// Input is restricted to concrete set of values
// (use SingleEnumAttributeValueProviderBase for Enum types!)
return new ComboBoxEditingSupport(viewer, clazz, currentInputChoice,
fixedInputChoice.isEmpty());
return new ComboBoxEditingSupport(viewer, clazz, currentInputChoiceMap.get(instanceKey),
fixedInputChoiceMap.get(instanceKey).isEmpty());
}
/**
......@@ -162,7 +178,7 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
* {@link #createEditingSupport(ColumnViewer, Class, String)}).
*/
public EditingSupport createEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz) {
Class<? extends IAnnotatedSpecification> clazz) throws Exception {
return createEditingSupport(viewer, clazz, null);
}
......@@ -210,7 +226,9 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
}
// Create annotation
T specification = (T)annotationFactory.create(annotatedSpecificationEClass);
T specification =
(T)annotatedSpecificationEClass.getEPackage().getEFactoryInstance()
.create(annotatedSpecificationEClass);
if(getInstanceKeys(specification).isEmpty()) {
decorateAnnotationSpecification(specification);
} else {
......@@ -252,26 +270,35 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
return false;
}
/** Sets the {@link #fixedInputChoice} field. */
/** Sets the {@link #fixedInputChoiceMap} field for a specific instance key */
public void setFixedInputChoice(List<String> fixedInputChoice, String instanceKey) {
this.fixedInputChoiceMap.put(instanceKey, fixedInputChoice);
}
/**
* Sets the {@link #fixedInputChoiceMap} field for an {@link IAnnotationValueProvider} that
* manages only a single instance key.
*/
public void setFixedInputChoice(List<String> fixedInputChoice) {
this.fixedInputChoice = fixedInputChoice;
setFixedInputChoice(fixedInputChoice, DEFAULT_KEY);
}
/**
* Initializes the {@link #currentInputChoice} field (called during the construction of the
* Initializes the {@link #currentInputChoiceMap} field (called during the construction of the
* editing support in {@link #createEditingSupport(ColumnViewer, Class)}).
*/
@SuppressWarnings("unchecked")
private void initializeInputChoice(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> clazz) throws Exception {
Class<? extends IAnnotatedSpecification> clazz, String instanceKey) throws Exception {
// Input choice is not set, or it is restricted to concrete set of values
// (use SingleEnumAttributeValueProviderBase for Enum types!)
if(fixedInputChoice == null || !fixedInputChoice.isEmpty()) {
currentInputChoice = fixedInputChoice;
if(fixedInputChoiceMap.get(instanceKey) == null ||
!fixedInputChoiceMap.get(instanceKey).isEmpty()) {
currentInputChoiceMap.put(instanceKey, fixedInputChoiceMap.get(instanceKey));
} else if(!(viewer.getInput() instanceof Set<?>) || ((Set<?>)viewer.getInput()).isEmpty() ||
!(((Set<?>)viewer.getInput()).iterator().next() instanceof AnnotationEntry)) {
currentInputChoice = null;
currentInputChoiceMap.put(instanceKey, null);
} else {
......@@ -283,10 +310,12 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
root = root.eContainer();
}
currentInputChoice = new TreeSet<String>();
Set<String> choices = new TreeSet<String>();
for(T specification : (EList<T>)EcoreUtils.getChildrenWithType(root, clazz)) {
currentInputChoice.add(getAnnotationValue(specification).toString());
choices.add(getAnnotationValue(specification).toString());
}
currentInputChoiceMap.put(instanceKey, choices);
}
}
......@@ -295,31 +324,32 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple
* {@link #setAnnotationValue(String, IAnnotatedSpecification)}. In particular, this
* method handles the removal of input choices from if these are dynamically managed.
*/
protected String getAnnotationValueAndUpdateInputChoice(String value, T specification)
throws Exception {
if((value == null || value.isEmpty()) && currentInputChoice != null &&
!currentInputChoice.isEmpty()) {
protected String getAnnotationValueAndUpdateInputChoice(String value, T specification,
String instanceKey) throws Exception {
if((value == null || value.isEmpty()) && currentInputChoiceMap.get(instanceKey) != null &&
!currentInputChoiceMap.get(instanceKey).isEmpty()) {
// Only one entry left: do not remove
if(currentInputChoice.size() == 1) {
return currentInputChoice.iterator().next();
if(currentInputChoiceMap.get(instanceKey).size() == 1) {
return currentInputChoiceMap.get(instanceKey).iterator().next();
}
// 1st entry is to be removed: Choose 2nd entry as new value
String currentValue = getAnnotationValue(specification);
if(currentInputChoice.iterator().next().equals(currentValue)) {
Iterator<String> iter = currentInputChoice.iterator();
if(currentInputChoiceMap.get(instanceKey).iterator().next().equals(currentValue)) {
Iterator<String> iter = currentInputChoiceMap.get(instanceKey).iterator();
iter.next();
String rval = iter.next();
currentInputChoice.remove(currentValue);
currentInputChoiceMap.get(instanceKey).remove(currentValue);
return rval;
}
// Otherwise, return the entry just before the entry to be removed.
String rval = null;
for(Iterator<String> iter = currentInputChoice.iterator(); iter.hasNext();) {
for(Iterator<String> iter = currentInputChoiceMap.get(instanceKey).iterator(); iter
.hasNext();) {
String s = iter.next();
if(s != null && s.equals(currentValue)) {
currentInputChoice.remove(currentValue);
currentInputChoiceMap.get(instanceKey).remove(currentValue);
return rval;
}
rval = s;
......
......@@ -584,7 +584,7 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
/** Creates a column in tableViewer that displays the annotation given in spec */
protected void createAnnotationColumn(ColumnHandle columnHandle) {
TableColumn tableColumn;
TableColumn tableColumn = null;
if(columnHandle.isCreateColumn()) {
// Create column that contains a button for adding new instances of the
// current annotation type.
......@@ -595,30 +595,38 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
tableColumn = column.getColumn();
} else {
Class<? extends IAnnotatedSpecification> annotationClass =
columnHandle.getAnnotatedSpecification().getClass();
// Add new new column
TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
tableColumn = column.getColumn();
// Add new column
try {
String specName = getColumnName(columnHandle);
tableColumn.setText(specName);
// Have the matching EditingSupport created for the current annotated specification
// (work is delegated to respective IAnnotationValueProvider implementation)
EditingSupport editingSupport =
columnHandle.getEntry().createSpecificationEditElement(tableViewer,
annotationClass, columnHandle.getInstanceKey());
TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
tableColumn = column.getColumn();
Class<? extends IAnnotatedSpecification> annotationClass =
columnHandle.getAnnotatedSpecification().getClass();
String specName = getColumnName(columnHandle);
tableColumn.setText(specName);
column.setEditingSupport(editingSupport);
// Have the matching EditingSupport created for the current annotated specification
// (work is delegated to respective IAnnotationValueProvider implementation)
EditingSupport editingSupport =
columnHandle.getEntry().createSpecificationEditElement(tableViewer,
annotationClass, columnHandle.getInstanceKey());
column.setEditingSupport(editingSupport);
// Add column label provider, and set EditingSupport
column.setLabelProvider(new AnnotationLabelProvider(annotationClass, this,
columnHandle.getInstanceKey()));
} catch(Exception e) {
System.out.println("Failed to create editing support for annotation class " +
annotationClass.getCanonicalName() + ": " + e.getMessage());
}
// Add column label provider, and set EditingSupport
column.setLabelProvider(new AnnotationLabelProvider(annotationClass, this, columnHandle
.getInstanceKey()));
}
tableColumn.setWidth(125);
if(tableColumn != null) {
tableColumn.setWidth(125);
}
}
......
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