From 199c8154316016aa1a22c2b909b957b809c517b4 Mon Sep 17 00:00:00 2001 From: Andreas Bayha <bayha@fortiss.org> Date: Wed, 22 Jul 2020 15:03:19 +0200 Subject: [PATCH] Annotations: Improved code - The filter is now better integrated with the content provider. - Javadoc comments. Issue-Ref: 4014 Issue-Url: https://af3-developer.fortiss.org/issues/4014 Signed-off-by: Andreas Bayha <bayha@fortiss.org> --- .../annotation/view/fx/AnnotationViewFx.fxml | 9 +- .../base/ui/annotation/view/fx/.ratings | 4 +- .../view/fx/AnnotationViewFXController.java | 290 ++++++++++-------- ...=> FXAnnotationFilterContentProvider.java} | 103 +++++-- 4 files changed, 234 insertions(+), 172 deletions(-) rename org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/{FXAnnotationFilter.java => FXAnnotationFilterContentProvider.java} (72%) diff --git a/org.fortiss.tooling.base.ui/res/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFx.fxml b/org.fortiss.tooling.base.ui/res/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFx.fxml index 7e318bd67..10a7f77d9 100644 --- a/org.fortiss.tooling.base.ui/res/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFx.fxml +++ b/org.fortiss.tooling.base.ui/res/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFx.fxml @@ -6,7 +6,6 @@ <?import javafx.scene.control.RadioButton?> <?import javafx.scene.control.SplitPane?> <?import javafx.scene.control.TextField?> -<?import javafx.scene.control.ToggleGroup?> <?import javafx.scene.control.TreeTableView?> <?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.HBox?> @@ -27,12 +26,8 @@ <HBox prefHeight="40.0" prefWidth="148.0" spacing="5.0"> <children> <Label minHeight="20.0" text="Filter:" /> - <RadioButton fx:id="radBtnFilterModelElements" minHeight="20.0" mnemonicParsing="false" text="model elements"> - <toggleGroup> - <ToggleGroup fx:id="filterGroup" /> - </toggleGroup> - </RadioButton> - <RadioButton fx:id="radBtnFilterAnnotationNames" minHeight="20.0" mnemonicParsing="false" text="annotation names:" toggleGroup="$filterGroup" /> + <RadioButton fx:id="radBtnFilterModelElements" minHeight="20.0" mnemonicParsing="false" text="model elements" /> + <RadioButton fx:id="radBtnFilterAnnotationNames" minHeight="20.0" mnemonicParsing="false" text="annotation names:" /> <CheckBox fx:id="chkBoxMatchCase" mnemonicParsing="false" text="match case" /> </children> </HBox> diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/.ratings b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/.ratings index 53fade13b..649d4f77a 100644 --- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/.ratings +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/.ratings @@ -1,3 +1,3 @@ AnnotationFxViewPart.java 34c845f7162a8a8bb680df6ee08160ce63a5a5a3 YELLOW -AnnotationViewFXController.java 50e745f4f700b165c3d138d9f9cd2463252da31d RED -FXAnnotationFilter.java 05bc78a530becbce573545d67e5b0ef9ac3f697f YELLOW +AnnotationViewFXController.java 00c64dbad1bd9ae071360ebe3d071705c8d2a68c YELLOW +FXAnnotationFilterContentProvider.java 6c92d9c96fb2a2441256f70e20a20b1287018a9f YELLOW diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFXController.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFXController.java index 50e745f4f..00c64dbad 100644 --- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFXController.java +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/AnnotationViewFXController.java @@ -17,16 +17,15 @@ package org.fortiss.tooling.base.ui.annotation.view.fx; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; -import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilter.HIERARCHY_LEVELS_ALL; -import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilter.HIERARCHY_LEVELS_CURRENT; -import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilter.HIERARCHY_LEVELS_SELECTED_SUBMODEL; +import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilterContentProvider.HIERARCHY_LEVELS_ALL; +import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilterContentProvider.HIERARCHY_LEVELS_CURRENT; +import static org.fortiss.tooling.base.ui.annotation.view.fx.FXAnnotationFilterContentProvider.HIERARCHY_LEVELS_SELECTED_SUBMODEL; import static org.fortiss.tooling.kernel.ui.util.SelectionUtils.checkAndPickFirst; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getChildrenWithType; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstParentWithType; import static org.fortiss.tooling.kernel.utils.LoggingUtils.showWarning; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -52,7 +51,6 @@ import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.model.element.IModelElement; import org.fortiss.tooling.base.ui.annotation.view.generic.ColumnHandle; import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTextFieldTreeTableCell; -import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeContentProviderBase; import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeTableUIProviderBase; import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeTableViewer; import org.fortiss.tooling.common.ui.javafx.layout.CompositeFXControllerBase; @@ -61,6 +59,8 @@ import org.fortiss.tooling.kernel.model.INamedCommentedElement; import org.fortiss.tooling.kernel.model.IProjectRootElement; import org.fortiss.tooling.kernel.service.IPersistencyService; +import com.sun.webkit.ThemeClient; + import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.Node; @@ -74,6 +74,7 @@ import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableView; /** + * Controller for the Annotations view. * * @author bayha */ @@ -81,56 +82,76 @@ import javafx.scene.control.TreeTableView; public class AnnotationViewFXController extends CompositeFXControllerBase<SplitPane, Node> implements ISelectionListener { + /** Option text for the annotation type filter combo box. */ private static final String SHOW_ALL_ANNOTATION_TYPES = "Show all annotation types"; + /** {@link TextField} for entering the filter pattern. */ @FXML TextField txtFilterText; + /** {@link RadioButton} to enable filtering for model element names. */ @FXML RadioButton radBtnFilterModelElements; + /** {@link RadioButton} to enable filtering for annotation names. */ @FXML RadioButton radBtnFilterAnnotationNames; + /** {@link CheckBox} to make name filtering case sensitive. */ @FXML CheckBox chkBoxMatchCase; + /** {@link CheckBox} to only show model elements with the same type as the selected one. */ @FXML CheckBox chkBoxselectedTypeOnly; + /** + * {@link ComboBox} to chose the hierarchy option according to which the modele elements are + * displayed. + */ @FXML ComboBox<String> comboHierarchy; + /** {@link ComboBox} to chose an annotation type to be displayed exclusively. */ @FXML ComboBox<String> comboAnnotationType; - /** */ + /** The {@link TreeTableView} for the annotation table. */ @FXML private TreeTableView<AnnotationEntry> annotationTreeTableView; - /** */ + /** The {@link DynamicTreeTableViewer} to manage the annotationTreeTableView. */ private DynamicTreeTableViewer<AnnotationEntry> annotationViewer; - /** */ + /** The {@link IProjectRootElement} in which the selected element is contained in. */ private IProjectRootElement curentRootElement; + /** The {@link IModelElement} that is currently selected by the user. */ IModelElement selected; - private FXAnnotationFilter filter = new FXAnnotationFilter(); - + /** {@link Set} of {@link ColumnHandle}s (i.e. management objects for columns). */ private Set<ColumnHandle<IAnnotatedSpecification>> columnHandles = new TreeSet<>(); - private Map<ColumnHandle<IAnnotatedSpecification>, TreeTableColumn<AnnotationEntry, ?>> columnHandleToColumn = new HashMap<ColumnHandle<IAnnotatedSpecification>, TreeTableColumn<AnnotationEntry, ?>>(); + /** + * {@link Map} that maps {@link ColumnHandle}s (i.e. management objects for columns) to the + * respective columns. + */ + private Map<ColumnHandle<IAnnotatedSpecification>, TreeTableColumn<AnnotationEntry, ?>> columnHandleToColumn = + new HashMap<ColumnHandle<IAnnotatedSpecification>, TreeTableColumn<AnnotationEntry, ?>>(); - private Map<String, IAnnotatedSpecification> colNameToSpecification = new HashMap<String, IAnnotatedSpecification>(); + /** {@link Map} to get the {@link IAnnotatedSpecification} that corresponds to a column name. */ + private Map<String, IAnnotatedSpecification> colNameToSpecification = + new HashMap<String, IAnnotatedSpecification>(); - DynamicTreeContentProviderBase<AnnotationEntry> contentProvider; + /** Content provider for the annotation table with all filtering functionality. */ + FXAnnotationFilterContentProvider filterContentProvider = + new FXAnnotationFilterContentProvider(); /** * Associates the handles of the annotations with their ordered column indexes. * Used for the UI providers of cell items. */ - Map<Integer, ColumnHandle<IAnnotatedSpecification>> colIdxAnnotationMap = new HashMap<>();; + Map<Integer, ColumnHandle<IAnnotatedSpecification>> colIdxAnnotationMap = new HashMap<>(); /** {@inheritDoc} */ @Override @@ -149,18 +170,18 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP public void selectionChanged(IWorkbenchPart part, ISelection selection) { EObject selected = checkAndPickFirst(selection, EObject.class); - if (selected == null) { + if(selected == null) { clearTableViewer(); return; } - if (selected instanceof IProjectRootElement) { - curentRootElement = (IProjectRootElement) selected; + if(selected instanceof IProjectRootElement) { + curentRootElement = (IProjectRootElement)selected; } else { curentRootElement = getFirstParentWithType(selected, IProjectRootElement.class); } - if (curentRootElement == null) { + if(curentRootElement == null) { // There was no root element for the selected element. (Usually should be the // FileProject.) This is not displayed here. clearTableViewer(); @@ -168,9 +189,9 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP return; } - if (selected instanceof IModelElement) { - filter.setCurrentySelectedModelElement((IModelElement) selected); - this.selected = (IModelElement) selected; + if(selected instanceof IModelElement) { + filterContentProvider.setCurrentySelectedModelElement((IModelElement)selected); + this.selected = (IModelElement)selected; } setupAnnotationTree(); @@ -180,7 +201,8 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP ObservableList<String> annotationTypeOptions = comboAnnotationType.getItems(); annotationTypeOptions.clear(); annotationTypeOptions.add(SHOW_ALL_ANNOTATION_TYPES); - List<String> annotations = columnHandles.stream().map(h -> h.getColumnName()).collect(toList()); + List<String> annotations = + columnHandles.stream().map(h -> h.getColumnName()).collect(toList()); annotationTypeOptions.addAll(annotations); comboAnnotationType.setValue(SHOW_ALL_ANNOTATION_TYPES); } @@ -190,34 +212,36 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP * selectedElement. */ private void setupAnnotationTree() { - if (curentRootElement == null) { + if(curentRootElement == null) { return; } clearTableViewer(); // Collect the annotation entries for all elements. - EList<IModelElement> childElements = getChildrenWithType(curentRootElement, IModelElement.class); + EList<IModelElement> childElements = + getChildrenWithType(curentRootElement, IModelElement.class); ArtificialRoot rootElement = new ArtificialRoot(); - for (IModelElement elem : childElements) { + for(IModelElement elem : childElements) { AnnotationEntry entry = IAnnotationValueService.getInstance().getAnnotationEntry(elem); - if (entry != null && !entry.getSpecificationsList().isEmpty()) { + if(entry != null && !entry.getSpecificationsList().isEmpty()) { rootElement.elements.add(entry); } } Set<AnnotationEntry> annotationEntries = new HashSet<>(); - childElements.forEach(e -> annotationEntries.add(AnnotationValueService.getInstance().getAnnotationEntry(e))); + childElements.forEach(e -> annotationEntries + .add(AnnotationValueService.getInstance().getAnnotationEntry(e))); // Aggregate required columns. Column order is defined by // ColumnHandle.compareTo(). - for (AnnotationEntry entry : annotationEntries) { - for (IAnnotatedSpecification spec : entry.getSpecificationsList()) { - ColumnHandle<IAnnotatedSpecification> columnHandle = new ColumnHandle<IAnnotatedSpecification>(entry, - spec); + for(AnnotationEntry entry : annotationEntries) { + for(IAnnotatedSpecification spec : entry.getSpecificationsList()) { + ColumnHandle<IAnnotatedSpecification> columnHandle = + new ColumnHandle<IAnnotatedSpecification>(entry, spec); columnHandles.add(columnHandle); colNameToSpecification.put(columnHandle.getColumnName(), spec); } @@ -226,16 +250,17 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP // The DynamicTreeTableViewer needs to be created new, as the root is different. boolean showRoot = false; int revealLevel = 1; - DynamicTreeTableUIProviderBase<AnnotationEntry> uiProvider = new AnnotationTreeTableUIProvider(); - contentProvider = new AnnotationTableContentProvider(); - annotationViewer = new DynamicTreeTableViewer<AnnotationEntry>(annotationTreeTableView, rootElement, showRoot, - revealLevel, contentProvider, uiProvider); + DynamicTreeTableUIProviderBase<AnnotationEntry> uiProvider = + new AnnotationTreeTableUIProvider(); + + annotationViewer = new DynamicTreeTableViewer<AnnotationEntry>(annotationTreeTableView, + rootElement, showRoot, revealLevel, filterContentProvider, uiProvider); annotationViewer.addColumn("Model Element", 200); annotationViewer.addColumn("Comment", 250); int columnIdx = 2; - for (ColumnHandle<IAnnotatedSpecification> handle : columnHandles) { + for(ColumnHandle<IAnnotatedSpecification> handle : columnHandles) { TreeTableColumn<AnnotationEntry, ?> col = createColumnForHandle(columnIdx, handle); columnHandleToColumn.put(handle, col); @@ -244,6 +269,7 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP filterColumns(); } + /** Resets {@link ThemeClient} annotation table to be empty. Also removes the columns. */ private void clearTableViewer() { colIdxAnnotationMap.clear(); columnHandles.clear(); @@ -252,10 +278,11 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP annotationTreeTableView.setRoot(null); } + /** Configures the filter widgets for the annotation table. */ private void setupFilterWidgets() { comboAnnotationType.getItems().add(SHOW_ALL_ANNOTATION_TYPES); comboAnnotationType.setValue(SHOW_ALL_ANNOTATION_TYPES); - + ObservableList<String> hierarchyLevels = comboHierarchy.getItems(); hierarchyLevels.clear(); hierarchyLevels.add(HIERARCHY_LEVELS_ALL); @@ -264,21 +291,21 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP comboHierarchy.setValue(HIERARCHY_LEVELS_ALL); comboHierarchy.valueProperty().addListener((obs, oVal, nVal) -> { - filter.setHierarchyLevelFilter(nVal); + filterContentProvider.setHierarchyLevelFilter(nVal); updateAnnotationTree(); }); comboAnnotationType.valueProperty().addListener((obs, oVal, nVal) -> { - filter.setHierarchyLevelFilter(nVal); + filterContentProvider.setHierarchyLevelFilter(nVal); updateAnnotationTree(); }); txtFilterText.textProperty().addListener((obs, oVal, nVal) -> { - filter.setNameFilterPattern(nVal); + filterContentProvider.setFilterExpression(nVal); - if (radBtnFilterAnnotationNames.isSelected()) { + if(radBtnFilterAnnotationNames.isSelected()) { filterColumns(); } @@ -286,23 +313,33 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP }); radBtnFilterAnnotationNames.selectedProperty().addListener((obs, oVal, nVal) -> { - filter.setFilterColumnName(nVal); + filterContentProvider.setFilterColumnName(nVal); filterColumns(); + if(nVal) { + // De-select other radio button, if this one is selected. + radBtnFilterModelElements.setSelected(false); + } + updateAnnotationTree(); }); radBtnFilterModelElements.selectedProperty().addListener((obs, oVal, nVal) -> { - filter.setFilterRowName(nVal); + filterContentProvider.setFilterRowName(nVal); + + if(nVal) { + // De-select other radio button, if this one is selected. + radBtnFilterAnnotationNames.setSelected(false); + } updateAnnotationTree(); }); chkBoxMatchCase.selectedProperty().addListener((obs, oVal, nVal) -> { - filter.setFilterNameMatchCase(nVal); + filterContentProvider.setFilterNameMatchCase(nVal); - if (radBtnFilterAnnotationNames.isSelected()) { + if(radBtnFilterAnnotationNames.isSelected()) { filterColumns(); } @@ -310,18 +347,18 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP }); chkBoxselectedTypeOnly.selectedProperty().addListener((obs, oVal, nVal) -> { - filter.setRestrictToSelectedModelElementType(nVal); + filterContentProvider.setRestrictToSelectedModelElementType(nVal); updateAnnotationTree(); }); comboAnnotationType.valueProperty().addListener((obs, oVal, nVal) -> { IAnnotatedSpecification selectedSpec = colNameToSpecification.get(nVal); - if (selectedSpec != null) { - filter.setAnnotationTypeFilter(selectedSpec.getClass()); + if(selectedSpec != null) { + filterContentProvider.setAnnotationTypeFilter(selectedSpec.getClass()); } else { // In this case, the filter has been reset to "All Types" - filter.setAnnotationTypeFilter(null); + filterContentProvider.setAnnotationTypeFilter(null); } filterColumns(); @@ -329,15 +366,20 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP }); } + /** + * Triggers the update the annotation tree with the latest filter settings and model element + * changes. + */ private void updateAnnotationTree() { annotationViewer.update(); annotationViewer.expandAllItems(); } + /** Hides columns which are de-selected by the current filter settings. */ private void filterColumns() { - for (ColumnHandle<IAnnotatedSpecification> c : columnHandles) { + for(ColumnHandle<IAnnotatedSpecification> c : columnHandles) { TreeTableColumn<AnnotationEntry, ?> col = columnHandleToColumn.get(c); - col.setVisible(filter.passesColumnFilter(c)); + col.setVisible(filterContentProvider.passesColumnFilter(c)); } updateAnnotationTree(); @@ -346,13 +388,14 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP /** Creates the annotation column for the given handle. */ private TreeTableColumn<AnnotationEntry, ?> createColumnForHandle(int columnIdx, ColumnHandle<IAnnotatedSpecification> handle) { - Class<IAnnotatedSpecification> annotationClass = (Class<IAnnotatedSpecification>) handle - .getAnnotatedSpecification().getClass(); + Class<IAnnotatedSpecification> annotationClass = + (Class<IAnnotatedSpecification>)handle.getAnnotatedSpecification().getClass(); AnnotationEntry entry = handle.getEntry(); - IAnnotationValueProvider<IAnnotatedSpecification> valueProvider = entry - .getAnnotationValueProvider(annotationClass); + IAnnotationValueProvider<IAnnotatedSpecification> valueProvider = + entry.getAnnotationValueProvider(annotationClass); IAnnotatedSpecification specification = entry.getSpecification(annotationClass); - EClassifier valueType = valueProvider.getEStructuralFeatureDescriptor().getEType(specification); + EClassifier valueType = + valueProvider.getEStructuralFeatureDescriptor().getEType(specification); String columnName = valueProvider.getAnnotationName(specification); @@ -361,51 +404,60 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP TreeTableColumn<AnnotationEntry, String> column = null; // Case distinction for the cell factory depending on the type to be edited. - if (valueType == null) { + if(valueType == null) { column = annotationViewer.addColumn(columnName, 150); column.setEditable(false); return column; - } else if (valueType instanceof EEnum) { + } else if(valueType instanceof EEnum) { // Add a combo column for enumerations. column = annotationViewer.addComboColumn(columnName, 150, rowEntry -> { - ValueProviderBase<IAnnotatedSpecification> annotationValueProvider = (ValueProviderBase<IAnnotatedSpecification>) rowEntry - .getAnnotationValueProvider(annotationClass); - EStructuralFeatureDescriptor structuralFeature = annotationValueProvider - .getEStructuralFeatureDescriptor(); - EClassifier type = structuralFeature.getEType(rowEntry.getSpecification(annotationClass)); + ValueProviderBase<IAnnotatedSpecification> annotationValueProvider = + (ValueProviderBase<IAnnotatedSpecification>)rowEntry + .getAnnotationValueProvider(annotationClass); + EStructuralFeatureDescriptor structuralFeature = + annotationValueProvider.getEStructuralFeatureDescriptor(); + EClassifier type = + structuralFeature.getEType(rowEntry.getSpecification(annotationClass)); // Get the enum literals again, as it might be different for each row. - if (type instanceof EEnum) { - EList<EEnumLiteral> allLiterals = ((EEnum) type).getELiterals(); + if(type instanceof EEnum) { + EList<EEnumLiteral> allLiterals = ((EEnum)type).getELiterals(); return allLiterals.stream().map(l -> l.getLiteral()).collect(toList()); } return emptyList(); }); - } else if (valueType.getInstanceClass().equals(Boolean.class)) { + } else if(valueType.getInstanceClass().equals(Boolean.class)) { // Use a checkbox column for booleans annotationViewer.addCheckboxColumn(columnName, 100); } else { // For all other types, there is text editing. column = annotationViewer.addColumn(columnName, 150); column.setCellFactory(ttColumn -> new DynamicTextFieldTreeTableCell<AnnotationEntry>() { + /** {@inheritDoc} */ + @Override protected boolean canEdit(AnnotationEntry element) { // We start editing only, if this cell is supposed to be editable. - IAnnotationValueProvider<IAnnotatedSpecification> annotationValueProvider = element - .getAnnotationValueProvider(annotationClass); - IAnnotatedSpecification currentSpecification = element.getSpecification(annotationClass); - return annotationValueProvider != null && annotationValueProvider.canEdit(currentSpecification); + IAnnotationValueProvider<IAnnotatedSpecification> annotationValueProvider = + element.getAnnotationValueProvider(annotationClass); + IAnnotatedSpecification currentSpecification = + element.getSpecification(annotationClass); + return annotationValueProvider != null && + annotationValueProvider.canEdit(currentSpecification); } + /** {@inheritDoc} */ + @Override protected void setValueOnLeavingCell(AnnotationEntry element, String currentValue) { - IAnnotatedSpecification specification = element.getSpecification(annotationClass); + IAnnotatedSpecification specification = + element.getSpecification(annotationClass); setAnnotationEntryValue(specification, element, currentValue); } }); } - if (column != null) { + if(column != null) { column.setEditable(true); column.setOnEditCommit(event -> { @@ -424,23 +476,25 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP * Local helper to set the given newValue for the given annotationEntry and * specification. */ - private void setAnnotationEntryValue(IAnnotatedSpecification specification, AnnotationEntry annotationEntry, - String newValue) { - ITopLevelElement tle = IPersistencyService.getInstance().getTopLevelElementFor(curentRootElement); + private void setAnnotationEntryValue(IAnnotatedSpecification specification, + AnnotationEntry annotationEntry, String newValue) { + ITopLevelElement tle = + IPersistencyService.getInstance().getTopLevelElementFor(curentRootElement); tle.runAsCommand(() -> { try { annotationEntry.setSpecificationValue(newValue, specification.getClass()); - } catch (Exception e1) { + } catch(Exception e1) { showWarning("Problem during setting an AnnotationValue: \n" + e1.getStackTrace()); } }); } - private String getAnnotationEntryName(AnnotationEntry entry) { + /** Retrieves the model element name to be displayed for the given {@link AnnotationEntry}. */ + private String getNameForAnnotationEntry(AnnotationEntry entry) { IModelElement modelElement = entry.getModelElement(); - if (modelElement instanceof INamedCommentedElement) { - return ((INamedCommentedElement) modelElement).getName(); + if(modelElement instanceof INamedCommentedElement) { + return ((INamedCommentedElement)modelElement).getName(); } return ""; } @@ -448,78 +502,42 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP /** * UIProvider for the Annotation TreeTable. */ - protected class AnnotationTreeTableUIProvider extends DynamicTreeTableUIProviderBase<AnnotationEntry> { + private class AnnotationTreeTableUIProvider + extends DynamicTreeTableUIProviderBase<AnnotationEntry> { /** {@inheritDoc} */ @Override public String getLabel(AnnotationEntry entry, int column) { IModelElement element = entry.getModelElement(); - switch (column) { - case 0: - return getAnnotationEntryName(entry); - case 1: - if (element instanceof INamedCommentedElement) { - return ((INamedCommentedElement) element).getComment(); - } - return ""; - default: - IAnnotatedSpecification columnSpec = colIdxAnnotationMap.get(column).getAnnotatedSpecification(); - - Object specificationValue = entry.getSpecificationValue(columnSpec.getClass()); - if (specificationValue != null) { - return specificationValue.toString(); - } - - return ""; + switch(column) { + case 0: + return getNameForAnnotationEntry(entry); + case 1: + if(element instanceof INamedCommentedElement) { + return ((INamedCommentedElement)element).getComment(); + } + return ""; + default: + IAnnotatedSpecification columnSpec = + colIdxAnnotationMap.get(column).getAnnotatedSpecification(); + + Object specificationValue = entry.getSpecificationValue(columnSpec.getClass()); + if(specificationValue != null) { + return specificationValue.toString(); + } + + return ""; } } } - /** - * Content provider, that can deal with the {@link ArtificialRoot}. - * - * The tree under this root has only one layer. - */ - protected class AnnotationTableContentProvider extends DynamicTreeContentProviderBase<AnnotationEntry> { - - /** Constructor */ - public AnnotationTableContentProvider() { - // Initializes the filterExpressino to be non empty. - super.setFilterExpression("*"); - } - - /** {@inheritDoc} */ - @Override - protected Collection<? extends AnnotationEntry> getChildren(AnnotationEntry parent) { - if (parent instanceof ArtificialRoot) { - return ((ArtificialRoot) parent).elements; - } - - return emptyList(); - } - - /** {@inheritDoc} */ - @Override - protected boolean filter(AnnotationEntry entry, String filterValue) { - return filter.passesRowFilter(entry); - } - - /** {@inheritDoc} */ - @Override - public void setFilterExpression(String filterExpression) { - throw new UnsupportedOperationException( - "The AnnotationTableContentProvider class does not use the build in filter expression. " - + "This set operation would not have any effect."); - } - } - /** * Local class to represent the invisible root for the tree table. * * The only thing relevant here, is the {@link List} 'elements'. */ - private class ArtificialRoot extends AnnotationEntry { + protected class ArtificialRoot extends AnnotationEntry { /** * Constructor. diff --git a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilter.java b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilterContentProvider.java similarity index 72% rename from org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilter.java rename to org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilterContentProvider.java index 05bc78a53..6c92d9c96 100644 --- a/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilter.java +++ b/org.fortiss.tooling.base.ui/src/org/fortiss/tooling/base/ui/annotation/view/fx/FXAnnotationFilterContentProvider.java @@ -15,11 +15,13 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.ui.annotation.view.fx; +import static java.util.Collections.emptyList; import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.DOTALL; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getModelElementAncestor; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getModelElementLevel; +import java.util.Collection; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -27,21 +29,25 @@ import org.eclipse.emf.ecore.EObject; import org.fortiss.tooling.base.annotation.AnnotationEntry; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.model.element.IModelElement; +import org.fortiss.tooling.base.ui.annotation.view.fx.AnnotationViewFXController.ArtificialRoot; import org.fortiss.tooling.base.ui.annotation.view.generic.ColumnHandle; +import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeContentProviderBase; import org.fortiss.tooling.kernel.model.INamedElement; import org.fortiss.tooling.kernel.model.IProjectRootElement; /** - * Row and column filter for the {@link AnnotationViewFXController}. + * Content provider with row and column filter for the {@link AnnotationViewFXController}. * <ul> - * {@link FXAnnotationFilter#passesColumnFilter(ColumnHandle)} that is evaluated - * during the update of the {@link AnnotationViewFXController}.</li> + * {@link FXAnnotationFilterContentProvider#passesColumnFilter(ColumnHandle)} + * that is evaluated during the update of the + * {@link AnnotationViewFXController}.</li> * </ul> * * @author barner * @author bayha */ -public class FXAnnotationFilter { +public class FXAnnotationFilterContentProvider + extends DynamicTreeContentProviderBase<AnnotationEntry> { /** Filter hint text. */ static final String FILTER_HINT_TEXT = "type filter text (regex)"; @@ -83,6 +89,13 @@ public class FXAnnotationFilter { /** Column filter option based on annotation type. */ private Class<? extends IAnnotatedSpecification> annotationTypeFilter; + /** Constructor */ + public FXAnnotationFilterContentProvider() { + // Initialize filter expression to enable filtering also for empty patterns. + // (i.e. if only columns hall be filtered). + setFilterExpression("*"); + } + /** * Returns {@code true} if a given {@code input} passes a case-insensitive * filter specified by {@code filterString}. @@ -91,12 +104,12 @@ public class FXAnnotationFilter { // Null-filter accepts every input. This covers also the case when the pattern // provided by // the user is invalid. - if (filterPattern == null) { + if(filterPattern == null) { return true; } // Null-input cannot be accepted by a non-null filter - if (input == null) { + if(input == null) { return false; } @@ -108,30 +121,31 @@ public class FXAnnotationFilter { * model element (or if this particular filter option is turned off). */ private boolean passesSelectedElementTypeFilter(AnnotationEntry annotationEntry) { - boolean selectedElementIsInvalid = currentlySelectedModelElement == null - || currentlySelectedModelElement instanceof IProjectRootElement; + boolean selectedElementIsInvalid = currentlySelectedModelElement == null || + currentlySelectedModelElement instanceof IProjectRootElement; - if (selectedElementIsInvalid || hierarchyLevelFilter == null) { + if(selectedElementIsInvalid || hierarchyLevelFilter == null) { return true; } IModelElement modelElement = annotationEntry.getModelElement(); int modelElementLevel = getModelElementLevel(modelElement); - int currentlySelectedModelElementLevel = getModelElementLevel(currentlySelectedModelElement); + int currentlySelectedModelElementLevel = + getModelElementLevel(currentlySelectedModelElement); - if (hierarchyLevelFilter.equals(HIERARCHY_LEVELS_CURRENT)) { + if(hierarchyLevelFilter.equals(HIERARCHY_LEVELS_CURRENT)) { // Elements have different levels -> filter - if (modelElementLevel != currentlySelectedModelElementLevel) { + if(modelElementLevel != currentlySelectedModelElementLevel) { return false; } - if (currentlySelectedModelElement.eContainer() != modelElement.eContainer()) { + if(currentlySelectedModelElement.eContainer() != modelElement.eContainer()) { return false; } } - if (hierarchyLevelFilter.equals(HIERARCHY_LEVELS_SELECTED_SUBMODEL)) { + if(hierarchyLevelFilter.equals(HIERARCHY_LEVELS_SELECTED_SUBMODEL)) { // Model element has lower level than currently selected element -> filter - if (modelElementLevel < currentlySelectedModelElementLevel) { + if(modelElementLevel < currentlySelectedModelElementLevel) { return false; } @@ -141,20 +155,23 @@ public class FXAnnotationFilter { // identical // to the currently selected model element. int levelsUp = modelElementLevel - currentlySelectedModelElementLevel; - EObject modelElementAncestor = getModelElementAncestor(annotationEntry.getModelElement(), levelsUp); + EObject modelElementAncestor = + getModelElementAncestor(annotationEntry.getModelElement(), levelsUp); - if (currentlySelectedModelElement != modelElementAncestor) { + if(currentlySelectedModelElement != modelElementAncestor) { return false; } } Class<? extends IModelElement> modelElementClass = modelElement.getClass(); - Class<? extends IModelElement> currentlySelectedModelElementClass = currentlySelectedModelElement.getClass(); + Class<? extends IModelElement> currentlySelectedModelElementClass = + currentlySelectedModelElement.getClass(); // Pass test if either the model element type is not restricted, or the element // has the same // type as the selected one - return !restrictToSelectedModelElementType || modelElementClass.equals(currentlySelectedModelElementClass); + return !restrictToSelectedModelElementType || + modelElementClass.equals(currentlySelectedModelElementClass); } /** @@ -176,7 +193,8 @@ public class FXAnnotationFilter { .isHidden(columnHandle.getAnnotatedSpecification().getClass()); // Pass name filter, if: name is not filtered, or the condition is met - boolean passesNameFilter = !filterColumnName || passesNameFilter(columnHandle.getColumnName()); + boolean passesNameFilter = + !filterColumnName || passesNameFilter(columnHandle.getColumnName()); // Check if column passes all tests // @CodeFormatterOff @@ -195,21 +213,21 @@ public class FXAnnotationFilter { // Pass name filter, if: name is not filtered, element is not a INamedElement, // or it // actually passes the filter - boolean passesNameFilter = !filterRowName || !(modelElement instanceof INamedElement) - || passesNameFilter(((INamedElement) modelElement).getName()); + boolean passesNameFilter = !filterRowName || !(modelElement instanceof INamedElement) || + passesNameFilter(((INamedElement)modelElement).getName()); return passesNameFilter && passesSelectedElementTypeFilter(annotationEntry); } /** Sets the model element / annotation name filter pattern. */ - public void setNameFilterPattern(String filterPatternString) { - if (filterPatternString.equals(FILTER_HINT_TEXT)) { + private void setNameFilterPattern(String filterPatternString) { + if(filterPatternString.equals(FILTER_HINT_TEXT)) { filterPattern = null; } else { try { final int patternFlags = (filterNameMatchCase ? 0 : CASE_INSENSITIVE) | DOTALL; filterPattern = Pattern.compile(".*" + filterPatternString + ".*", patternFlags); - } catch (PatternSyntaxException e) { + } catch(PatternSyntaxException e) { filterPattern = null; } } @@ -229,7 +247,7 @@ public class FXAnnotationFilter { public void setFilterNameMatchCase(boolean filterNameMatchCase) { this.filterNameMatchCase = filterNameMatchCase; // Recompile pattern - if (filterPattern != null) { + if(filterPattern != null) { setNameFilterPattern(filterPattern.pattern()); } } @@ -248,7 +266,8 @@ public class FXAnnotationFilter { } /** Sets the annotation type filter option. */ - public void setAnnotationTypeFilter(Class<? extends IAnnotatedSpecification> annotationTypeFilter) { + public void + setAnnotationTypeFilter(Class<? extends IAnnotatedSpecification> annotationTypeFilter) { this.annotationTypeFilter = annotationTypeFilter; } @@ -256,4 +275,34 @@ public class FXAnnotationFilter { public void setCurrentySelectedModelElement(IModelElement currentySelectedModelElement) { this.currentlySelectedModelElement = currentySelectedModelElement; } + + /** {@inheritDoc} */ + @Override + protected Collection<? extends AnnotationEntry> getChildren(AnnotationEntry parent) { + if(parent instanceof ArtificialRoot) { + return ((ArtificialRoot)parent).elements; + } + + return emptyList(); + } + + /** {@inheritDoc} */ + @Override + protected boolean filter(AnnotationEntry entry, String filterValue) { + return passesRowFilter(entry); + } + + /** {@inheritDoc} */ + @Override + public void setFilterExpression(String filterExpression) { + // An empty expression would permit the content provider from calling the filter + // method. Hence it an empty expression is replaced by "*". + if(filterExpression == null || filterExpression.isEmpty()) { + setNameFilterPattern("*"); + super.setFilterExpression("*"); + } else { + setNameFilterPattern(filterExpression); + super.setFilterExpression(filterExpression); + } + } } -- GitLab