diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationEntry.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationEntry.java index 829d303e7dd7d71a5608cb1cf2e23a7586b3d714..8ab3644ed1c806044b9b2cae3afe2de03ae644e7 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationEntry.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationEntry.java @@ -167,7 +167,7 @@ public final class AnnotationEntry { Class<? extends IAnnotatedSpecification> clazz, Object parent) { for(IAnnotatedSpecification s : specificationsList) { if(clazz.isInstance(s)) { - return providerSpecMapping.get(clazz).getEditElement(viewer, clazz, parent); + return providerSpecMapping.get(clazz).getEditingSupport(viewer, clazz, parent); } } diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java index 2c53dbbdd20f557b1db86b7a8fb38d49c73316f7..1681a2aa4ad6627dce996d5dd5cd0775884e0071 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java @@ -82,15 +82,24 @@ public class AnnotationValueService extends List<? extends IModelElement> allChildren = getAllChildren(root, element.getClass(), - annotationProvider.filterOut()); + annotationProvider.excludeModelElementTypeFromAnnotatedSpecification()); for(final IModelElement e : allChildren) { IAnnotatedSpecification annotatedSpecification = - EcoreUtils.pickFirstInstanceOf(annotationProvider.getClazz(), + EcoreUtils.pickFirstInstanceOf( + annotationProvider.getAnnotationClazz(), e.getSpecifications()); if(annotatedSpecification == null) { - annotatedSpecification = - annotationProvider.addNewSpecToModelElement(e); + try { + annotatedSpecification = + annotationProvider + .getAnnotatedSpecificationForModelElement(e); + } catch(Exception ex) { + System.out + .println("Error instantating new annotation: createAnnotatedSpecificationForModelElement() failed for " + + annotationProvider.getAnnotationClazz() + "."); + return; + } } boolean add = true; @@ -122,11 +131,11 @@ public class AnnotationValueService extends * filterOut list */ 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>(); - if(filterOut != null) - getAllChildren2(element, type, filterOut, results); + if(modelElementTypesExcludedFromAnnotatedSpecification != null) + getAllChildren2(element, type, modelElementTypesExcludedFromAnnotatedSpecification, results); else results = EcoreUtils.getChildrenWithType(element, type); return results; @@ -136,21 +145,21 @@ public class AnnotationValueService extends /** depth search for desired elements */ @SuppressWarnings("unchecked") 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(); for(EObject o : eContents) { if(type.isInstance(o)) { results.add((T)o); - getAllChildren2(o, type, filterOut, results); + getAllChildren2(o, type, modelElementTypesExcludedFromAnnotatedSpecification, results); } else { boolean filter = false; - for(Class<?> c : filterOut) { + for(Class<?> c : modelElementTypesExcludedFromAnnotatedSpecification) { if(c.isInstance(o)) filter = true; } if(!filter) - getAllChildren2(o, type, filterOut, results); + getAllChildren2(o, type, modelElementTypesExcludedFromAnnotatedSpecification, results); } } } diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/IAnnotationValueProvider.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/IAnnotationValueProvider.java index fecdc43f2f95617cd07eb84431a137b5591fc740..c5ab4f9304bc280efd6a74cc68437540102daf08 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/IAnnotationValueProvider.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/IAnnotationValueProvider.java @@ -24,14 +24,41 @@ 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.view.GenericAnnotationView; import org.fortiss.tooling.kernel.service.base.IEObjectAware; /** - * Interface for {@link IAnnotatedSpecification}s. It defines the methods that need to be - * 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. + * Value provider interface for {@link IAnnotatedSpecification}s that * - * @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$ * @version $Rev$ * @ConQAT.Rating YELLOW Hash: 8BE6A1ECB76A0AD4141B7EE11CAE21DA @@ -43,44 +70,85 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext * 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. */ + // TODO: Review 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); - /** 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' */ - public <V> V getAnnotationValue(T specification); + /** Returns the value of the annotation in the user-specified data-type. */ + 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; /** * 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(); /** - * 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); /** - * Adds a new {@link IAnnotatedSpecification} of type T to the given model element and returns - * it + * Factory method that creates a new {@link IAnnotatedSpecification} specialization of type T to + * 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(); } diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SinglePrimitiveAttributeValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SinglePrimitiveAttributeValueProviderBase.java new file mode 100644 index 0000000000000000000000000000000000000000..b8ad8fb72435ebb0608a7a85abc20151e7012c1c --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SinglePrimitiveAttributeValueProviderBase.java @@ -0,0 +1,173 @@ +/*--------------------------------------------------------------------------+ +$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(); + } +} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/ValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/ValueProviderBase.java new file mode 100644 index 0000000000000000000000000000000000000000..abe8ef1c40ca21ea743c0bb6f8840234ed69ec07 --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/ValueProviderBase.java @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------+ +$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; + } + +}