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 80a18d3869bf4901cae85305c9e4332fe6031b56..a53b1308caaa24b9bf479b668e9d2b9a26594a79 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,6 +1,6 @@ AnnotationFxViewPart.java ca1548c49aa3842a9436262531464ba345b83688 GREEN AnnotationTreeTableUIProvider.java 85dfcf003c79d45f82c901b0f3f6bb30db59effa GREEN -AnnotationViewFXController.java 4351373c216d0aa4539784c9742f4db8bbf161e6 GREEN +AnnotationViewFXController.java 7d62ea076e87b14c4916935d3466168503c83c6f YELLOW AnnotationsFXUtils.java 754152735e037da59a4c40fa045602c3ed85a40f GREEN ColumnHandle.java 7b0fe536d4eb9faa63c4d812f0c078cf83d0fd42 GREEN FXAnnotationFilterContentProvider.java ca4587ef5dce1288ee4d7bf3bea5bd544ce6b89e GREEN 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 4351373c216d0aa4539784c9742f4db8bbf161e6..7d62ea076e87b14c4916935d3466168503c83c6f 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 @@ -15,9 +15,11 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.ui.annotation.view.fx; -import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static java.util.Collections.sort; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static org.fortiss.tooling.base.ui.annotation.view.fx.AnnotationsFXUtils.getValueLabel; 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; @@ -34,7 +36,9 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EEnumLiteral; @@ -46,8 +50,8 @@ import org.fortiss.tooling.base.annotation.AnnotationEntry; import org.fortiss.tooling.base.annotation.AnnotationValueService; import org.fortiss.tooling.base.annotation.IAnnotationValueService; import org.fortiss.tooling.base.annotation.valueprovider.EStructuralFeatureDescriptor; +import org.fortiss.tooling.base.annotation.valueprovider.EStructuralFeatureDescriptor.EReferenceScope; import org.fortiss.tooling.base.annotation.valueprovider.IAnnotationValueProvider; -import org.fortiss.tooling.base.annotation.valueprovider.ValueProviderBase; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.model.element.IModelElement; import org.fortiss.tooling.common.ui.javafx.control.treetableview.DynamicTreeTableUIProviderBase; @@ -57,6 +61,7 @@ import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.model.INamedCommentedElement; import org.fortiss.tooling.kernel.model.IProjectRootElement; import org.fortiss.tooling.kernel.service.IPersistencyService; +import org.fortiss.tooling.kernel.utils.HierarchicalNameComparator; import com.sun.webkit.ThemeClient; @@ -396,8 +401,10 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP IAnnotationValueProvider<IAnnotatedSpecification> valueProvider = entry.getAnnotationValueProvider(annotationType); IAnnotatedSpecification specification = entry.getSpecification(annotationType); - EClassifier valueType = - valueProvider.getEStructuralFeatureDescriptor().getEType(specification); + + EStructuralFeatureDescriptor featureDescriptor = + valueProvider.getEStructuralFeatureDescriptor(); + EClassifier valueType = featureDescriptor.getEType(specification); String columnName = valueProvider.getAnnotationName(specification); @@ -413,24 +420,12 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP return column; } - if(valueType instanceof EEnum) { - // Add a combo column for enumerations. + if(valueType instanceof EEnum || valueType instanceof EClass) { + // Add a combo column for enumerations and references column = annotationViewer.addComboColumn(columnName, 150, rowEntry -> { - ValueProviderBase<IAnnotatedSpecification> annotationValueProvider = - (ValueProviderBase<IAnnotatedSpecification>)rowEntry - .getAnnotationValueProvider(annotationType); - EStructuralFeatureDescriptor structuralFeature = - annotationValueProvider.getEStructuralFeatureDescriptor(); - EClassifier type = - structuralFeature.getEType(rowEntry.getSpecification(annotationType)); - - // Get the enum literals again, as it might be different for each row. - if(type instanceof EEnum) { - EList<EEnumLiteral> allLiterals = ((EEnum)type).getELiterals(); - - return allLiterals.stream().map(l -> l.getLiteral()).collect(toList()); - } - return emptyList(); + Map<Object, String> comboValues = getComboValues(featureDescriptor, specification, + rowEntry.getModelElement()); + return comboValues; }); } else if(valueType.getInstanceClass().equals(Boolean.class)) { // Use a checkbox column for booleans @@ -447,12 +442,49 @@ public class AnnotationViewFXController extends CompositeFXControllerBase<SplitP return column; } + /** + * Returns mapping of annotation values and their labels to be displayed in a combo box (for + * enums and references). + */ + private Map<Object, String> getComboValues(EStructuralFeatureDescriptor featureDescriptor, + IAnnotatedSpecification specification, IModelElement modelElement) { + + EClassifier eType = featureDescriptor.getEType(specification); + if(eType instanceof EEnum) { + EList<EEnumLiteral> allLiterals = ((EEnum)eType).getELiterals(); + + return allLiterals.stream().collect(toMap(l -> l.getInstance(), l -> l.getLiteral())); + } else if(eType instanceof EClass) { + + EObject root = featureDescriptor.getValueRootElement(modelElement); + if(root == null) { + return emptyMap(); + } + + EList<EObject> values = new BasicEList<EObject>(); + if(featureDescriptor.getEReferenceScope() == EReferenceScope.SUB_MODEL) { + values.add(root); + } + Class<? extends EObject> clazz = (Class<? extends EObject>)eType.getInstanceClass(); + for(EObject obj : getChildrenWithType(root, clazz)) { + if(featureDescriptor.isAvailableObject(obj, specification, modelElement)) { + values.add(obj); + } + } + + sort(values, new HierarchicalNameComparator()); + return values.stream().collect(toMap(v -> v, v -> getValueLabel(v, root))); + } + + return emptyMap(); + } + /** * Local helper to set the given newValue for the given annotationEntry and * specification. */ void setAnnotationEntryValue(IAnnotatedSpecification specification, - AnnotationEntry annotationEntry, String newValue) { + AnnotationEntry annotationEntry, Object newValue) { ITopLevelElement tle = IPersistencyService.getInstance().getTopLevelElementFor(curentRootElement); diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings index 289130f37a995025ad734549286b77b523a7b131..b3f1345a49aa3da5ff9190b17d856e6f53e56cbf 100644 --- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings +++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/.ratings @@ -5,8 +5,8 @@ DynamicTextFieldTreeTableCell.java de24117e6f785b328f1ff62383626a0b4b54e8ff GREE DynamicTreeContentProviderBase.java 91896b1fb5104d126544c44c1ff8c30f2a13a8d6 GREEN DynamicTreeItem.java 7486071d20e896d6ca9a9101bf105caccf3656d0 GREEN DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN -DynamicTreeTableUIProviderBase.java a091824351771293b8f68a53e658d712a2128878 GREEN -DynamicTreeTableViewer.java ead6f6671e9cb6b14632940bf440cba7e81fcd98 GREEN +DynamicTreeTableUIProviderBase.java 735766bf3b046dc696eb3324378754ae6db5f4d0 YELLOW +DynamicTreeTableViewer.java 9198fbd64af2c15829e63bafcab8095a173c6ff4 YELLOW DynamicTreeUIProviderBase.java 82d3c051213f0147f4c67ad247a08696cee73110 GREEN DynamicTreeViewer.java 545f1ca10b7b3cad171b294a4b447875da45c9ed GREEN DynamicTreeViewerBase.java a2013538b62d86f6a09efdf2cd78babac2072484 GREEN diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableUIProviderBase.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableUIProviderBase.java index a091824351771293b8f68a53e658d712a2128878..735766bf3b046dc696eb3324378754ae6db5f4d0 100644 --- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableUIProviderBase.java +++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableUIProviderBase.java @@ -13,10 +13,11 @@ *******************************************************************************/ package org.fortiss.tooling.common.ui.javafx.control.treetableview; +import static java.util.stream.Collectors.toMap; import static javafx.collections.FXCollections.observableArrayList; import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX; -import java.util.Collection; +import java.util.Map; import java.util.function.Function; import javafx.beans.property.SimpleBooleanProperty; @@ -268,10 +269,11 @@ public abstract class DynamicTreeTableUIProviderBase<T> { * @param column * The {@link TreeTableColumn} to be configured. * @param comboValueFactory - * A {@link Function} that maps the cell elements to their respective combo values. + * A {@link Function} that maps cell elements to a combo value map (data model + * element -> label) */ /* package */ final void applyToComboColumn(int columnIndex, TreeTableColumn<T, String> column, - Function<T, Collection<String>> comboValueFactory) { + Function<T, Map<?, String>> comboValueFactory) { column.setCellFactory( createEditableComboCellFactory(columnIndex, column, comboValueFactory)); } @@ -345,7 +347,7 @@ public abstract class DynamicTreeTableUIProviderBase<T> { /** Creates the cell factory for {@link ComboBox} editing. */ private Callback<TreeTableColumn<T, String>, TreeTableCell<T, String>> createEditableComboCellFactory(int columnIndex, TreeTableColumn<T, String> column, - Function<T, Collection<String>> comboValueFactory) { + Function<T, Map<?, String>> comboValueFactory) { // The list with the choices to be offered in the combo. ObservableList<String> items = observableArrayList(); Callback<TreeTableColumn<T, String>, TreeTableCell<T, String>> comboCellFactory = @@ -374,14 +376,30 @@ public abstract class DynamicTreeTableUIProviderBase<T> { // Changes the choices of the combo for every editing of every cell dynamically. column.setOnEditStart(event -> { - TreeItem<T> treeItem = event.getRowValue(); - T rowEntry = treeItem.getValue(); - - Collection<String> comboValues = comboValueFactory.apply(rowEntry); + T rowEntry = event.getRowValue().getValue(); + Map<?, String> comboValueMap = comboValueFactory.apply(rowEntry); items.clear(); - items.addAll(comboValues); + items.addAll(comboValueMap.values()); + }); + + column.setOnEditCommit(event -> { + // The column number needs to be retrieved from the viewer, as the the + // event.getTablePosition() does not take into account invisible columns for numbering. + TreeTableColumn<T, String> tableColumn = event.getTableColumn(); + int colIndex = tableColumn.getTreeTableView().getColumns().indexOf(tableColumn); + + // Convert displayed value label into underlying data model's value + String valueLabel = event.getNewValue(); + T rowEntry = event.getRowValue().getValue(); + Map<?, String> comboValueMap = comboValueFactory.apply(rowEntry); + Map<String, ?> valueMapInversed = comboValueMap.entrySet().stream() + .collect(toMap(Map.Entry::getValue, Map.Entry::getKey)); + + updateValue(rowEntry, colIndex, valueMapInversed.get(valueLabel)); + column.getTreeTableView().refresh(); }); + return comboCellFactory; } diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableViewer.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableViewer.java index ead6f6671e9cb6b14632940bf440cba7e81fcd98..9198fbd64af2c15829e63bafcab8095a173c6ff4 100644 --- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableViewer.java +++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/control/treetableview/DynamicTreeTableViewer.java @@ -19,6 +19,7 @@ import static java.lang.Integer.MAX_VALUE; import static javafx.scene.control.cell.CheckBoxTreeTableCell.forTreeTableColumn; import java.util.Collection; +import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -194,8 +195,7 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> { /** * Adds an editable column to the table part of the view. The labels, context menus and icons - * are shown as - * defined in the {@link DynamicTreeTableUIProviderBase}. + * are shown as defined in the {@link DynamicTreeTableUIProviderBase}. */ public TreeTableColumn<T, String> addTextColumn(String headerLabel, int prefWidth) { int num = view.getColumns().size(); @@ -232,17 +232,29 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> { * @param prefWidth * The preferred width of the new column in px. * @param comboValueFactory - * A Function, that maps cell elements to choices for the combo box. + * A {@link Function} that maps cell elements to a combo value map (data model + * element -> label) * * @return The newly created an configured column. */ public TreeTableColumn<T, String> addComboColumn(String headerLabel, int prefWidth, - Function<T, Collection<String>> comboValueFactory) { + Function<T, Map<?, String>> comboValueFactory) { + int num = view.getColumns().size(); - TreeTableColumn<T, String> column = addColumn(headerLabel, prefWidth); + TreeTableColumn<T, String> column = new TreeTableColumn<>(headerLabel); + column.setPrefWidth(prefWidth); + + column.setCellValueFactory(param -> { + T data = param.getValue().getValue(); + SimpleObjectProperty<String> cell = + new SimpleObjectProperty<String>(uiProvider.getLabel(data, num)); + return cell; + }); uiProvider.applyToComboColumn(num, column, comboValueFactory); + view.getColumns().add(column); + return column; }