From d5ef217841d863e4a040ac07b631b19b3202b9d8 Mon Sep 17 00:00:00 2001 From: Simon Barner <barner@fortiss.org> Date: Mon, 1 Sep 2014 11:43:02 +0000 Subject: [PATCH] - Sort columns alphabetically using a TreeSet of the newly introduced ColumnHandles. - Ensure that "Create" columns for dynamic multi-instance annotations are right to the corresponding instances. - Simplify column handling. Merge updateSingleInstanceAnnotationColumns() / updateMultiInstanceAnnotationColumns() into update() refs 1841 --- .../view/GenericAnnotationView.java | 281 ++++++++++++------ 1 file changed, 187 insertions(+), 94 deletions(-) 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 4f186af7f..a6cc52461 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 @@ -19,9 +19,9 @@ 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; +import java.util.Set; +import java.util.TreeSet; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.EditingSupport; @@ -55,10 +55,6 @@ import org.fortiss.tooling.base.ui.annotation.valueprovider.IAnnotationValueProv */ public class GenericAnnotationView extends AnnotationViewPartBase { - /** mapping of {@link IAnnotatedSpecification} -> TableViewerColumn */ - 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. @@ -66,104 +62,185 @@ public class GenericAnnotationView extends AnnotationViewPartBase { private List<CreateAnnotationInstanceColumn> createColumns = new ArrayList<CreateAnnotationInstanceColumn>(); + /** The table viewer */ + protected TableViewer tableViewer; + /** - * Map for associating those specifications that allow multiple values with their according - * AnnotationEntries. + * Character used to separte the annotation name from the instance name for multi-instance + * annotations. */ - private Map<IAnnotatedSpecification, AnnotationEntry> specsAllowingMultipleValues = - new HashMap<IAnnotatedSpecification, AnnotationEntry>(); + private final static String MULTIINSTANCE_NAME_SEPARATOR = ":"; - /** The table viewer */ - protected TableViewer tableViewer; + /** + * Data required to identify a column displaying a particular {@link IAnnotatedSpecification} in + * a column of the {@link GenericAnnotationView}. Used to sort columns (see + * {@link #compareTo(ColumnHandle)}). + */ + private class ColumnHandle implements Comparable<ColumnHandle> { + /** + * {@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; + + /** + * Instance key identifying the particular instance of an {@link IAnnotatedSpecification} + * from {@code entry} to be displayed in the column represented by this {@link ColumnHandle} + * . + */ + private String instanceKey; + + /** Flag if this {@link ColumnHandle} represents a {@link CreateAnnotationInstanceColumn}. */ + private boolean isCreateColumn; + + /** Constructs a new {@link ColumnHandle}. */ + public ColumnHandle(AnnotationEntry entry, IAnnotatedSpecification annotatedSpecification, + String instanceKey, boolean isCreateColumn) { + + this.entry = entry; + this.annotatedSpecification = annotatedSpecification; + this.instanceKey = 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 the instance key identifying the particular instance of an + * {@link IAnnotatedSpecification} from {@code entry} to be displayed in the column + * represented by this {@link ColumnHandle} . + */ + public String getInstanceKey() { + return instanceKey; + } + + /** + * Returns a flag if this {@link ColumnHandle} represents a + * {@link CreateAnnotationInstanceColumn}. + */ + public boolean isCreateColumn() { + return isCreateColumn; + } + + /** {@inheritDoc} */ + @Override + public int compareTo(ColumnHandle other) { + String columnName = getColumnName(this); + String annotationName; + + int columnNameSeparatorIndex = columnName.indexOf(MULTIINSTANCE_NAME_SEPARATOR); + if(columnNameSeparatorIndex != -1) { + annotationName = columnName.substring(0, columnNameSeparatorIndex); + } else { + annotationName = columnName; + } + + String otherColumnName = getColumnName(other); + String otherAnnotationName; + int otherColumnNameSeparatorIndex = + otherColumnName.indexOf(MULTIINSTANCE_NAME_SEPARATOR); + if(otherColumnNameSeparatorIndex != -1) { + otherAnnotationName = otherColumnName.substring(0, otherColumnNameSeparatorIndex); + } else { + otherAnnotationName = otherColumnName; + } + + // Place "create" columns (label: "<specification name>") after their instances + // (which are labeled "<specification name>: <instance name>"). + if(annotationName.equals(otherAnnotationName)) { + // Ensure uniqueness of "create" columns" + if(isCreateColumn && other.isCreateColumn) { + return 0; + } + if(isCreateColumn) { + return 1; + } + if(other.isCreateColumn) { + return -1; + } + } + + // Sort alphabetically by specification column label + return columnName.compareTo(otherColumnName); + } + } /** {@inheritDoc} */ @Override protected void update(Collection<AnnotationEntry> annotationEntries) { - updateSingleInstanceAnnotationColumns(annotationEntries); - updateMultiInstanceAnnotationColumns(annotationEntries); - } + /* + * Sorted set of {@link ColumnHandle} used to instantiate this {@link + * GenericAnnotationView}'s columns in the right order. + */ + Set<ColumnHandle> sortedColumnHandles = new TreeSet<ColumnHandle>(); - /** Create columns for ordinary (single instance) {@link IAnnotatedSpecification}s */ - private void - updateSingleInstanceAnnotationColumns(Collection<AnnotationEntry> annotationEntries) { /* - * disposes all columns of the table viewer, except the first column, which holds the names + * Dispose 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(); } - annotationSpecColumns.clear(); - - /* - * Create a column for each annotation specification provided by any AnnotationEntry. There - * is no additional columns created for those specification which already have an associated - * column or provide complex values. - */ - for(AnnotationEntry entry : annotationEntries) { - for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { - if(!isExistingColumn(spec) && - !entry.allowsDynamicAnnotationInstances(spec.getClass()) && - entry.getInstanceKeys(spec.getClass()).isEmpty()) { - createAnnotationColumn(entry, spec, null); - } - } - } - if(!tableViewer.getTable().isDisposed()) - tableViewer.setInput(annotationEntries); - } - - /** Create columns for multi-instance {@link IAnnotatedSpecification}s */ - private void - updateMultiInstanceAnnotationColumns(Collection<AnnotationEntry> annotationEntries) { 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>(); + // Aggregate required columns. Column order is defined by ColumnHandle.compareTo(). for(AnnotationEntry entry : annotationEntries) { for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { - if((!entry.getInstanceKeys(spec.getClass()).isEmpty() || entry - .allowsDynamicAnnotationInstances(spec.getClass())) && - !specClassNamesMult.contains(spec.getClass().getSimpleName())) { - specsAllowingMultipleValues.put(spec, entry); - specClassNamesMult.add(spec.getClass().getSimpleName()); - } - } - } + // Create new column for each instance of the current multi-instance annotation + if((entry.allowsDynamicAnnotationInstances(spec.getClass())) || + !entry.getInstanceKeys(spec.getClass()).isEmpty()) { - // Iterate over all specification supporting multiple values. - for(IAnnotatedSpecification spec : specsAllowingMultipleValues.keySet().toArray( - new IAnnotatedSpecification[specsAllowingMultipleValues.keySet().size()])) { - AnnotationEntry entry = specsAllowingMultipleValues.get(spec); + for(String instanceKey : entry.getInstanceKeys(spec.getClass())) { + sortedColumnHandles.add(new ColumnHandle(entry, spec, instanceKey, false)); + } + } - // Create new column for each instance of the current multi-instance annotation - for(String key : entry.getInstanceKeys(spec.getClass())) { - createAnnotationColumn(entry, spec, key); - } + // Create a new column for + // - ordinary (single-instance) annotations + // - "create" column for multi-instance annotations for which instances can be + // created dynamically + if(entry.getInstanceKeys(spec.getClass()).isEmpty() || + entry.allowsDynamicAnnotationInstances(spec.getClass())) { + sortedColumnHandles.add(new ColumnHandle(entry, spec, null, entry + .allowsDynamicAnnotationInstances(spec.getClass()))); - if(entry.allowsDynamicAnnotationInstances(spec.getClass())) { - // 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); + } } + } + // Instantiate columns + for(ColumnHandle columnHandle : sortedColumnHandles) { + createAnnotationColumn(columnHandle); } - // Refresh table to trigger the update method of the create columns in order to actually - // instantiate the "Create" buttons + // Register content provider + if(!tableViewer.getTable().isDisposed()) { + tableViewer.setInput(annotationEntries); + } tableViewer.refresh(); } @@ -195,42 +272,58 @@ public class GenericAnnotationView extends AnnotationViewPartBase { } /** Creates a column in tableViewer that displays the annotation given in spec */ - protected void createAnnotationColumn(AnnotationEntry entry, IAnnotatedSpecification spec, - String instanceKey) { - - // Determine column name - String specName = entry.getSpecificationAnnotationName(spec.getClass()); - if(specName == null || specName.isEmpty()) { - specName = "<Unnamed Annotation>"; + protected void createAnnotationColumn(ColumnHandle columnHandle) { + + if(columnHandle.isCreateColumn()) { + // Create column that contains a button for adding new instances of the + // current annotation type. + createColumns.add(new CreateAnnotationInstanceColumn(tableViewer, SWT.NONE, + columnHandle.getAnnotatedSpecification(), columnHandle.getEntry())); + (createColumns.get(createColumns.size() - 1)).getColumn().setWidth(125); + return; } - if(instanceKey != null) { - specName += ": " + instanceKey; - } + String specName = getColumnName(columnHandle); // Add new new column TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE); column.getColumn().setText(specName); + Class<? extends IAnnotatedSpecification> annotationClass = + columnHandle.getAnnotatedSpecification().getClass(); + 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(), instanceKey); + columnHandle.getEntry().createSpecificationEditElement(tableViewer, + annotationClass, columnHandle.getInstanceKey()); // Add column label provider, and set EditingSupport - column.setLabelProvider(new AnnotationLabelProvider(spec.getClass(), this, instanceKey)); + column.setLabelProvider(new AnnotationLabelProvider(annotationClass, this, columnHandle + .getInstanceKey())); column.setEditingSupport(editingSupport); } - /** Checks if column for given specification already exists */ - protected boolean isExistingColumn(IAnnotatedSpecification specification) { - if(annotationSpecColumns.containsKey(specification.getClass())) - return true; - return false; + /** + * Returns the name of a column for a given {@link IAnnotatedSpecification} represented by the + * given {@link ColumnHandle}. + */ + protected String getColumnName(ColumnHandle columnHandle) { + // Determine column name + String specName = + columnHandle.getEntry().getSpecificationAnnotationName( + columnHandle.getAnnotatedSpecification().getClass()); + if(specName == null || specName.isEmpty()) { + specName = "<Unnamed Annotation>"; + } + + if(columnHandle.getInstanceKey() != null) { + specName += MULTIINSTANCE_NAME_SEPARATOR + " " + columnHandle.getInstanceKey(); + } + return specName; } /** {@inheritDoc} */ -- GitLab