Skip to content
Snippets Groups Projects
Commit b67721d1 authored by Andreas Bayha's avatar Andreas Bayha
Browse files

DynamicTreeTable: Improved text editing and removed redundant code

The classes MyTextFieldTreeTableCell (local class in
DynamicTreeTableUIProviderBase) and DynamicTextFieldTreeTableCell
implemented similar redundant functionalities.

They were combined to utilize both functionalities and simpolify the
code base.

Issue-ref: 4365
Issue-URL: af3#4365



Signed-off-by: default avatarAndreas Bayha <bayha@fortiss.org>
parent 29b169c6
Branches
Tags
1 merge request!2294365
Pipeline #41554 passed
Pipeline: maven-releng

#41555

    Showing with 54 additions and 222 deletions
    AnnotationFilterContentProvider.java 4cfc9452781fe151bc63faf7dff330d6e39942d4 GREEN
    AnnotationTreeTableUIProvider.java 24ccf734fc3ecd1ba600ccc7f1e9e019c20be3e1 GREEN
    AnnotationViewController.java a6eb15d93112434d2e1ecd84b476ad5edf51c6f7 GREEN
    AnnotationTreeTableUIProvider.java 6b9a5a686b2ecdf806b731196bfa83ee74d35214 YELLOW
    AnnotationViewController.java 4ef0dc005792124fef08d24aaa171fc795d247b9 YELLOW
    AnnotationViewPart.java 2442d3a048559fd6297e7be37567aec9178dc415 GREEN
    AnnotationViewUtils.java 11b65e75fcbe7f91503793b9ca0354e25b8364cc GREEN
    ColumnHandle.java cc21d5eb1d3d5c81f00c7b4eb95958dff1a034d2 GREEN
    ......
    ......@@ -123,7 +123,7 @@ import javafx.scene.paint.Color;
    /** {@inheritDoc} */
    @Override
    public boolean isEditable(int column, AnnotationEntry ae) {
    public boolean isElementEditable(int column, AnnotationEntry ae) {
    IAnnotatedSpecification spec = getAnnotation(column, ae);
    // Check 'editable' predicate for specification/annotation contained by model element
    ......@@ -160,7 +160,7 @@ import javafx.scene.paint.Color;
    for(AnnotationEntry ae : this.viewController.root.elements) {
    // If any cell is editable in this column, the column is editable.
    if(isEditable(column, ae)) {
    if(isElementEditable(column, ae)) {
    return true;
    }
    }
    ......
    ......@@ -441,7 +441,7 @@ public class AnnotationViewController extends CompositeFXControllerBase<SplitPan
    column = annotationViewer.addCheckboxColumn(columnName, 100);
    } else {
    // For all other types, there is text editing.
    column = annotationViewer.addTextColumn(columnName, 150);
    column = annotationViewer.addColumn(columnName, 150);
    }
    if(column != null) {
    ......
    DynamicList.java 786300e2e914826da239329d190abea1710478ea GREEN
    DynamicListContentProvider.java 817cba44f246a361207a88ef9a4e1869215803f7 GREEN
    DynamicStreamContentProvider.java f46e91400609cba54793dd240be0fe2aa0d5cced GREEN
    DynamicTextFieldTreeTableCell.java 62fa0c08b11d87e0eed41f84be85505c2740e75d GREEN
    DynamicTextFieldTreeTableCell.java b49c836a12f12b4c02ac1d16abdc0d1ac71886bf YELLOW
    DynamicTreeContentProviderBase.java 91896b1fb5104d126544c44c1ff8c30f2a13a8d6 GREEN
    DynamicTreeItem.java 7e81ea98038b5eca90df583e0268d4e8f37aaf25 GREEN
    DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN
    DynamicTreeTableUIProviderBase.java c52a1f9598de25874f83c133a8cbbcddc86442e9 GREEN
    DynamicTreeTableViewer.java 6e1fcc7a45076d741b80c3a5642a5c688fc651a6 GREEN
    DynamicTreeTableUIProviderBase.java 006b4d34141eb403675c29cfa23ebd9368f583ef YELLOW
    DynamicTreeTableViewer.java 04fcf982e807e7423e3fd69fa20c3e2d6d9a0d01 YELLOW
    DynamicTreeUIProviderBase.java 606d2f199f82aba3fcc33f96caa07157b087cbe5 GREEN
    DynamicTreeViewer.java b0d8cc4b3e11aa970446af12d1e54c750713b297 GREEN
    DynamicTreeViewerBase.java a2013538b62d86f6a09efdf2cd78babac2072484 GREEN
    ......
    /*-------------------------------------------------------------------------+
    | Copyright 2020 fortiss GmbH |
    | Copyright 2020-2024 fortiss GmbH |
    | |
    | Licensed under the Apache License, Version 2.0 (the "License"); |
    | you may not use this file except in compliance with the License. |
    ......@@ -15,6 +15,8 @@
    +--------------------------------------------------------------------------*/
    package org.fortiss.tooling.common.ui.javafx.control.treetableview;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.control.TextField;
    import javafx.scene.control.TreeTableRow;
    import javafx.scene.control.cell.TextFieldTreeTableCell;
    ......@@ -32,16 +34,9 @@ import javafx.util.converter.DefaultStringConverter;
    * @author bayha
    */
    public class DynamicTextFieldTreeTableCell<T> extends TextFieldTreeTableCell<T, String> {
    /** Flag to indicate any occurred Escape key press events during editing. */
    private boolean escapePressed = false;
    /** The currently edited Element. */
    private T currentlyEditedElement;
    /** The current entered text in the TextField. */
    private String currentInput = "";
    /** The UIProvider of the editor in which this cell is embedded in. */
    DynamicTreeTableUIProviderBase<T> uiProvider;
    ......@@ -57,6 +52,8 @@ public class DynamicTextFieldTreeTableCell<T> extends TextFieldTreeTableCell<T,
    this.uiProvider = uiProvider;
    this.columnIndex = columnIndex;
    setConverter(new DefaultStringConverter());
    }
    /**
    ......@@ -67,74 +64,49 @@ public class DynamicTextFieldTreeTableCell<T> extends TextFieldTreeTableCell<T,
    this.setOnKeyPressed(event -> {
    if(event.getCode().equals(KeyCode.ESCAPE)) {
    if(currentlyEditedElement != null) {
    escapePressed = true;
    }
    } else {
    escapePressed = false;
    }
    });
    }
    /**
    * May be overwritten to determine for this cell, whether it is editable for a
    * given element.
    *
    * @param element
    * The element for which to decide, whether it shall be editable.
    * @return true, if the given element is supposed to be editable. Otherwise false.
    */
    protected boolean canEdit(T element) {
    return true;
    }
    /**
    * May be overwritten, if the current input value is supposed to be kept/set
    * after leaving the cell, e.g. by selecting a different cell or view.
    *
    * Note, that with this, only pressing Escape will cancel an editing operation
    * of a user.
    *
    * @param element
    * The element to set the current text input as new value.
    * @param currentValue
    * The current value from the editing process.
    */
    protected void setValueOnLeavingCell(T element, String currentValue) {
    // Empty
    }
    /** {@inheritDoc} */
    @Override
    public void startEdit() {
    TreeTableRow<T> row = getTreeTableRow();
    T currentEntry = row.getItem();
    if(canEdit(currentEntry)) {
    super.startEdit();
    // Remember currently edited element.
    currentlyEditedElement = currentEntry;
    String initialEditorContent =
    uiProvider.getInitialEditorContent(currentlyEditedElement, columnIndex);
    boolean isElementEditable = !uiProvider.isElementEditable(columnIndex, currentEntry);
    if(currentEntry == null || !isEditable() || !getTreeTableView().isEditable() ||
    !getTableColumn().isEditable() || isElementEditable) {
    return;
    }
    // Reset currentInput buffer for the new element.
    currentInput = initialEditorContent;
    super.startEdit();
    // We keep the current input in the buffer variable currentInput to be able to
    // use it during unintended cancel options. See cancelEdit().
    TextField textField = (TextField)getGraphic();
    if(textField != null) {
    textField.setOnKeyReleased(event -> {
    currentInput = textField.getText();
    });
    textField.setText(initialEditorContent);
    // Listener to add possibility to update the model in case the editor loses focus (user
    // clicking elsewhere or escape pressed).
    textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
    @Override
    public void changed(ObservableValue<? extends Boolean> val, Boolean oldVal,
    Boolean newVal) {
    String newValue = textField.getText();
    String oldValue = uiProvider.getLabel(getTreeTableRow().getItem(), columnIndex);
    // Do not update value in case it did not change or escape was pressed (i.e.
    // intended cancel).
    if(!newValue.equals(oldValue) && !escapePressed) {
    T currentlyEditedElement = getTreeTableRow().getItem();
    if(currentlyEditedElement != null) {
    uiProvider.updateValue(currentlyEditedElement, columnIndex, newValue);
    }
    }
    } else {
    // Reset buffer
    currentlyEditedElement = null;
    currentInput = null;
    }
    });
    }
    }
    ......@@ -143,33 +115,14 @@ public class DynamicTextFieldTreeTableCell<T> extends TextFieldTreeTableCell<T,
    public void cancelEdit() {
    super.cancelEdit();
    if(escapePressed) {
    escapePressed = false;
    currentlyEditedElement = null;
    } else {
    // Reset the new value to this cell.
    setText(currentInput);
    // Set the current TextField value if intended.
    if(currentlyEditedElement != null) {
    String initialEditorContent =
    uiProvider.getInitialEditorContent(currentlyEditedElement, columnIndex);
    if(!currentInput.equals(initialEditorContent)) {
    setValueOnLeavingCell(currentlyEditedElement, currentInput);
    }
    currentlyEditedElement = null;
    }
    }
    getTreeTableView().refresh();
    }
    /** {@inheritDoc} */
    @Override
    public void commitEdit(String newValue) {
    // Reset the currentlyEditedElement since the editing is over.
    currentlyEditedElement = null;
    public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    super.commitEdit(newValue);
    uiProvider.styleCell(this, columnIndex);
    }
    }
    ......@@ -29,16 +29,13 @@ import javafx.collections.ObservableList;
    import javafx.scene.Node;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.ContextMenu;
    import javafx.scene.control.TextField;
    import javafx.scene.control.Tooltip;
    import javafx.scene.control.TreeItem;
    import javafx.scene.control.TreeTableCell;
    import javafx.scene.control.TreeTableColumn;
    import javafx.scene.control.cell.CheckBoxTreeTableCell;
    import javafx.scene.control.cell.ComboBoxTreeTableCell;
    import javafx.scene.control.cell.TextFieldTreeTableCell;
    import javafx.scene.input.Dragboard;
    import javafx.scene.input.KeyCode;
    import javafx.scene.input.KeyEvent;
    import javafx.scene.input.MouseButton;
    import javafx.scene.input.MouseEvent;
    ......@@ -46,7 +43,6 @@ import javafx.scene.paint.Color;
    import javafx.scene.text.Font;
    import javafx.scene.text.Text;
    import javafx.util.Callback;
    import javafx.util.converter.DefaultStringConverter;
    /**
    * This UI provider is responsible to return the label, the icon, and the context menu for each cell
    ......@@ -203,7 +199,7 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
    * The element to be checked
    * @return Whether the column is editable
    */
    public boolean isEditable(int column, T element) {
    public boolean isElementEditable(int column, T element) {
    return isEditable(column);
    }
    ......@@ -335,7 +331,7 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
    * @param columnIndex
    * The number of the column in which this cell is contained in.
    */
    private final void styleCell(TreeTableCell<T, ?> cell, int columnIndex) {
    /*package*/ final void styleCell(TreeTableCell<T, ?> cell, int columnIndex) {
    if(cell.getTreeTableRow() != null) {
    T data = cell.getTreeTableRow().getItem();
    ......@@ -388,10 +384,10 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
    private Callback<TreeTableColumn<T, String>, TreeTableCell<T, String>>
    createEditableCellFactory(int colIndex) {
    return param -> {
    MyTextFieldTreeTableCell myTextFieldTreeTableCell =
    new MyTextFieldTreeTableCell(colIndex);
    styleCell(myTextFieldTreeTableCell, colIndex);
    return myTextFieldTreeTableCell;
    DynamicTextFieldTreeTableCell<T> cell =
    new DynamicTextFieldTreeTableCell<T>(this, colIndex);
    styleCell(cell, colIndex);
    return cell;
    };
    }
    ......@@ -471,70 +467,6 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
    return comboCellFactory;
    }
    /** Custom table cell implementation to allow on key released validation. */
    private class MyTextFieldTreeTableCell extends TextFieldTreeTableCell<T, String> {
    /** The column index of this cell. */
    private final int columnIndex;
    /** Constructor. */
    public MyTextFieldTreeTableCell(int colIndex) {
    this.columnIndex = colIndex;
    setConverter(new DefaultStringConverter());
    }
    /** {@inheritDoc} */
    @Override
    public void startEdit() {
    if(getItem() == null || !isEditable() || !getTreeTableView().isEditable() ||
    !getTableColumn().isEditable()) {
    return;
    }
    super.startEdit();
    // the following code uses implementation details of
    // CellUtils.startEdit(...) and CellUtils.createTextfield(...)
    TextField tf = (TextField)getGraphic(); // CellUtils:228
    tf.setOnKeyReleased(t -> {
    DynamicTreeTableUIProviderBase<T>.MyTextFieldTreeTableCell mythis =
    MyTextFieldTreeTableCell.this;
    if(t.getCode() == KeyCode.ESCAPE) {
    mythis.cancelEdit();
    t.consume();
    } else {
    T item = mythis.getTreeTableRow().getItem();
    validateOnKeyReleased(t, columnIndex, item, tf.getText());
    }
    });
    tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
    // If the focus is lost (user clicking elsewhere), the currently entered value is
    // committed.
    @Override
    public void changed(ObservableValue<? extends Boolean> val, Boolean oldVal,
    Boolean newVal) {
    if(!newVal) {
    commitEdit(tf.getText());
    }
    }
    });
    }
    /** {@inheritDoc} */
    @Override
    public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    styleCell(this, this.columnIndex);
    addContextMenuToCell(this, this.columnIndex);
    }
    /** {@inheritDoc} */
    @Override
    public void cancelEdit() {
    super.cancelEdit();
    T item = getTreeTableRow().getItem();
    validateOnCancelEdit(columnIndex, item);
    }
    }
    /**
    * Called when editing a cell was canceled.
    *
    ......@@ -585,46 +517,6 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
    };
    }
    /**
    * Applies this UIProvider to configure the given {@link TreeTableColumn}.
    *
    * @param columnIndex
    * The index number of the column.
    * @param column
    * The column to be configured.
    */
    public void applyToTextColumn(int columnIndex, TreeTableColumn<T, String> column) {
    column.setCellFactory(ttColumn -> {
    DynamicTextFieldTreeTableCell<T> cell =
    new DynamicTextFieldTreeTableCell<T>(this, columnIndex) {
    /** {@inheritDoc} */
    @Override
    protected boolean canEdit(T element) {
    return DynamicTreeTableUIProviderBase.this.isEditable(columnIndex,
    element);
    }
    /** {@inheritDoc} */
    @Override
    protected void setValueOnLeavingCell(T element, String currentValue) {
    updateValue(element, columnIndex, currentValue);
    }
    /** {@inheritDoc} */
    @Override
    public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    styleCell(this, columnIndex);
    }
    };
    styleCell(cell, columnIndex);
    return cell;
    });
    }
    /**
    * Adds the context menu to the given {@code cell} in the given {@code columnIndex}.
    *
    ......
    ......@@ -281,19 +281,6 @@ public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> {
    return column;
    }
    /**
    * 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}.
    */
    public TreeTableColumn<T, String> addTextColumn(String headerLabel, int prefWidth) {
    int num = view.getColumns().size();
    TreeTableColumn<T, String> column = addColumn(headerLabel, prefWidth);
    uiProvider.applyToTextColumn(num, column);
    return column;
    }
    /**
    * Adds a boolean checkbox column to the table part of the view. The labels, context menus and
    * icons are shown as defined in the {@link DynamicTreeTableUIProviderBase}.
    ......
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please to comment