Commit 9b274ef6 authored by Alexander Diewald's avatar Alexander Diewald
Browse files

Extend the AnnotationAction "framework".

- Move the annotation and annotationEntry fields from the ColumnHandle to the AnnotationInstSpec class.
- Add a container class to the IAnnotationValueProvider that allows to specify the menu entry string and the set of elements to apply the specified action to.
- Modify the IAnnotationValueProvider and DefaultAnnotationContextActions interfaces to use the new container class.
- Adjust the GenericAnnotationView to create runnables based on the information found in the new container class.
- Simplify the "Propagate to all" annotation action.
refs 2361
parent a0ec7ac8
......@@ -29,7 +29,7 @@ import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
* @author barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating YELLOW Hash: 7A023A8AF4AD6C6766060D8D64620E17
* @ConQAT.Rating YELLOW Hash: D2398D01DFE1F8E87DAB7820C808E928
*/
public class ColumnHandle<T extends IAnnotatedSpecification> extends AnnotationInstSpec<T>
implements Comparable<ColumnHandle<T>> {
......@@ -39,18 +39,6 @@ public class ColumnHandle<T extends IAnnotatedSpecification> extends AnnotationI
*/
private final static String MULTIINSTANCE_NAME_SEPARATOR = ":";
/**
* {@link AnnotationEntry} from which a particular {@link IAnnotatedSpecification} is to be
* displayed in the column represented by this {@link ColumnHandle}.
*/
private AnnotationEntry entry;
/**
* {@link IAnnotatedSpecification} from {@code entry} to be displayed in the column
* represented by this {@link ColumnHandle}.
*/
private IAnnotatedSpecification annotatedSpecification;
/** Flag if this {@link ColumnHandle} represents a {@link CreateAnnotationInstanceColumn}. */
private boolean isCreateColumn;
......@@ -58,28 +46,11 @@ public class ColumnHandle<T extends IAnnotatedSpecification> extends AnnotationI
@SuppressWarnings("unchecked")
public ColumnHandle(AnnotationEntry entry, T annotatedSpecification, String instanceKey,
boolean isCreateColumn) {
super((Class<T>)annotatedSpecification.getClass(), instanceKey);
this.entry = entry;
this.annotatedSpecification = annotatedSpecification;
super(entry, (Class<T>)annotatedSpecification.getClass(), annotatedSpecification,
instanceKey);
this.isCreateColumn = isCreateColumn;
}
/**
* Returns the {@link AnnotationEntry} from which a particular {@link IAnnotatedSpecification}
* is to be displayed in the column represented by this {@link ColumnHandle}.
*/
public AnnotationEntry getEntry() {
return entry;
}
/**
* Returns the {@link IAnnotatedSpecification} from {@code entry} to be displayed in the
* column represented by this {@link ColumnHandle}.
*/
public IAnnotatedSpecification getAnnotatedSpecification() {
return annotatedSpecification;
}
/**
* Returns a flag if this {@link ColumnHandle} represents a
* {@link CreateAnnotationInstanceColumn}.
......
......@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.conqat.lib.commons.collections.Pair;
......@@ -68,6 +69,7 @@ import org.fortiss.tooling.base.annotation.AnnotationEntry;
import org.fortiss.tooling.base.annotation.IAnnotationValueService;
import org.fortiss.tooling.base.annotation.valueprovider.AnnotationInstSpec;
import org.fortiss.tooling.base.annotation.valueprovider.IAnnotationValueProvider;
import org.fortiss.tooling.base.annotation.valueprovider.IAnnotationValueProvider.AnnotationActionEntry;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.base.ui.annotation.editingsupport.EditingSupportFactory;
......@@ -79,6 +81,8 @@ import org.fortiss.tooling.base.ui.annotation.labelprovider.ElementNameLabelProv
import org.fortiss.tooling.base.ui.annotation.view.AnnotationViewPartBase;
import org.fortiss.tooling.base.ui.annotation.view.generic.filter.AnnotationFilter;
import org.fortiss.tooling.base.ui.annotation.view.generic.filter.AnnotationFilterWidget;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.service.IPersistencyService;
/**
* <p>
......@@ -93,7 +97,7 @@ import org.fortiss.tooling.base.ui.annotation.view.generic.filter.AnnotationFilt
* @author eder, diewald, barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating YELLOW Hash: E73C8AEA023803F8E01B7C576DDAC5A4
* @ConQAT.Rating YELLOW Hash: 1F5E6C7E3A7A0B46E67BD1E90B04E7D3
*/
public class GenericAnnotationView extends AnnotationViewPartBase {
/** Root composite of {@link GenericAnnotationView}. */
......@@ -396,7 +400,7 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
* Constructs a {@link Listener} such that a context menu is created upon a right-click on
* entries in the Annotation View.
*/
private void addContextMenuListener(Table table) {
private <T extends IAnnotatedSpecification> void addContextMenuListener(Table table) {
table.addListener(SWT.MouseDown, new Listener() {
@Override
public void handleEvent(Event event) {
......@@ -412,15 +416,24 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
}
CellLabelProvider labelProv =
tableViewer.getLabelProvider(cell.getColumnIndex());
if(labelProv instanceof AnnotationLabelProvider) {
@SuppressWarnings("unchecked") Class<IAnnotatedSpecification> annotationType =
(Class<IAnnotatedSpecification>)((AnnotationLabelProvider)labelProv)
.getAnnotationType();
Object selectedElement = cell.getElement();
if(labelProv instanceof AnnotationLabelProvider &&
selectedElement instanceof AnnotationEntry) {
AnnotationEntry selEntry = (AnnotationEntry)selectedElement;
@SuppressWarnings("unchecked") Class<T> annotationType =
(Class<T>)((AnnotationLabelProvider)labelProv).getAnnotationType();
String instanceKey = ((AnnotationLabelProvider)labelProv).getInstanceKey();
AnnotationInstSpec<IAnnotatedSpecification> spec =
new AnnotationInstSpec<IAnnotatedSpecification>(annotationType,
instanceKey);
addContextMenuEntries(contextMenu, annotationCtxEntries.get(spec), spec);
AnnotationInstSpec<T> spec =
new AnnotationInstSpec<T>(selEntry, annotationType, selEntry
.getSpecification(annotationType), instanceKey);
// Bay Construction of the map, we can ensure that this cast will always be
// valid.
@SuppressWarnings("unchecked") IAnnotationValueProvider<T> valProvider =
(IAnnotationValueProvider<T>)annotationCtxEntries.get(spec);
addContextMenuEntries(contextMenu, valProvider, spec);
}
contextMenu.setVisible(true);
}
......@@ -432,44 +445,96 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
* Adds a {@link Listener} to the given {@link Menu} entry such that the given
* {@link BiConsumer} is executed upon selection.
*/
private
<T extends IAnnotatedSpecification, S extends IModelElement>
void
addContextMenuEntryListener(
MenuItem entry,
BiConsumer<AnnotationInstSpec<IAnnotatedSpecification>, AnnotationEntry> action,
AnnotationInstSpec<IAnnotatedSpecification> specificationType) {
private <T extends IAnnotatedSpecification, S extends IModelElement> void
addContextMenuEntryListener(MenuItem entry, AnnotationActionEntry actionEntry,
BiConsumer<AnnotationInstSpec<T>, T> action,
AnnotationInstSpec<T> entrySpecification,
Stream<AnnotationEntry> annotationEntries) {
entry.addSelectionListener(new SelectionAdapter() {
AnnotationInstSpec<IAnnotatedSpecification> spec = specificationType;
@Override
public void widgetSelected(SelectionEvent e) {
if(selectedTableItem.getFirstElement() instanceof AnnotationEntry) {
AnnotationEntry entry = (AnnotationEntry)selectedTableItem.getFirstElement();
ITopLevelElement modelContext =
IPersistencyService.getInstance().getTopLevelElementFor(
entry.getModelElement());
Runnable r =
createAnnoationActionRunnable(entry, action, actionEntry,
entrySpecification, annotationEntries);
boolean updateEnabled = isUpdateEnabled();
setUpdateEnabled(false);
action.accept(spec, entry);
modelContext.runAsCommand(r);
setUpdateEnabled(updateEnabled);
}
}
});
}
/**
* Creates a runnable for actions defined in {@link IAnnotationValueProvider} that are selected
* via the context menu of the AnnotationView. The Scope enum of an
* {@link AnnotationActionEntry} defines the elements on which the created {@link Runnable}
* executes the define {@link BiConsumer}.
*
* @param entry
* {@link AnnotationEntry} selected in the AnnotationView.
* @param action
* Action to be executed it selected.
* @param actionEntry
* {@link AnnotationActionEntry} describing the parameters of the action.
* @param specificationType
* Type of the Annotation.
* @param annotationEntries
* {@link AnnotationEntry}s that are currently visible in the AnnotationView.
* @return Runnable that is executed when the corresponding menu entry is selected.
*/
private <T extends IAnnotatedSpecification> Runnable createAnnoationActionRunnable(
AnnotationEntry entry, BiConsumer<AnnotationInstSpec<T>, T> action,
AnnotationActionEntry actionEntry, AnnotationInstSpec<T> specificationType,
Stream<AnnotationEntry> annotationEntries) {
Runnable r;
if(actionEntry.getScope() == AnnotationActionEntry.ActionScope.ALL_VISIBLE_ITEMS) {
r =
() -> {
for(T annotation : annotationEntries.map(
e -> e.getSpecification(specificationType
.getAnnotatedSpecificationType())).collect(
Collectors.toList())) {
action.accept(specificationType, annotation);
}
};
} else if(actionEntry.getScope() == AnnotationActionEntry.ActionScope.SINGLE_ITEM) {
T annotation =
entry.getSpecification(specificationType.getAnnotatedSpecificationType());
r = () -> {
action.accept(specificationType, annotation);
};
} else {
r = () -> {/* NOP */
};
}
return r;
}
/**
* Adds context menu entries to the given {@link Menu} whose name and associated action is
* determined by the {@link IAnnotationValueProvider}.
*/
private void addContextMenuEntries(Menu contextMenu,
IAnnotationValueProvider<IAnnotatedSpecification> valueProvider,
AnnotationInstSpec<IAnnotatedSpecification> annotationClass) {
private <T extends IAnnotatedSpecification> void addContextMenuEntries(Menu contextMenu,
IAnnotationValueProvider<T> valueProvider, AnnotationInstSpec<T> annotationClass) {
final Stream<AnnotationEntry> annotationEntriesMatchingFilter =
getLastAnnotationEntries().stream()
.filter(e -> annotationFilter.passesRowFilter(e));
for(Pair<String, BiConsumer<AnnotationInstSpec<IAnnotatedSpecification>, AnnotationEntry>> ctxMenuEntry : valueProvider
.getContextMenuEntries(annotationEntriesMatchingFilter)) {
for(Pair<AnnotationActionEntry, BiConsumer<AnnotationInstSpec<T>, T>> ctxMenuEntry : valueProvider
.getContextMenuEntries()) {
MenuItem mItem = new MenuItem(contextMenu, SWT.None);
mItem.setText(ctxMenuEntry.getFirst());
addContextMenuEntryListener(mItem, ctxMenuEntry.getSecond(), annotationClass);
mItem.setText(ctxMenuEntry.getFirst().getName());
addContextMenuEntryListener(mItem, ctxMenuEntry.getFirst(), ctxMenuEntry.getSecond(),
annotationClass, annotationEntriesMatchingFilter);
}
}
......
......@@ -17,6 +17,7 @@ $Id: codetemplates.xml 1 2011-01-01 00:00:01Z hoelzl $
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.annotation.valueprovider;
import org.fortiss.tooling.base.annotation.AnnotationEntry;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
/**
......@@ -26,15 +27,27 @@ import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
* @author diewald
* @author $Author: hoelzl $
* @version $Rev: 18709 $
* @ConQAT.Rating YELLOW Hash: 41A961F3E903456E5DD7A9867994DA8C
* @ConQAT.Rating YELLOW Hash: E886A6567782B37C7BEFEE21F56BEFA0
*/
public class AnnotationInstSpec<T extends IAnnotatedSpecification> {
/**
* {@link AnnotationEntry} from which a particular {@link IAnnotatedSpecification} is to be
* displayed in the column represented by this {@link AnnotationInstSpec}.
*/
private AnnotationEntry entry;
/**
* {@link IAnnotatedSpecification} from {@code entry} to be displayed in the column
* represented by this {@link AnnotationInstSpec}.
*/
private Class<T> annotatedSpecificationClass;
/**
* {@link IAnnotatedSpecification} from {@code entry} to be displayed in the column
* represented by this {@link AnnotationInstSpec}.
*/
private IAnnotatedSpecification annotatedSpecification;
/**
* Instance key identifying the particular instance of an {@link IAnnotatedSpecification} from
* {@code entry} to be displayed in the column represented by this {@link AnnotationInstSpec}.
......@@ -42,11 +55,22 @@ public class AnnotationInstSpec<T extends IAnnotatedSpecification> {
private String instanceKey;
/** Constructor. */
public AnnotationInstSpec(Class<T> annotatedSpecificationClass, String instanceKey) {
public AnnotationInstSpec(AnnotationEntry entry, Class<T> annotatedSpecificationClass,
T annotatedSpecification, String instanceKey) {
this.entry = entry;
this.annotatedSpecificationClass = annotatedSpecificationClass;
this.annotatedSpecification = annotatedSpecification;
this.instanceKey = instanceKey;
}
/**
* Returns the {@link AnnotationEntry} from which a particular {@link IAnnotatedSpecification}
* is to be displayed in the column represented by this {@link AnnotationInstSpec}.
*/
public AnnotationEntry getEntry() {
return entry;
}
/**
* Returns the {@link IAnnotatedSpecification} from {@code entry} to be displayed in the
* column represented by this {@link AnnotationInstSpec}.
......@@ -55,6 +79,14 @@ public class AnnotationInstSpec<T extends IAnnotatedSpecification> {
return annotatedSpecificationClass;
}
/**
* Returns the {@link IAnnotatedSpecification} from {@code entry} to be displayed in the
* column represented by this {@link AnnotationInstSpec}.
*/
public IAnnotatedSpecification getAnnotatedSpecification() {
return annotatedSpecification;
}
/**
* Returns the instance key identifying the particular instance of an
* {@link IAnnotatedSpecification} from {@code entry} to be displayed in the column
......@@ -64,7 +96,16 @@ public class AnnotationInstSpec<T extends IAnnotatedSpecification> {
return instanceKey;
}
/** {@inheritDoc} */
/**
* <p>
* The hashcode of the {@link AnnotationInstSpec} is ONLY based on the annotation type and the
* instance key to represent one particular annotation instance type. Nevertheless, the
* {@link AnnotationInstSpec} also carries references to the {@link AnnotationEntry} and the
* {@link IAnnotatedSpecification} instances to allow a backtracking to the originating
* elements.
*
* {@inheritDoc}
*/
@Override
public int hashCode() {
return annotatedSpecificationClass.hashCode() +
......
......@@ -17,20 +17,15 @@ $Id: codetemplates.xml 1 2011-01-01 00:00:01Z hoelzl $
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.base.annotation.valueprovider;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.conqat.lib.commons.collections.Pair;
import org.fortiss.tooling.base.ToolingBaseActivator;
import org.fortiss.tooling.base.annotation.AnnotationEntry;
import org.fortiss.tooling.base.annotation.valueprovider.IAnnotationValueProvider.AnnotationActionEntry.ActionScope;
import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.service.IPersistencyService;
import org.fortiss.tooling.kernel.utils.LoggingUtils;
/**
* Interface defining default implementations for the context menu of
......@@ -39,61 +34,48 @@ import org.fortiss.tooling.kernel.service.IPersistencyService;
* @author diewald
* @author $Author: hoelzl $
* @version $Rev: 18709 $
* @ConQAT.Rating YELLOW Hash: 5A3C99F6C95BD4E0AFE4B8B2D35C0752
* @ConQAT.Rating YELLOW Hash: A87B8527D55071EBD06CCB3BCE03B255
*/
public interface DefaultAnnotationContextActions<T extends IAnnotatedSpecification> extends
IAnnotationValueProvider<T> {
/** {@inheritDoc} */
@Override
public default List<Pair<String, BiConsumer<AnnotationInstSpec<T>, AnnotationEntry>>>
getContextMenuEntries(Stream<AnnotationEntry> annotationEntries) {
List<Pair<String, BiConsumer<AnnotationInstSpec<T>, AnnotationEntry>>> retList =
public default List<Pair<AnnotationActionEntry, BiConsumer<AnnotationInstSpec<T>, T>>>
getContextMenuEntries() {
List<Pair<AnnotationActionEntry, BiConsumer<AnnotationInstSpec<T>, T>>> retList =
new ArrayList<>();
// Propagates values from the selected entry to all entries in the same ITopLevelElement
// with the same type.
BiConsumer<AnnotationInstSpec<T>, AnnotationEntry> propagateToAll =
(AnnotationInstSpec<T> spec, AnnotationEntry entry) -> {
BiConsumer<AnnotationInstSpec<T>, T> propagateToAll =
(AnnotationInstSpec<T> spec, T annotation) -> {
Object value =
spec.getEntry().getSpecificationValue(
spec.getAnnotatedSpecificationType(), spec.getInstanceKey());
Class<T> specType = spec.getAnnotatedSpecificationType();
Object value = entry.getSpecificationValue(specType);
try {
if(spec.getInstanceKey() == null || spec.getInstanceKey().equals("")) {
setAnnotationValue(value, annotation);
} else {
setAnnotationValue(value, annotation, spec.getInstanceKey());
}
} catch(Exception e) {
LoggingUtils
.error(ToolingBaseActivator.getDefault(),
"Could not set the value of the annotation " +
annotation.getName() +
" when trying to propagate the value form the selected annotation.",
e);
}
};
ITopLevelElement topElement =
IPersistencyService.getInstance().getTopLevelElementFor(
entry.getModelElement());
AnnotationActionEntry propToAllDescriptor =
new AnnotationActionEntry("Propagate to all", ActionScope.ALL_VISIBLE_ITEMS);
// TODO: Move the creation of the runnable, the for-loop to iterate
// over the affected annotation entries as well as the selection of the affected
// entries (currently in GenericAnnotationView::addContextMenuEntries()) to
// IAnnotationValueProvider.getContextMenuEntries() (= DEFAULT ITERATION
// POLICY).
//
// The creation of the BiConsumer that the defines the actual action FOR A
// SINGLE ENTRY should be performed in another method of the
// IAnnotationValueProvider.
//
Runnable run =
() -> {
for(T annotation : annotationEntries.map(
e -> e.getSpecification(specType)).collect(
Collectors.toList())) {
try {
setAnnotationValue(value, annotation);
} catch(Exception ex) {
error(ToolingBaseActivator.getDefault(),
"Could not set the value of the annotation " +
annotation.getName() +
" when trying to propagate the value form the selected annotation.",
ex);
}
}
};
topElement.runAsCommand(run);
};
// Add the propagate action to the list of context menu entries.
retList.add(new Pair<String, BiConsumer<AnnotationInstSpec<T>, AnnotationEntry>>(
"Propagate value", propagateToAll));
retList.add(new Pair<AnnotationActionEntry, BiConsumer<AnnotationInstSpec<T>, T>>(
propToAllDescriptor, propagateToAll));
return retList;
}
......
......@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import org.conqat.lib.commons.collections.Pair;
import org.eclipse.emf.ecore.EObject;
......@@ -69,11 +68,47 @@ import org.fortiss.tooling.kernel.service.base.IEObjectAware;
* @author eder, diewald, barner
* @author $Author$
* @version $Rev$
* @ConQAT.Rating YELLOW Hash: 35E646C624C6EEEF82A16AC2EC255A4D
* @ConQAT.Rating YELLOW Hash: 87BAF8186707DA50675FF8A27B36519A
*/
public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> extends
IEObjectAware<IModelElement> {
/**
* Container to define an action entry (name & applicable items) that typically appears in the
* context menu of an annotation of the annotation view.
*/
public class AnnotationActionEntry {
/** Scope defining the {@link AnnotationEntry}s to apply the corresponding action to. */
public enum ActionScope {
/** All {@link AnnotationEntry}s that are matching the selected filter. */
ALL_VISIBLE_ITEMS,
/** Apply the action only to the selected item. */
SINGLE_ITEM
}
/** Name of the associated action, i.e. its entry. */
private String entryName;
/** {@link AnnotationEntry} elements to apply the associated action to. */
private ActionScope scope;
/** Constructor defining the name and the scope of the corresponding action. */
public AnnotationActionEntry(String entryName, ActionScope scope) {
this.entryName = entryName;
this.scope = scope;
}
/** Returns the name of the corresponding action. */
public String getName() {
return entryName;
}
/** Returns the scope of the action, i.e. the set of elements to apply the action to. */
public ActionScope getScope() {
return scope;
}
}
/**
* Default key used in case this {@link IAnnotationValueProvider} is used to manage a single
* instance key only.
......@@ -198,8 +233,9 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext
/**
* <p>
* Returns a list of String <--> {@link BiConsumer} {@link Pair}s that define the context menu
* entries that are available for specific entries of an {@link IAnnotatedSpecification}.
* Returns a list of {@link AnnotationActionEntry}s <--> {@link BiConsumer} {@link Pair}s that
* define the context menu entries that are available for specific entries of an
* {@link IAnnotatedSpecification}.
* </p>
* <p>
* This list is used in the view part of the annotations to provide actions for concrete
......@@ -208,16 +244,12 @@ public interface IAnnotationValueProvider<T extends IAnnotatedSpecification> ext
* annotation view (typically, the set of visible annotations that match the current filters).
* </p>
*
* @param annotationEntries
* {@link Stream} of {@link AnnotationEntry}s for which the actions should be
* offered.
*
* @return List of String <--> {@link BiConsumer} {@link Pair}s that define the context menu
* entries that are available for specific entries of an {@link IAnnotatedSpecification}
* .
* @return List of AnnotationActionEntry <--> {@link BiConsumer} {@link Pair}s that define the
* context menu entries that are available for specific entries of an
* {@link IAnnotatedSpecification}.
*/
default List<Pair<String, BiConsumer<AnnotationInstSpec<T>, AnnotationEntry>>>
getContextMenuEntries(Stream<AnnotationEntry> annotationEntries) {
default List<Pair<AnnotationActionEntry, BiConsumer<AnnotationInstSpec<T>, T>>>
getContextMenuEntries() {
return Collections.emptyList();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment