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

- Revise and document IAnnotationValueProvider API and add some TODOs for further refinement

- Provide generic abstract base classes:
  - ValueProviderBase -> for generic annotated specifications
  - SinglePrimitiveAttributeValueProviderBase, for annotated specifications whose storage is implemented by a single primitive attribute (Double, Integer, String, etc.)
parent 5e8b053e
No related branches found
No related tags found
No related merge requests found
...@@ -167,7 +167,7 @@ public final class AnnotationEntry { ...@@ -167,7 +167,7 @@ public final class AnnotationEntry {
Class<? extends IAnnotatedSpecification> clazz, Object parent) { Class<? extends IAnnotatedSpecification> clazz, Object parent) {
for(IAnnotatedSpecification s : specificationsList) { for(IAnnotatedSpecification s : specificationsList) {
if(clazz.isInstance(s)) { if(clazz.isInstance(s)) {
return providerSpecMapping.get(clazz).getEditElement(viewer, clazz, parent); return providerSpecMapping.get(clazz).getEditingSupport(viewer, clazz, parent);
} }
} }
......
...@@ -82,15 +82,24 @@ public class AnnotationValueService extends ...@@ -82,15 +82,24 @@ public class AnnotationValueService extends
List<? extends IModelElement> allChildren = List<? extends IModelElement> allChildren =
getAllChildren(root, element.getClass(), getAllChildren(root, element.getClass(),
annotationProvider.filterOut()); annotationProvider.excludeModelElementTypeFromAnnotatedSpecification());
for(final IModelElement e : allChildren) { for(final IModelElement e : allChildren) {
IAnnotatedSpecification annotatedSpecification = IAnnotatedSpecification annotatedSpecification =
EcoreUtils.pickFirstInstanceOf(annotationProvider.getClazz(), EcoreUtils.pickFirstInstanceOf(
annotationProvider.getAnnotationClazz(),
e.getSpecifications()); e.getSpecifications());
if(annotatedSpecification == null) { if(annotatedSpecification == null) {
annotatedSpecification = try {
annotationProvider.addNewSpecToModelElement(e); annotatedSpecification =
annotationProvider
.getAnnotatedSpecificationForModelElement(e);
} catch(Exception ex) {
System.out
.println("Error instantating new annotation: createAnnotatedSpecificationForModelElement() failed for " +
annotationProvider.getAnnotationClazz() + ".");
return;
}
} }
boolean add = true; boolean add = true;
...@@ -122,11 +131,11 @@ public class AnnotationValueService extends ...@@ -122,11 +131,11 @@ public class AnnotationValueService extends
* filterOut list * filterOut list
*/ */
private <S, T> List<? extends IModelElement> getAllChildren(EObject element, private <S, T> List<? extends IModelElement> getAllChildren(EObject element,
Class<? extends IModelElement> type, List<Class<? extends EObject>> filterOut) { Class<? extends IModelElement> type, List<Class<? extends EObject>> modelElementTypesExcludedFromAnnotatedSpecification) {
List<? extends IModelElement> results = new ArrayList<IModelElement>(); List<? extends IModelElement> results = new ArrayList<IModelElement>();
if(filterOut != null) if(modelElementTypesExcludedFromAnnotatedSpecification != null)
getAllChildren2(element, type, filterOut, results); getAllChildren2(element, type, modelElementTypesExcludedFromAnnotatedSpecification, results);
else else
results = EcoreUtils.getChildrenWithType(element, type); results = EcoreUtils.getChildrenWithType(element, type);
return results; return results;
...@@ -136,21 +145,21 @@ public class AnnotationValueService extends ...@@ -136,21 +145,21 @@ public class AnnotationValueService extends
/** depth search for desired elements */ /** depth search for desired elements */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T, S> void getAllChildren2(EObject element, Class<? extends IModelElement> type, private <T, S> void getAllChildren2(EObject element, Class<? extends IModelElement> type,
List<Class<? extends EObject>> filterOut, final List<T> results) { List<Class<? extends EObject>> modelElementTypesExcludedFromAnnotatedSpecification, final List<T> results) {
EList<EObject> eContents = element.eContents(); EList<EObject> eContents = element.eContents();
for(EObject o : eContents) { for(EObject o : eContents) {
if(type.isInstance(o)) { if(type.isInstance(o)) {
results.add((T)o); results.add((T)o);
getAllChildren2(o, type, filterOut, results); getAllChildren2(o, type, modelElementTypesExcludedFromAnnotatedSpecification, results);
} else { } else {
boolean filter = false; boolean filter = false;
for(Class<?> c : filterOut) { for(Class<?> c : modelElementTypesExcludedFromAnnotatedSpecification) {
if(c.isInstance(o)) if(c.isInstance(o))
filter = true; filter = true;
} }
if(!filter) if(!filter)
getAllChildren2(o, type, filterOut, results); getAllChildren2(o, type, modelElementTypesExcludedFromAnnotatedSpecification, results);
} }
} }
} }
......
...@@ -24,14 +24,41 @@ import org.eclipse.jface.viewers.ColumnViewer; ...@@ -24,14 +24,41 @@ import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.EditingSupport;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement; import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.annotation.view.GenericAnnotationView;
import org.fortiss.tooling.kernel.service.base.IEObjectAware; import org.fortiss.tooling.kernel.service.base.IEObjectAware;
/** /**
* Interface for {@link IAnnotatedSpecification}s. It defines the methods that need to be * Value provider interface for {@link IAnnotatedSpecification}s that
* implemented by a value provider to define the handling of the stored data and to retrieve
* information relevant to the UI, like the support for complex value types.
* *
* @author eder, diewald * <p>
* <ul>
* <li>establishes the link between the model (data storage) and the UI (data exchange and
* conversion)</li>
* <li>provides related annotation data-type specific operations, e.g. factory methods to create
* <ul>
* <li>new annotation instances</li>
* <li>{@link EditingSupport} UI controls for the generic table-based {@link GenericAnnotationView}</li>
* </ul>
* </ul>
*
* Concrete annotations need to provide specific implementations of this interface to perform the
* data exchange and conversion, and to provide the required factory methods.
* </p>
*
* <p>
* The interface / some of its methods take two template parameters
*
* <ul>
* <li><tt>T</tt>: Meta-model type of the specification, i.e. the particular subclass of
* {@link IAnnotatedSpecification} supported by the respective implementation of this
* {@link IAnnotationValueProvider} interface.</li>
* <li><tt>U</tt>: Data type used in the UI to support the respective annotation. For <tt>U</tt>, a
* reasonable {@code toString()} implementation must be provided that is used by the framework to
* render the value of the annotation in text-based editing support UI controls.</li>
* </ul>
* </p>
*
* @author eder, diewald, barner
* @author $Author$ * @author $Author$
* @version $Rev$ * @version $Rev$
* @ConQAT.Rating YELLOW Hash: 8BE6A1ECB76A0AD4141B7EE11CAE21DA * @ConQAT.Rating YELLOW Hash: 8BE6A1ECB76A0AD4141B7EE11CAE21DA
...@@ -43,44 +70,85 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext ...@@ -43,44 +70,85 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext
* Returns a boolean whether the implemented specification supports storing multiple values. * Returns a boolean whether the implemented specification supports storing multiple values.
* This method is used to handle these classes in the view part in a simpler manner. * This method is used to handle these classes in the view part in a simpler manner.
*/ */
// TODO: Review
public boolean allowsMultipleValues(); public boolean allowsMultipleValues();
/** Returns the name of the Annotation for 'specification' */ /**
* Returns the name of the annotation (e.g., used as column label in the table-based
* {@link GenericAnnotationView}).
*/
public String getAnnotationName(T specification); public String getAnnotationName(T specification);
/** Sets a new name for the annotation and overrides the old one */ /**
public void setAnnotationName(String name, T specification) throws IllegalArgumentException; * Sets a new name for the annotation (e.g., used as column label in the table-based
* {@link GenericAnnotationView}). The return value indicates if the rename operation was
* successful.
*/
public boolean setAnnotationName(String name, T specification);
/** Returns the value of the annotation for 'specification' */ /** Returns the value of the annotation in the user-specified data-type. */
public <V> V getAnnotationValue(T specification); public <U> U getAnnotationValue(T specification);
/** Sets a new value for the annotation. */ /**
public <V> void setAnnotationValue(V value, T specification) throws IllegalArgumentException; * Sets a new value for the annotation, taking an instance the user-specified data type has an
* input.
*
* @throws Exception
* is thrown if the conversion from the UI internal value representation ({@code U})
* to the respective specialization of {@link IAnnotatedSpecification} has failed,
* or if this operation is not available.
*/
public <U> void setAnnotationValue(U value, T specification) throws Exception;
/** Sets a new value in the annotation from a {@link String} representation. */ /**
* Sets a new value in the annotation from a {@link String} representation.
*
* @throws Exception
* is thrown if the conversion from {@link String} to the respective specialization
* of {@link IAnnotatedSpecification} has failed, or if this operation is not
* available.
*/
public void setAnnotationValue(String value, T specification) throws Exception; public void setAnnotationValue(String value, T specification) throws Exception;
/** /**
* If this method does not return null, a combo box is provided with the specific return values * If this method does not return null, a combo box is provided with the specific return values
*/ */
// TODO: Review / Remove from interface, implement {@link EditingSupport} for Enums instead
public List<String> getFixedValues(); public List<String> getFixedValues();
/** /**
* Returns a custom EditingSupport element for the annotation view * Returns a custom {@link EditingSupport} support element for the table-based
* {@link GenericAnnotationView}. In case {@code null} is returned, the annotation framework
* tries to fall back to one of the stand {@link EditingSupport}s instead.
*/ */
public EditingSupport getEditElement(ColumnViewer viewer, public EditingSupport getEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> class1, Object parent); Class<? extends IAnnotatedSpecification> class1, Object parent);
/** /**
* Adds a new {@link IAnnotatedSpecification} of type T to the given model element and returns * Factory method that creates a new {@link IAnnotatedSpecification} specialization of type T to
* it * the given model {@code element} and returns a reference to it.
*
* In case the annotation already exists in the model, this method does not create a new object,
* but returns the existing one.
*
* @throws Exception
* is thrown if no existing element could be retrieved, and the creation of a new
* element has failed.
*/ */
public T addNewSpecToModelElement(IModelElement element); public T getAnnotatedSpecificationForModelElement(IModelElement element) throws Exception;
/** Returns the class of T */ /**
public Class<T> getClazz(); * Returns the concrete specialization {@code T} of {@link IAnnotatedSpecification} supported by
* this specialization of {@link IAnnotationValueProvider}.
*/
public Class<T> getAnnotationClazz();
/** Returns a List of Objects which children will not have {@link IAnnotatedSpecification}s */ /**
public List<Class<? extends EObject>> filterOut(); * Returns a {@link List} of model element types which will not have the
* {@link IAnnotatedSpecification} managed by this {@link IAnnotationValueProvider}, refining
* the registration of the respective {@link IAnnotatedSpecification} in the
* {@code org.fortiss.tooling.base.ui.annotationViewPart} extension point.
*/
public List<Class<? extends EObject>> excludeModelElementTypeFromAnnotatedSpecification();
} }
/*--------------------------------------------------------------------------+
$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;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.model.element.IModelElementSpecification;
/**
* Base class for {@link IAnnotationValueProvider}s for {@link IAnnotatedSpecification}s that
* contain only a single (primitive type) attribute.
*
* @author barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating RED Hash:
*/
public abstract class SinglePrimitiveAttributeValueProviderBase<T extends IAnnotatedSpecification>
extends ValueProviderBase<T> {
/**
* {@link EClass} of {@link IAnnotatedSpecification} managed by this
* {@link IAnnotationValueProvider}.
*/
final private EClass annotatedSpecificationEClass;
/**
* {@link EFactory} of ECore model that contains {@link IAnnotatedSpecification} identified by
* {@code annotatedSpecificationEClass} (used to create new instances of the annotation).
*/
final private EFactory eFactory;
/**
* {@link Class} of the primitive attribute used to implemented the storage of the underlying
* {@link IAnnotatedSpecification}.
*/
final private Class<?> attributeClazz;
/**
* String representation of default value used to initialize the primitive attribute of the
* underlying {@link IAnnotatedSpecification}. If it is {@code null}, the default constructor
* of the data type identified by {@code attributeClazz} is used to create the attribute
* instance.
*/
final String attributeDefaultValue;
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented by a single, primitive attribute. Unless the type of the
* attribute (contained in {@code attributeClazz} is {@link Double} or {@link Integer}, this
* constructor assumes that the attribute is default constructible. Otherwise, the new instances
* of the attribute are initialized to {@code 0}.
*/
public SinglePrimitiveAttributeValueProviderBase(EClass annotatedSpecificationEClass,
EFactory eFactory, Class<?> attributeClazz) {
this(annotatedSpecificationEClass, eFactory, attributeClazz,
getDefaultValueInitializer(attributeClazz));
}
/**
* Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that
* whose storage is implemented by a single, primitive attribute. The constructor assumes that
* the attribute type has a constructor that can initialize the new instance from a
* {@link String}.
*/
public SinglePrimitiveAttributeValueProviderBase(EClass annotatedSpecificationEClass,
EFactory eFactory, Class<?> attributeClazz, final String attributeDefaultValue) {
this.annotatedSpecificationEClass = annotatedSpecificationEClass;
this.eFactory = eFactory;
this.attributeClazz = attributeClazz;
this.attributeDefaultValue = attributeDefaultValue;
}
/**
* Returns the initializer {@link String} in case this {@link IAnnotationValueProvider} is
* constructed without specifying a default value, i.e. using
* {@link #SinglePrimitiveAttributeValueProviderBase(EClass, EFactory, Class)}, or {@code null}
* that indicates that the attribute type's default constructor should be used to initialize new
* instances of the {@link IAnnotatedSpecification}'s attribute.
*/
private static String getDefaultValueInitializer(Class<?> attributeClazz) {
if(attributeClazz.equals(Double.class) || attributeClazz.equals(Integer.class)) {
return "0";
}
return null;
}
/**
* Returns the structural {@link EStructuralFeature} of the attribute used to implement the
* storage of the underlying {@link IAnnotatedSpecification}. This implementation returns the
* first attribute of the annotation identified by {@code annotatedSpecificationEClass}.
*/
private EStructuralFeature getStructuralFeature() {
return annotatedSpecificationEClass.getEStructuralFeatures().get(0);
}
/** {@inheritDoc} */
@Override
public void setAnnotationValue(String value, T specification) throws Exception {
specification.eSet(getStructuralFeature(),
attributeClazz.getDeclaredConstructor(String.class).newInstance(value));
}
/** {@inheritDoc} */
@Override
public <U> void setAnnotationValue(U value, T specification) throws Exception {
specification.eSet(getStructuralFeature(), value);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public <U> U getAnnotationValue(T specification) {
return (U)specification.eGet(getStructuralFeature());
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public T getAnnotatedSpecificationForModelElement(IModelElement element) throws Exception {
// Return existing annotation
for(IModelElementSpecification specification : element.getSpecifications()) {
if(annotatedSpecificationEClass.equals(specification.eClass())) {
return (T)specification;
}
}
// Create annotation
T specification = (T)eFactory.create(annotatedSpecificationEClass);
Object attributeValue;
// Create annotation attribute
if(attributeDefaultValue != null) {
attributeValue =
attributeClazz.getDeclaredConstructor(String.class).newInstance(
attributeDefaultValue);
} else {
attributeValue = attributeClazz.newInstance();
}
specification.eSet(getStructuralFeature(), attributeValue);
// Hook specification to model element
element.addSpecification(specification);
return specification;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public Class<T> getAnnotationClazz() {
return (Class<T>)annotatedSpecificationEClass.getClass();
}
}
/*--------------------------------------------------------------------------+
$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.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
/**
* Base class for {@link IAnnotationValueProvider}s.
*
* @author diewald
* @author $Author$
* @version $Rev$
* @ConQAT.Rating RED Hash:
*/
public abstract class ValueProviderBase<T extends IAnnotatedSpecification> implements
IAnnotationValueProvider<T> {
/** {@inheritDoc} */
@Override
public boolean setAnnotationName(String name, T specification) {
// Renaming this annotation is not supported.
return false;
}
/** {@inheritDoc} */
@Override
public void setAnnotationValue(String value, T specification) throws Exception {
throw new Exception(
"setAnnotationValue(String) is not supported / has not been implemented for annotations of type " +
getClass());
}
/** {@inheritDoc} */
@Override
public <U> void setAnnotationValue(U value, T specification) throws Exception {
throw new Exception(
"setAnnotationValue(U) is not supported / has not been implemented for annotations of type " +
getClass());
}
/** {@inheritDoc} */
@Override
public boolean allowsMultipleValues() {
return false;
}
/** {@inheritDoc} */
@Override
public List<String> getFixedValues() {
return null;
}
/** {@inheritDoc} */
@Override
public EditingSupport getEditingSupport(ColumnViewer viewer,
Class<? extends IAnnotatedSpecification> class1, Object parent) {
return null;
}
/** {@inheritDoc} */
@Override
public List<Class<? extends EObject>> excludeModelElementTypeFromAnnotatedSpecification() {
return null;
}
}
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