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 e6053d0a4f5f58c48eff12f1c77fe6865aa64c24..f6b61e07c8091b039d74638cc2b907b19757239e 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 @@ -71,9 +71,9 @@ public final class AnnotationEntry { /** * Indicates whether the given specification contains a value type allowing the storage of - * multiple items (like a list of strings). This methods significantly simplifies the UI logic. + * multiple instances of the annotation (like a list of strings). */ - public boolean allowsMultipleValues(Class<? extends IAnnotatedSpecification> clazz) { + public boolean allowsMultipleAnnoationInstances(Class<? extends IAnnotatedSpecification> clazz) { for(IAnnotatedSpecification s : specificationsList) { if(clazz.isInstance(s)) { return providerSpecMapping.get(clazz).allowsMultipleAnnotationInstances(); @@ -110,6 +110,25 @@ public final class AnnotationEntry { } /** Returns the annotation value */ + public <V> V getSpecificationValue(Class<? extends IAnnotatedSpecification> clazz, + String instanceKey) { + for(IAnnotatedSpecification s : specificationsList) { + if(clazz.isInstance(s)) { + try { + return providerSpecMapping.get(clazz).getAnnotationValue(s, instanceKey); + } catch(Exception e) { + throw null; + } + } + } + + throw null; + } + + /** + * Returns the annotation value for a specific instance for a annotation with multi-value + * support. + */ public <V> V getSpecificationValue(Class<? extends IAnnotatedSpecification> clazz) { for(IAnnotatedSpecification s : specificationsList) { if(clazz.isInstance(s)) { @@ -120,6 +139,36 @@ public final class AnnotationEntry { throw null; } + /** + * Sets a new value for the given specification clazz. + */ + public <V> void setSpecificationValue(V value, Class<? extends IAnnotatedSpecification> clazz, + String instanceKey) throws Exception { + for(IAnnotatedSpecification s : specificationsList) { + if(clazz.isInstance(s)) { + providerSpecMapping.get(clazz).setAnnotationValue(value, s, instanceKey); + return; + } + } + + throw new Exception("Could not find a AnnotationValueProvider for " + clazz.toString()); + } + + /** + * Sets a new value for the given specification clazz from a {@link String} representation. + */ + public void setSpecificationValue(String value, Class<? extends IAnnotatedSpecification> clazz, + String instanceKey) throws Exception { + for(IAnnotatedSpecification s : specificationsList) { + if(clazz.isInstance(s)) { + providerSpecMapping.get(clazz).setAnnotationValue(value, s, instanceKey); + return; + } + } + + throw new Exception("Could not find a AnnotationValueProvider for " + clazz.toString()); + } + /** * Sets a new value for the given specification clazz. */ @@ -155,10 +204,11 @@ public final class AnnotationEntry { * {@code clazz} (for use in the {@link GenericAnnotationView} . */ public EditingSupport createSpecificationEditElement(ColumnViewer viewer, - Class<? extends IAnnotatedSpecification> clazz) { + Class<? extends IAnnotatedSpecification> clazz, String instanceKey) { for(IAnnotatedSpecification s : specificationsList) { if(clazz.isInstance(s)) { - return providerSpecMapping.get(clazz).createEditingSupport(viewer, clazz); + return providerSpecMapping.get(clazz).createEditingSupport(viewer, clazz, + instanceKey); } } diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..1b9ddcfa8d16e01727d8bf255e1be43c8c9eb5bd --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------+ +$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.editingsupport; + +import org.eclipse.emf.common.util.EMap; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.swt.widgets.Shell; +import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; +import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; +import org.fortiss.tooling.base.ui.annotation.valueprovider.MultiInstanceAnnotationValueProviderBase; +import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; +import org.fortiss.tooling.kernel.service.IPersistencyService; + +/** + * This class extends {@link TextEditingSupport} to support text annotations for which multiple + * instances can exist. + * + * @see MultiInstanceAnnotationValueProviderBase + * + * @author diewald, barner + * @author $Author$ + * @version $Rev$ + * @ConQAT.Rating RED Hash: + */ +public class MultiInstanceAnnotationTextEditingSupport extends TextEditingSupport { + + /** Instance key to identify the corresponding instance of the annotation */ + private String instanceKey; + + /** Constructs a new {@link MultiInstanceAnnotationTextEditingSupport} for a specific column. */ + public MultiInstanceAnnotationTextEditingSupport(ColumnViewer viewer, + Class<? extends IAnnotatedSpecification> clazz, String instanceKey) { + super(viewer, clazz); + + this.instanceKey = instanceKey; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + protected Object getValue(Object element) { + String rval = null; + if(element instanceof AnnotationEntry) { + AnnotationEntry data = (AnnotationEntry)element; + if(data.getSpecificationValue(specClass) != null) { + rval = + ((EMap<String, String>)data.getSpecificationValue(specClass)) + .get(instanceKey); + } + } + return rval != null ? rval : ""; + } + + /** {@inheritDoc} */ + @Override + protected void setValue(Object element, final Object value) { + if(element instanceof AnnotationEntry && value instanceof String) { + final AnnotationEntry entry = (AnnotationEntry)element; + + if(!value.equals(entry.getSpecificationValue(specClass, instanceKey))) { + + ITopLevelElement modelContext = + IPersistencyService.INSTANCE.getTopLevelElementFor(entry.getModelElement()); + modelContext.runAsCommand(new Runnable() { + + @Override + public void run() { + try { + entry.setSpecificationValue(value, specClass, instanceKey); + } catch(IllegalArgumentException e) { + // e.printStackTrace(); + MessageDialog + .openError( + new Shell(), + "ERROR", + "The value you entered does not have the desired type.\nDetailed message:\n" + + e.getMessage()); + } catch(Exception e) { + MessageDialog.openError(new Shell(), "ERROR", e.getMessage()); + } + } + }); + this.getViewer().refresh(true); + } + + } + } +} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/TextEditingSupport.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/TextEditingSupport.java index ba152d6a6b9d657d20db5ef39a5b26022fd1b8b3..09179fdbce43cb4d80eff64993bec32a366ed0a7 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/TextEditingSupport.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/TextEditingSupport.java @@ -82,24 +82,24 @@ public class TextEditingSupport extends EditingSupport { return value.toString(); } } - return "-"; + return ""; } /** {@inheritDoc} */ @Override protected void setValue(Object element, final Object value) { if(element instanceof AnnotationEntry && value instanceof String) { - final AnnotationEntry data = (AnnotationEntry)element; + final AnnotationEntry entry = (AnnotationEntry)element; - if(!value.equals(data.getSpecificationValue(specClass))) { + if(!value.equals(entry.getSpecificationValue(specClass))) { ITopLevelElement modelContext = - IPersistencyService.INSTANCE.getTopLevelElementFor(data.getModelElement()); + IPersistencyService.INSTANCE.getTopLevelElementFor(entry.getModelElement()); modelContext.runAsCommand(new Runnable() { @Override public void run() { try { - data.setSpecificationValue((String)value, specClass); + entry.setSpecificationValue((String)value, specClass); } catch(IllegalArgumentException e) { // e.printStackTrace(); MessageDialog 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 99394f9db9f2259faba13e71a20d6acb5709e76c..386f92a762ec6f71b305976dc4570755bac84781 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 @@ -67,10 +67,10 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext IEObjectAware<IModelElement> { /** - * Predicate whether multiple instances of the {@link IAnnotatedSpecification} managed - * by this {@link IAnnotationValueProvider} can exist. For instance, the - * {@link GenericAnnotationView} will in this case create UI controls to enable the creation of - * these instances. + * Predicate whether the {@link IAnnotatedSpecification} managed + * by this {@link IAnnotationValueProvider} provides support for multiple (named) instances. For + * instance, the {@link GenericAnnotationView} will in this case create UI controls to enable + * the creation of these instances. */ public boolean allowsMultipleAnnotationInstances(); @@ -87,12 +87,16 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext */ public boolean setAnnotationName(String name, T specification); - /** Returns the value of the annotation in the user-specified data-type. */ + /** Returns the value of the annotation. */ public <U> U getAnnotationValue(T specification); /** - * Sets a new value for the annotation, taking an instance the user-specified data type has an - * input. + * Returns the value of a multi-instance annotation's instance denoted by {@code instanceKey}. + */ + public <U> U getAnnotationValue(T specification, String instanceKey) throws Exception; + + /** + * Sets a new value for the annotation. * * @throws Exception * is thrown if the conversion from the UI internal value representation ({@code U}) @@ -102,7 +106,7 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext 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} initializer. * * @throws Exception * is thrown if the conversion from {@link String} to the respective specialization @@ -111,14 +115,39 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext */ public void setAnnotationValue(String value, T specification) throws Exception; + /** + * Sets a new value for a multi-instance annotation's instance denoted by {@code instanceKey}. + * + * @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, String instanceKey) + throws Exception; + + /** + * Sets a new value for a multi-instance annotation's instance denoted by {@code instanceKey} + * from a {@link String} initializer. + * + * @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, String instanceKey) + throws Exception; + /** * Creates and returns the {@link EditingSupport} support element for the table-based * {@link GenericAnnotationView}. {@link IAnnotationValueProvider}s for specialized * {@link IAnnotatedSpecification} may choose to provide a dedicated, custom - * {@link EditingSupport}. + * {@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. */ public EditingSupport createEditingSupport(ColumnViewer viewer, - Class<? extends IAnnotatedSpecification> clazz); + Class<? extends IAnnotatedSpecification> clazz, String instanceKey); /** * Factory method that creates a new {@link IAnnotatedSpecification} specialization of type T to diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/MultiInstanceAnnotationValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/MultiInstanceAnnotationValueProviderBase.java new file mode 100644 index 0000000000000000000000000000000000000000..832cc75bada4778036a6f3c1285dba8ba7a3b869 --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/MultiInstanceAnnotationValueProviderBase.java @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------------------+ +$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.common.util.EMap; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EFactory; +import org.eclipse.emf.ecore.EStructuralFeature; +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.MultiInstanceAnnotationTextEditingSupport; + +/** + * <p> + * Base class for {@link IAnnotationValueProvider}s that support {@link IAnnotatedSpecification} for + * which multiple instances can exist. For each model element, a single instance of this + * {@link IAnnotatedSpecification} exists whose storage is implemented by a {@link EMap} + * {@code <EString, V>}, where the key is used as the instance name, and V is an EClass depicting + * the annotation type (e.g., {@code EString, EIntegerObject, ...}. + * </p> + * + * <p> + * The underlying {@link EMap} must be declared in the {@link IAnnotatedSpecification}'s meta-model + * as detailed here: <a href="http://wiki.eclipse.org/EMF/FAQ#How_do_I_create_a_Map_in_EMF.3F"> + * http://wiki.eclipse.org/EMF/FAQ#How_do_I_create_a_Map_in_EMF.3F</a>. + * </p> + * + * @author diewald, barner + * @author $Author$ + * @version $Rev$ + * @ConQAT.Rating RED Hash: + */ +public abstract class MultiInstanceAnnotationValueProviderBase<T extends IAnnotatedSpecification> + extends SingleEStructuralFeatureValueProviderBase<T> { + + /** + * {@link EDataType} of the value type V of the underlying EMap<String, V> storing the annotation + * instances. + */ + EDataType valueDataType; + + /** + * {@link EFactory} to construct (in particular from a {@link String} representation instances of + * the value type V of the underlying EMap<String, V> storing the annotation instances. + */ + EFactory valueFactory; + + /** + * Constructs a multi-instance enabled {@link IAnnotationValueProvider} for a + * {@link IAnnotatedSpecification} that whose storage is implemented by a single + * {@link EStructuralFeature}. + */ + public MultiInstanceAnnotationValueProviderBase(EClass annotatedSpecificationEClass, + EFactory annotationFactory, EStructuralFeature structuralFeature, + EFactory attributeFactory, EDataType valueDataType, EFactory valueFactory) { + super(annotatedSpecificationEClass, annotationFactory, structuralFeature, attributeFactory); + this.valueDataType = valueDataType; + this.valueFactory = valueFactory; + } + + /** {@inheritDoc} */ + @Override + public boolean allowsMultipleAnnotationInstances() { + return true; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public <V> V getAnnotationValue(T spec, String instanceKey) { + // Return value of current instance (entry map containing all instances of the annotation) + return ((EMap<String, V>)getAnnotationValue(spec)).get(instanceKey); + + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public <V> void setAnnotationValue(V value, T specification, String instanceKey) { + if(value instanceof String) { + ((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey, + (V)valueFactory.createFromString(valueDataType, (String)value)); + } else { + ((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey, value); + } + + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public void setAnnotationValue(String value, T specification, String instanceKey) { + ((EMap<String, String>)getAnnotationValue(specification)).put(instanceKey, value); + + } + + /** {@inheritDoc} */ + @Override + public EditingSupport createEditingSupport(ColumnViewer viewer, + Class<? extends IAnnotatedSpecification> clazz, String instanceKey) { + + return new MultiInstanceAnnotationTextEditingSupport(viewer, clazz, instanceKey); + } +} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleAttributeValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleAttributeValueProviderBase.java deleted file mode 100644 index fe2649995c5f3812e4ae92f0357f07887795e9f3..0000000000000000000000000000000000000000 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleAttributeValueProviderBase.java +++ /dev/null @@ -1,116 +0,0 @@ -/*--------------------------------------------------------------------------+ -$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.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EFactory; -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 that manages a single {@link EAttribute} - * contained by a {@link IAnnotatedSpecification}. - * - * @author barner - * @author $Author$ - * @version $Rev$ - * @ConQAT.Rating RED Hash: - */ -public abstract class SingleAttributeValueProviderBase<T extends IAnnotatedSpecification> extends - ValueProviderBase<T> { - - /** - * {@link EClass} of {@link IAnnotatedSpecification} that contains the respective attribute and - * that is managed by this {@link IAnnotationValueProvider}. - */ - final protected EClass annotatedSpecificationEClass; - - /** - * {@link EFactory} of ECore model that contains {@link IAnnotatedSpecification} identified by - * {@code annotatedSpecificationEClass} (used to create new instances of the annotation). - */ - final protected EFactory annotationFactory; - - /** - * The attribute of the {@link IAnnotatedSpecification} that is managed by this - * {@link IAnnotationValueProvider}. - */ - final protected EAttribute attribute; - - /** - * Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that - * whose storage is implemented by a single attribute. - */ - public SingleAttributeValueProviderBase(EClass annotatedSpecificationEClass, EFactory eFactory, - EAttribute attribute) { - this.annotatedSpecificationEClass = annotatedSpecificationEClass; - this.annotationFactory = eFactory; - this.attribute = attribute; - } - - /** {@inheritDoc} */ - @Override - public <U> void setAnnotationValue(U value, T specification) throws Exception { - specification.eSet(attribute, value); - } - - /** {@inheritDoc} */ - @SuppressWarnings("unchecked") - @Override - public <U> U getAnnotationValue(T specification) { - return (U)specification.eGet(attribute); - } - - /** - * Creates a new instance of the attribute (use to populate newly created annotation instances - * created in {@link #getAnnotatedSpecificationForModelElement(IModelElement)}. - */ - protected abstract Object createAttributeValue() throws Exception; - - /** {@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)annotationFactory.create(annotatedSpecificationEClass); - - // Create an set annotation attribute - specification.eSet(attribute, createAttributeValue()); - - // 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/SingleEDataTypeAttributeValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEDataTypeAttributeValueProviderBase.java deleted file mode 100644 index 35590a87083f9fe24e5f16ee6a26cacbf6ae8139..0000000000000000000000000000000000000000 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEDataTypeAttributeValueProviderBase.java +++ /dev/null @@ -1,118 +0,0 @@ -/*--------------------------------------------------------------------------+ -$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.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EDataType; -import org.eclipse.emf.ecore.EFactory; -import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; - -/** - * Base class for {@link IAnnotationValueProvider}s that manages a single {@link EDataType} - * attribute contained in a {@link IAnnotatedSpecification} (e.g., including primitive data types - * such as {@code int, double, ...}). - * - * @author barner - * @author $Author$ - * @version $Rev$ - * @ConQAT.Rating RED Hash: - */ -public abstract class SingleEDataTypeAttributeValueProviderBase<T extends IAnnotatedSpecification> - extends SingleAttributeValueProviderBase<T> { - - /** - * {@link EDataType} of the primitive attribute used to implemented the storage - * of the underlying {@link IAnnotatedSpecification}. - */ - final protected EDataType attributeEDataType; - - /** - * String representation of default value used to initialize the primitive attribute of the - * underlying {@link IAnnotatedSpecification}. If it is {@code null}, {@link EDataType}'s - * default value will be used. - */ - final protected String attributeDefaultValue; - - /** - * {@link EFactory} of used to create new attribute instances. - */ - final protected EFactory attributeFactory; - - /** - * Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that - * that manages a single {@link EDataType} attribute contained in a - * {@link IAnnotatedSpecification}. New instances of the attribute will be initialized to the - * respective default value. - */ - public SingleEDataTypeAttributeValueProviderBase(EClass annotatedSpecificationEClass, - EFactory annotationFactory, EAttribute attribute, EDataType attributeEDataType, - EFactory attributeFactory) { - this(annotatedSpecificationEClass, annotationFactory, attribute, attributeEDataType, - attributeFactory, null); - } - - /** - * Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that - * that that manages a single {@link EDataType} attribute contained in a - * {@link IAnnotatedSpecification}. The constructor assumes that an instance of the attribute - * type can initialized from a {@link String}. - */ - public SingleEDataTypeAttributeValueProviderBase(EClass annotatedSpecificationEClass, - EFactory annotationFactory, EAttribute attribute, EDataType attributeEDataType, - EFactory attributeFactory, final String attributeDefaultValue) { - super(annotatedSpecificationEClass, annotationFactory, attribute); - this.attributeEDataType = attributeEDataType; - this.attributeDefaultValue = attributeDefaultValue; - this.attributeFactory = attributeFactory; - } - - /** {@inheritDoc} */ - @Override - public void setAnnotationValue(String value, T specification) throws Exception { - setAnnotationValue(attributeFactory.createFromString(attributeEDataType, value), - specification); - } - - /** {@inheritDoc} */ - @Override - protected Object createAttributeValue() throws Exception { - if(attributeDefaultValue != null) { - // Use default value if it has been specified - return attributeFactory.createFromString(attributeEDataType, attributeDefaultValue); - } - - // Return data types default value, it it is non-null. - Object rval = attributeEDataType.getDefaultValue(); - - if(rval != null) { - return rval; - } - - try { - // Try to construct attribute from empty string - rval = attributeFactory.createFromString(attributeEDataType, ""); - } catch(NumberFormatException e) { - // Last try: initialize numbers with 0 (throws NumberFormatException if not - // successful). - rval = attributeFactory.createFromString(attributeEDataType, "0"); - } - - return rval; - } -} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEStructuralFeatureValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEStructuralFeatureValueProviderBase.java new file mode 100644 index 0000000000000000000000000000000000000000..1a33ffcc44db346facab116058962df4acc49d85 --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEStructuralFeatureValueProviderBase.java @@ -0,0 +1,208 @@ +/*--------------------------------------------------------------------------+ +$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.EAttribute; +import org.eclipse.emf.ecore.EClass; +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.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 that manages a single {@link EStructuralFeature} + * contained by a {@link IAnnotatedSpecification}. + * + * @author barner + * @author $Author$ + * @version $Rev$ + * @ConQAT.Rating RED Hash: + */ +public abstract class SingleEStructuralFeatureValueProviderBase<T extends IAnnotatedSpecification> + extends ValueProviderBase<T> { + + /** + * {@link EClass} of {@link IAnnotatedSpecification} that contains the respective structural + * feature and that is managed by this {@link IAnnotationValueProvider}. + */ + final protected EClass annotatedSpecificationEClass; + + /** + * {@link EFactory} of ECore model that contains {@link IAnnotatedSpecification} identified by + * {@code annotatedSpecificationEClass} (used to create new instances of the annotation). + */ + final protected EFactory annotationFactory; + + /** + * The structural feature of the {@link IAnnotatedSpecification} that is managed by this + * {@link IAnnotationValueProvider}. + */ + final protected EStructuralFeature structuralFeature; + + /** + * {@link EFactory} of used to create new attribute instances. + */ + final protected EFactory structuralFeatureFactory; + + /** + * String representation of default value used to initialize the primitive attribute of the + * underlying {@link IAnnotatedSpecification}. If it is {@code null}, {@link EDataType}'s + * default value will be used. + */ + final protected String structuralFeatureDefaultValue; + + /** + * Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that + * whose storage is implemented by a single {@link EStructuralFeature}. + */ + public SingleEStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass, + EFactory annotationFactory, EStructuralFeature structuralFeature, + EFactory structuralFeatureFactory) { + this(annotatedSpecificationEClass, annotationFactory, structuralFeature, + structuralFeatureFactory, null); + } + + /** + * Constructs a {@link IAnnotationValueProvider} for a {@link IAnnotatedSpecification} that + * whose storage is implemented by a single {@link EStructuralFeature}. + */ + public SingleEStructuralFeatureValueProviderBase(EClass annotatedSpecificationEClass, + EFactory annotationFactory, EStructuralFeature structuralFeature, + EFactory structuralFeatureFactory, final String structuralFeatureDefaultValue) { + + this.annotatedSpecificationEClass = annotatedSpecificationEClass; + this.annotationFactory = annotationFactory; + this.structuralFeature = structuralFeature; + this.structuralFeatureFactory = structuralFeatureFactory; + this.structuralFeatureDefaultValue = structuralFeatureDefaultValue; + } + + /** {@inheritDoc} */ + @Override + public <U> void setAnnotationValue(U value, T specification) throws Exception { + specification.eSet(structuralFeature, value); + } + + /** {@inheritDoc} */ + @Override + public void setAnnotationValue(String value, T specification) throws Exception { + if(structuralFeature instanceof EAttribute) { + setAnnotationValue( + structuralFeatureFactory.createFromString( + ((EAttribute)structuralFeature).getEAttributeType(), value), + specification); + } else { + throw new Exception( + "setAnnotationValue(String, T) is not supported / has not been implemented the annotation type " + + structuralFeature.getEType().getName() + + "(specification class: " + + specification.getClass() + ")."); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override + public <U> U getAnnotationValue(T specification) { + return (U)specification.eGet(structuralFeature); + } + + /** + * Creates a new instance of the {@link EStructuralFeature} (use to populate newly created + * annotation instances created in + * {@link #getAnnotatedSpecificationForModelElement(IModelElement)}. + */ + protected Object createStructuralFeatureInstance() throws Exception { + if(structuralFeature instanceof EAttribute) { + + EDataType attributeEDataType = ((EAttribute)structuralFeature).getEAttributeType(); + + if(structuralFeatureDefaultValue != null) { + // Use default value if it has been specified + return structuralFeatureFactory.createFromString(attributeEDataType, + structuralFeatureDefaultValue); + } + + // 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 = structuralFeatureFactory.createFromString(attributeEDataType, ""); + } catch(NumberFormatException e) { + // Last try: initialize numbers with 0 (throws NumberFormatException if not + // successful). + rval = structuralFeatureFactory.createFromString(attributeEDataType, "0"); + } + + return rval; + } 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 structuralFeatureFactory.create(reference.getEReferenceType()); + } else { + throw new Exception( + "createStructuralFeatureInstance() is not supported / has not been implemented the annotation type " + + structuralFeature.getEType().getName() + "."); + } + } + + /** {@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)annotationFactory.create(annotatedSpecificationEClass); + + // Create and set structural feature implementing the annotation + Object structuralFeatureVal = createStructuralFeatureInstance(); + if(structuralFeatureVal != null) { + specification.eSet(structuralFeature, structuralFeatureVal); + } + + // 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/SingleEnumAttributeValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEnumAttributeValueProviderBase.java index cc0a39c736022d0f33f8eb72d67d3cb95d3f557a..491b128faaed34c79571e9fcba7b5367bdf339bf 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEnumAttributeValueProviderBase.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/SingleEnumAttributeValueProviderBase.java @@ -42,7 +42,7 @@ import org.fortiss.tooling.base.ui.annotation.editingsupport.ComboBoxEditingSupp * @ConQAT.Rating RED Hash: */ public abstract class SingleEnumAttributeValueProviderBase<T extends IAnnotatedSpecification> - extends SingleEDataTypeAttributeValueProviderBase<T> { + extends SingleEStructuralFeatureValueProviderBase<T> { /** Data type of the enumeration managed by this {@link IAnnotationValueProvider} */ private EEnum eEnum; @@ -68,7 +68,7 @@ public abstract class SingleEnumAttributeValueProviderBase<T extends IAnnotatedS public SingleEnumAttributeValueProviderBase(EClass annotatedSpecificationEClass, EFactory annotationFactory, EAttribute attribute, EEnum eEnum, EFactory attributeFactory, final String attributeDefaultValue) { - super(annotatedSpecificationEClass, annotationFactory, attribute, eEnum, attributeFactory, + super(annotatedSpecificationEClass, annotationFactory, attribute, attributeFactory, attributeDefaultValue); this.eEnum = eEnum; } @@ -76,7 +76,7 @@ public abstract class SingleEnumAttributeValueProviderBase<T extends IAnnotatedS /** {@inheritDoc} */ @Override public EditingSupport createEditingSupport(ColumnViewer viewer, - Class<? extends IAnnotatedSpecification> clazz) { + Class<? extends IAnnotatedSpecification> clazz, String instanceKey) { List<String> enumValues = new ArrayList<String>(); for(EEnumLiteral e : eEnum.getELiterals()) { 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 index 0422a2bd52fbab374a9801f3362399188665dd23..82bcc9b283fd24690802ef65c17ff381025c8a1b 100644 --- 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 @@ -43,20 +43,40 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple return false; } + /** {@inheritDoc} */ + @Override + public <U> U getAnnotationValue(T specification, String instanceKey) throws Exception { + return getAnnotationValue(specification); + } + /** {@inheritDoc} */ @Override public void setAnnotationValue(String value, T specification) throws Exception { + setAnnotationValue(value, specification, null); + } + + /** {@inheritDoc} */ + @Override + public <U> void setAnnotationValue(U value, T specification) throws Exception { + setAnnotationValue(value, specification, null); + } + + /** {@inheritDoc} */ + @Override + public void setAnnotationValue(String value, T specification, String instanceKey) + throws Exception { throw new Exception( "setAnnotationValue(String) is not supported / has not been implemented for annotations of type " + - getClass()); + specification.getClass()); } /** {@inheritDoc} */ @Override - public <U> void setAnnotationValue(U value, T specification) throws Exception { + public <U> void setAnnotationValue(U value, T specification, String instanceKey) + throws Exception { throw new Exception( "setAnnotationValue(U) is not supported / has not been implemented for annotations of type " + - getClass()); + specification.getClass()); } /** {@inheritDoc} */ @@ -68,12 +88,22 @@ public abstract class ValueProviderBase<T extends IAnnotatedSpecification> imple /** {@inheritDoc} */ @Override public EditingSupport createEditingSupport(ColumnViewer viewer, - Class<? extends IAnnotatedSpecification> clazz) { + Class<? extends IAnnotatedSpecification> clazz, String instanceKey) { // Default to text editing cell. return new TextEditingSupport(viewer, clazz); } + /** + * Creates the editing support without referring to the optional {@code userData} (see + * {@link #createEditingSupport(ColumnViewer, Class, String)}). + */ + public EditingSupport createEditingSupport(ColumnViewer viewer, + Class<? extends IAnnotatedSpecification> clazz) { + + return createEditingSupport(viewer, clazz, null); + } + /** {@inheritDoc} */ @Override public List<Class<? extends EObject>> excludeModelElementTypeFromAnnotatedSpecification() { diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationLabelProvider.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationLabelProvider.java index 7922a2956735c6e0dfae887ef4266e936de44018..264049cde059f91b2a82f443056c4dba17d7789a 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationLabelProvider.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationLabelProvider.java @@ -39,17 +39,22 @@ public class AnnotationLabelProvider extends ColumnLabelProvider { /** Contains the basic annotation view class */ protected AnnotationViewPartBase parentView; + /** String holding the key of which identifies the value to be displayed */ + protected String instanceKey; + /** * @param class1 * specification which provides the values to be displayed * * @param parent * view required to retrieve the selected elements + * @param instanceKey */ public AnnotationLabelProvider(Class<? extends IAnnotatedSpecification> class1, - AnnotationViewPartBase parent) { + AnnotationViewPartBase parent, String instanceKey) { specClass = class1; parentView = parent; + this.instanceKey = instanceKey; } /** {@inheritDoc} */ @@ -57,12 +62,13 @@ public class AnnotationLabelProvider extends ColumnLabelProvider { public String getText(Object element) { if(element instanceof AnnotationEntry) { AnnotationEntry annotationEntry = (AnnotationEntry)element; - Object value = annotationEntry.getSpecificationValue(specClass); + + Object value = annotationEntry.getSpecificationValue(specClass, instanceKey); if(value != null) { return value.toString(); } } - return "-"; + return ""; } /** {@inheritDoc} */ diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java new file mode 100644 index 0000000000000000000000000000000000000000..24678fe1ffe4c03b963ce20c6658d143d6bb36f7 --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java @@ -0,0 +1,277 @@ +/*--------------------------------------------------------------------------+ +$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.view; + +import org.eclipse.emf.common.util.EMap; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerColumn; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; +import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; +import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; +import org.fortiss.tooling.kernel.service.IPersistencyService; + +/** + * This class is responsible to construct a column which holds a button that allows adding new + * instance for multi-instance annotations. + * + * This class is in part based on code from the class {@link TableViewerColumn}. + * + * @author diewald, barner + * @author $Author$ + * @version $Rev$ + * @ConQAT.Rating RED + */ +public class CreateAnnotationInstanceColumn extends ViewerColumn { + + /** the column to be added to the table */ + private TableColumn column; + + /** annotation specification this column refers to */ + private IAnnotatedSpecification columnSpec; + + /** annotation entry the specification {@code columnSpec} is associated with */ + private AnnotationEntry columnSpecAnnEntry; + + /** the button which opens a dialog to create new values for the specification {@code columnSpec} */ + private Button crButton; + + /** + * Creates a new viewer column for the given {@link TableViewer} on a new {@link TableColumn} + * with the given style bits. The column is added at the + * end of the list of columns. + * + * @param viewer + * the table viewer to which this column belongs + * @param style + * the style used to create the column, for applicable style bits + * see {@link TableColumn} + * @see TableColumn#TableColumn(Table, int) + */ + public CreateAnnotationInstanceColumn(TableViewer viewer, int style) { + this(viewer, style, -1); + } + + /** + * Creates a new viewer column for the given {@link TableViewer} on a new {@link TableColumn} + * with the given style bits. The column is inserted at + * the given index into the list of columns. + * + * @param viewer + * the table viewer to which this column belongs + * @param style + * the style used to create the column, for applicable style bits + * see {@link TableColumn} + * @param index + * the index at which to place the newly created column + * @see TableColumn#TableColumn(Table, int, int) + */ + public CreateAnnotationInstanceColumn(TableViewer viewer, int style, int index) { + this(viewer, createColumn(viewer.getTable(), style, index)); + } + + /** + * This class creates a standard table columns by calling the default of this class which is + * taken form {@link TableViewerColumn}. Additionally, it sets some specific values that are + * associated with the given annotation specification {@code spec}. Furthermore, it manages the + * creation and the functionality of the 'create' button and the associated dialog. + * + * @param viewer + * the table in which the column shall appear + * @param style + * the column's style + * @param spec + * the annotation specification that this class shall refer to + * @param entry + * the AnnotationEntry associated with the given specification {@code spec} + */ + public CreateAnnotationInstanceColumn(TableViewer viewer, int style, + IAnnotatedSpecification spec, AnnotationEntry entry) { + this(viewer, style, -1); + + columnSpec = spec; + columnSpecAnnEntry = entry; + column.setText(entry.getSpecificationAnnotationName(spec.getClass())); + + setLabelProvider(new CreateNewAnnotationColumn()); + } + + /** + * Creates a new viewer column for the given {@link TableViewer} on the given + * {@link TableColumn}. + * + * @param viewer + * the table viewer to which this column belongs + * @param column + * the underlying table column + */ + public CreateAnnotationInstanceColumn(TableViewer viewer, TableColumn column) { + super(viewer, column); + this.column = column; + } + + /** creates the column by instantiating TableColumn */ + private static TableColumn createColumn(Table table, int style, int index) { + if(index >= 0) { + return new TableColumn(table, style, index); + } + + return new TableColumn(table, style); + } + + /** + * @return the underlying SWT table column + */ + public TableColumn getColumn() { + return column; + } + + /** + * creates the content of a new column via the update method of the table viewer to provide a + * "Create" button in the first row such that new values can be added to the table + */ + private class CreateNewAnnotationColumn extends ColumnLabelProvider { + /** {@inheritDoc} */ + @Override + public void update(ViewerCell cell) { + + TableItem item = (TableItem)cell.getItem(); + + if(columnSpec != null && crButton == null) { + crButton = new Button((Composite)cell.getViewerRow().getControl(), SWT.NONE); + crButton.setText("Create"); + + crButton.addListener(SWT.Selection, new CreateButtonListener()); + + TableEditor editor = new TableEditor(item.getParent()); + editor.grabHorizontal = true; + editor.grabVertical = true; + editor.setEditor(crButton, item, cell.getColumnIndex()); + editor.layout(); + } + } + } + + /** + * This Listener watches the "Create" button such that a dialog is opened if pressed and a new + * key can be added to the specification type of this column + */ + private class CreateButtonListener implements Listener { + /** Buffer holding the annotation's map to support the get/set functions of the model */ + + /** {@inheritDoc} */ + @Override + public void handleEvent(Event event) { + if(event.widget == crButton) { + InputDialog dlg = + new InputDialog(Display.getCurrent().getActiveShell(), "Create Annotation", + "Enter the name of the new annotation", "", + new AnnotationNameValidator()); + if(dlg.open() == Window.OK) { + final String instanceKey = dlg.getValue(); + + // Register the new annotation instance with the model, by writing a null value + // for the input key provided by the user. A write transaction / a switch to the + // model context is required to modify the from the GUI context. + ITopLevelElement modelContext = + IPersistencyService.INSTANCE.getTopLevelElementFor(columnSpecAnnEntry + .getModelElement()); + modelContext.runAsCommand(new Runnable() { + + @SuppressWarnings("unchecked") + @Override + public void run() { + try { + // Work around the fact that getSpecificationValue(null, + // columnSpec.getClass(), instanceKey) would resolve + // to the more specific getSpecificationValue(String, Class<? + // extends IAnnotatedSpecification>, String) overload of the method, + // and thus would not work for maps whose value type is not String. + // + // Hence, the entire instance map is retrieved here, and put() is + // called explicitly. + ((EMap<String, ?>)columnSpecAnnEntry + .getSpecificationValue(columnSpec.getClass())).put( + instanceKey, null); + } catch(IllegalArgumentException e) { + // e.printStackTrace(); + MessageDialog + .openError( + new Shell(), + "ERROR", + "The value you entered does not have the desired type.\nDetailed message:\n" + + e.getMessage()); + } catch(Exception e) { + MessageDialog.openError(new Shell(), "ERROR", e.getMessage()); + } + } + }); + } + } + } + } + + /** Provides a validator which checks if an input string is not an existing annotation name */ + class AnnotationNameValidator implements IInputValidator { + /** + * Validates the String. Returns null for no error, or an error message + * + * @param inputText + * the String to validate + * @return String + */ + @Override + public String isValid(String inputText) { + @SuppressWarnings("unchecked") EMap<String, ?> kVMap = + (EMap<String, ?>)columnSpecAnnEntry + .getSpecificationValue(columnSpec.getClass()); + if(kVMap != null) { + if(kVMap.containsKey(inputText)) + return "You cannot create a new key that already exists for the selected specification class."; + } + return null; + } + } + + /** + * Disposes the UI elements created by this class, namely {@code crButton} and {@code column}. + * This is required whenever the parent UI-element is repainted. See the general Java-UI + * documentation for details. + */ + public void dispose() { + crButton.dispose(); + column.dispose(); + } +} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java index d2a5a49caed60253a9194cc479f212ad82b57458..48ceece4ffa743e5ab557e21deeab85c23054440 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java @@ -17,8 +17,12 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.ui.annotation.view; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.emf.common.util.EMap; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.EditingSupport; @@ -43,7 +47,7 @@ import org.fortiss.tooling.kernel.model.INamedCommentedElement; * Per default, this class only supports displaying simple annotation types. You are required to * override the {@code selectionChanged} method to support displaying these annotations. * - * @author eder + * @author eder, diewald, barner * @author $Author$ * @version $Rev$ * @ConQAT.Rating YELLOW Hash: D91763408246ECD3578DAD0E37BC4C41 @@ -54,6 +58,20 @@ public class GenericAnnotationView extends AnnotationViewPartBase { protected HashMap<Class<? extends IAnnotatedSpecification>, TableViewerColumn> annotationSpecColumns = new HashMap<Class<? extends IAnnotatedSpecification>, TableViewerColumn>(); + /** + * List containing the columns that are responsible for creating new keys. Required for + * disposing when updating the view. + */ + private List<CreateAnnotationInstanceColumn> createColumns = + new ArrayList<CreateAnnotationInstanceColumn>(); + + /** + * Map for associating those specifications that allow multiple values with their according + * AnnotationEntries. + */ + private Map<IAnnotatedSpecification, AnnotationEntry> specsAllowingMultipleValues = + new HashMap<IAnnotatedSpecification, AnnotationEntry>(); + /** The table viewer */ protected TableViewer tableViewer; @@ -77,9 +95,15 @@ public class GenericAnnotationView extends AnnotationViewPartBase { public void selectionChanged(IWorkbenchPart part, ISelection selection) { super.selectionChanged(part, selection); + createSingleInstanceAnnotationColumns(); + createMultiInstanceAnnotationColumns(); + } + + /** Create columns for ordinary (single instance) {@link IAnnotatedSpecification}s */ + private void createSingleInstanceAnnotationColumns() { /* - * disposes all columns of the table viewer, except the first column, which holds the model - * elements + * disposes all columns of the table viewer, except the first column, which holds the names + * of the model elements */ while(tableViewer.getTable().getColumnCount() > 1) { tableViewer.getTable().getColumn(1).dispose(); @@ -93,15 +117,69 @@ public class GenericAnnotationView extends AnnotationViewPartBase { */ for(AnnotationEntry entry : annotationEntryList) { for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { - if(!isExistingColumn(spec) && !entry.allowsMultipleValues(spec.getClass())) { - createAnnotationColumn(entry, spec); + if(!isExistingColumn(spec) && + !entry.allowsMultipleAnnoationInstances(spec.getClass())) { + createAnnotationColumn(entry, spec, null); } } } if(!tableViewer.getTable().isDisposed()) tableViewer.setInput(annotationEntryList); + } + + /** Create columns for multi-instance {@link IAnnotatedSpecification}s */ + private void createMultiInstanceAnnotationColumns() { + for(CreateAnnotationInstanceColumn col : createColumns) { + col.dispose(); + } + + specsAllowingMultipleValues.clear(); + + /* + * Iterate over all available specifications in the model. Columns for specifications + * with simple values have already been created by the superclass 'GenericAnnotationView', + * others are stored in the map 'specsAllowingMultipleValues'. + * Each annotation specification type may exist only once in the table view or the map + * 'code specsAllowingMultipleValues'. + */ + List<String> specClassNamesMult = new ArrayList<String>(); + for(AnnotationEntry entry : annotationEntryList) { + for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { + if(entry.allowsMultipleAnnoationInstances(spec.getClass()) && + !specClassNamesMult.contains(spec.getClass().getSimpleName())) { + specsAllowingMultipleValues.put(spec, entry); + specClassNamesMult.add(spec.getClass().getSimpleName()); + } + } + } + // Iterate over all specification supporting multiple values. + for(IAnnotatedSpecification spec : specsAllowingMultipleValues.keySet().toArray( + new IAnnotatedSpecification[specsAllowingMultipleValues.keySet().size()])) { + AnnotationEntry entry = specsAllowingMultipleValues.get(spec); + + // Map holding the values of the current multi-instance specification type + EMap<String, ?> kVMap = entry.getSpecificationValue(spec.getClass()); + + if(kVMap != null) { + // Create new column for each instance of the current multi-instance annotation + for(String key : kVMap.keySet().toArray(new String[kVMap.keySet().size()])) { + createAnnotationColumn(entry, spec, key); + } + } + + // Create column that contains a button for adding new instances of the + // current annotation type. + createColumns + .add(new CreateAnnotationInstanceColumn(tableViewer, SWT.NONE, spec, entry)); + (createColumns.get(createColumns.size() - 1)).getColumn().setWidth(125); + + } + + // Refresh table to trigger the update method of the create columns in order to actually + // instantiate the "Create" buttons + tableViewer.refresh(); } /** Creates the (leading) column which displays the model elements */ @@ -138,23 +216,33 @@ public class GenericAnnotationView extends AnnotationViewPartBase { } /** Creates a column in tableViewer that displays the annotation given in spec */ - protected void createAnnotationColumn(AnnotationEntry entry, IAnnotatedSpecification spec) { - /* add the new column and name it */ - TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE); + protected void createAnnotationColumn(AnnotationEntry entry, IAnnotatedSpecification spec, + String instanceKey) { + + // Determine column name String specName = entry.getSpecificationAnnotationName(spec.getClass()); - if(specName == null) - specName = "Empty Annotation"; + if(specName == null || specName.isEmpty()) { + specName = "<Unnamed Annotation>"; + } + + if(instanceKey != null) { + specName += ": " + instanceKey; + } + + // Add new new column + TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE); column.getColumn().setText(specName); + column.getColumn().setWidth(125); annotationSpecColumns.put(spec.getClass(), column); // Have the matching EditingSupport created for the current annotated specification // (work is delegated to respective IAnnotationValueProvider implementation) EditingSupport editingSupport = - entry.createSpecificationEditElement(tableViewer, spec.getClass()); + entry.createSpecificationEditElement(tableViewer, spec.getClass(), instanceKey); // Add column label provider, and set EditingSupport - column.setLabelProvider(new AnnotationLabelProvider(spec.getClass(), this)); + column.setLabelProvider(new AnnotationLabelProvider(spec.getClass(), this, instanceKey)); column.setEditingSupport(editingSupport); }