From 9c6a70bc9ac787e0238ef1a1cb03e8c1f40b86f6 Mon Sep 17 00:00:00 2001 From: Simon Barner <barner@fortiss.org> Date: Thu, 28 Aug 2014 10:02:03 +0000 Subject: [PATCH] - Install {@link Adapter} to watch for the addition or removal of model elements to/from elements visible in this {@link AnnotationViewPartBase} (to trigger according updates). - Ensure that all annotations for all offspring of the currently selected are shown in the view - AnnotationViewPartBase no longer maintains a protected attribute with the list of current annotation entries, but triggers the abstract update(Collection<AnnotationEntry>) method at the right occasions (to be implemented by concrete views). - Possible improvement in GenericAnnotationView: efficient implementation of update(Collection<AnnotationEntry>) (instead of complete redraw). refs 1841 --- .../view/AnnotationViewPartBase.java | 130 ++++++++++++++++-- .../view/GenericAnnotationView.java | 53 ++++--- 2 files changed, 148 insertions(+), 35 deletions(-) diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationViewPartBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationViewPartBase.java index e92e42acd..d8ada35eb 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationViewPartBase.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/AnnotationViewPartBase.java @@ -17,9 +17,16 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.ui.annotation.view; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.impl.AdapterImpl; +import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.ISelectionListener; @@ -30,7 +37,9 @@ import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; import org.fortiss.tooling.base.ui.annotation.IAnnotationValueService; import org.fortiss.tooling.base.ui.editpart.DiagramEditPartBase; import org.fortiss.tooling.base.ui.editpart.ElementEditPartBase; +import org.fortiss.tooling.kernel.model.IProjectRootElement; import org.fortiss.tooling.kernel.ui.util.SelectionUtils; +import org.fortiss.tooling.kernel.utils.EcoreUtils; /** * This class provides a limited set of variables and methods to annotation views. Its main purposes @@ -47,8 +56,27 @@ public abstract class AnnotationViewPartBase extends ViewPart implements ISelect /** the currently selected object */ private IModelElement currentlySelectedObject; - /** List of all Annotation entries of the {@link #currentlySelectedObject} */ - protected List<AnnotationEntry> annotationEntryList = new ArrayList<AnnotationEntry>(); + /** + * Set of {@link IModelElement}s for which the {@link #changeListener} has been installed to + * watch for model changes (to trigger an update of this {@link AnnotationViewPartBase}). + */ + Set<IModelElement> watchedModelElements = new HashSet<IModelElement>(); + + /** + * {@link Adapter} to watch for the addition or removal of model elements to/from elements + * visible in this {@link AnnotationViewPartBase} (to trigger according updates). + */ + private final Adapter changeListener = new AdapterImpl() { + @Override + public void notifyChanged(Notification notification) { + if((notification.getEventType() == Notification.ADD) || + (notification.getEventType() == Notification.REMOVE)) { + if(notification.getNewValue() instanceof IModelElement) { + update((IModelElement)notification.getNewValue()); + } + } + } + }; /** {@inheritDoc} */ @Override @@ -59,19 +87,99 @@ public abstract class AnnotationViewPartBase extends ViewPart implements ISelect if(currentlySelectedObject == null) { ElementEditPartBase<?> editPart = SelectionUtils.checkAndPickFirst(selection, ElementEditPartBase.class); - if(editPart != null) + if(editPart != null) { currentlySelectedObject = (IModelElement)editPart.getModel(); - else { + } else { + // Not all editors are derived from ElementEditPartBase, most notably + // PlatformArchitectureDiagramEditPart DiagramEditPartBase<?> diagramPart = SelectionUtils.checkAndPickFirst(selection, DiagramEditPartBase.class); - if(diagramPart != null) + if(diagramPart != null) { currentlySelectedObject = (IModelElement)diagramPart.getModel(); + } } } + if(currentlySelectedObject != null) { + update(currentlySelectedObject); + } + } + + /** Update registration of model listeners. */ + private void updateChangeListener(Collection<AnnotationEntry> annotationEntryList) { + // Determine all root elements + Set<EObject> rootElements = new HashSet<EObject>(); + for(AnnotationEntry entry : annotationEntryList) { + EObject rootElement = entry.getModelElement(); + while(!(rootElement instanceof IProjectRootElement)) { + rootElement = rootElement.eContainer(); + } + rootElements.add(rootElement); + } + + // Determine all IModelElements below the current root elements + Set<IModelElement> currentWatchedModelElements = new HashSet<IModelElement>(); + for(EObject rootElement : rootElements) { + for(EObject modelElement : EcoreUtils.getChildrenWithType(rootElement, + IModelElement.class)) { + currentWatchedModelElements.add((IModelElement)modelElement); + } + if(rootElement instanceof IModelElement) { + currentWatchedModelElements.add((IModelElement)rootElement); + } + } + + // Add change listeners to IModelElements that are about to appear in the view + Set<IModelElement> tmpWatchedModelElements = + new HashSet<IModelElement>(currentWatchedModelElements); + tmpWatchedModelElements.removeAll(watchedModelElements); + for(EObject modelElement : tmpWatchedModelElements) { + modelElement.eAdapters().add(changeListener); + } + + // Remove change listeners IModelElements that are about to disappear from the view + tmpWatchedModelElements = new HashSet<IModelElement>(watchedModelElements); + tmpWatchedModelElements.removeAll(currentWatchedModelElements); + for(EObject modelElement : tmpWatchedModelElements) { + modelElement.eAdapters().remove(changeListener); + } - annotationEntryList = IAnnotationValueService.INSTANCE.getValues(currentlySelectedObject); + watchedModelElements = currentWatchedModelElements; } + /** + * Update the {@link AnnotationViewPartBase}: delegate update of concrete view to + * {@link #update(Collection)}, and update model change listeners. + */ + private void update(IModelElement modelElement) { + Set<AnnotationEntry> annotationEntries = + new TreeSet<AnnotationEntry>(new Comparator<AnnotationEntry>() { + /** Compare AnnotationEntries by the model element they refer to. */ + @Override + public int compare(AnnotationEntry a1, AnnotationEntry a2) { + // Equality of model element implies equal hashCode(), order is arbitrary + // but not relevant for + // ensuring uniqueness of annotation entries. + return Integer.compare(a1.getModelElement().hashCode(), a2 + .getModelElement().hashCode()); + } + }); + + // Collect all AnnotationEntries for the current model element and its offspring + annotationEntries.addAll(IAnnotationValueService.INSTANCE.getValues(modelElement)); + for(IModelElement childModelElement : EcoreUtils.getChildrenWithType(modelElement, + IModelElement.class)) { + annotationEntries.addAll(IAnnotationValueService.INSTANCE.getValues(childModelElement)); + } + + // Update the view + update(annotationEntries); + + updateChangeListener(annotationEntries); + } + + /** Update concrete view */ + protected abstract void update(Collection<AnnotationEntry> annotationEntries); + /** {@inheritDoc} */ @Override public void createPartControl(Composite parent) { @@ -87,6 +195,12 @@ public abstract class AnnotationViewPartBase extends ViewPart implements ISelect @Override public void dispose() { getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this); + + for(EObject modelElement : watchedModelElements) { + modelElement.eAdapters().remove(changeListener); + } + watchedModelElements.clear(); + super.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 48ceece4f..849e066b8 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 @@ -18,6 +18,7 @@ $Id$ package org.fortiss.tooling.base.ui.annotation.view; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +27,6 @@ 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; -import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; @@ -34,7 +34,6 @@ import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.IWorkbenchPart; import org.eclipse.wb.swt.SWTResourceManager; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.ui.annotation.AnnotationEntry; @@ -77,30 +76,14 @@ public class GenericAnnotationView extends AnnotationViewPartBase { /** {@inheritDoc} */ @Override - public void createPartControl(Composite parent) { - super.createPartControl(parent); - Composite c = new Composite(parent, SWT.NULL); - c.setLayout(new FillLayout(SWT.HORIZONTAL)); - - tableViewer = new TableViewer(c, SWT.BORDER | SWT.FULL_SELECTION); - Table table = tableViewer.getTable(); - table.setHeaderVisible(true); - table.setLinesVisible(true); - - createModelElementColumn(); - } - - /** {@inheritDoc} */ - @Override - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - super.selectionChanged(part, selection); - - createSingleInstanceAnnotationColumns(); - createMultiInstanceAnnotationColumns(); + protected void update(Collection<AnnotationEntry> annotationEntries) { + updateSingleInstanceAnnotationColumns(annotationEntries); + updateMultiInstanceAnnotationColumns(annotationEntries); } /** Create columns for ordinary (single instance) {@link IAnnotatedSpecification}s */ - private void createSingleInstanceAnnotationColumns() { + private void + updateSingleInstanceAnnotationColumns(Collection<AnnotationEntry> annotationEntries) { /* * disposes all columns of the table viewer, except the first column, which holds the names * of the model elements @@ -115,7 +98,7 @@ public class GenericAnnotationView extends AnnotationViewPartBase { * is no additional columns created for those specification which already have an associated * column or provide complex values. */ - for(AnnotationEntry entry : annotationEntryList) { + for(AnnotationEntry entry : annotationEntries) { for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { if(!isExistingColumn(spec) && !entry.allowsMultipleAnnoationInstances(spec.getClass())) { @@ -125,11 +108,12 @@ public class GenericAnnotationView extends AnnotationViewPartBase { } if(!tableViewer.getTable().isDisposed()) - tableViewer.setInput(annotationEntryList); + tableViewer.setInput(annotationEntries); } /** Create columns for multi-instance {@link IAnnotatedSpecification}s */ - private void createMultiInstanceAnnotationColumns() { + private void + updateMultiInstanceAnnotationColumns(Collection<AnnotationEntry> annotationEntries) { for(CreateAnnotationInstanceColumn col : createColumns) { col.dispose(); } @@ -144,7 +128,7 @@ public class GenericAnnotationView extends AnnotationViewPartBase { * 'code specsAllowingMultipleValues'. */ List<String> specClassNamesMult = new ArrayList<String>(); - for(AnnotationEntry entry : annotationEntryList) { + for(AnnotationEntry entry : annotationEntries) { for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { if(entry.allowsMultipleAnnoationInstances(spec.getClass()) && !specClassNamesMult.contains(spec.getClass().getSimpleName())) { @@ -182,6 +166,21 @@ public class GenericAnnotationView extends AnnotationViewPartBase { tableViewer.refresh(); } + /** {@inheritDoc} */ + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + Composite c = new Composite(parent, SWT.NULL); + c.setLayout(new FillLayout(SWT.HORIZONTAL)); + + tableViewer = new TableViewer(c, SWT.BORDER | SWT.FULL_SELECTION); + Table table = tableViewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + createModelElementColumn(); + } + /** Creates the (leading) column which displays the model elements */ protected void createModelElementColumn() { -- GitLab