Skip to content
Snippets Groups Projects
Commit 3895a2ee authored by Alexander Diewald's avatar Alexander Diewald
Browse files

JavaFX: Use generics for basic controls.

* DynamicTreeViewers and alike are often used for a specific set of base
  types. Thus, generics can be used to reduce the code by subclassing
  these controls for specific meta-model types like IHierarchicElements.
* Second, a bit more type-safety is achieved without sacrificing
  ease-of-use since the controls can still be constructed for Objects
  for complex object relations.

Issue-Ref: 3209
Issue-Url: https://af3-developer.fortiss.org/issues/3209


Signed-off-by: default avatarAlexander Diewald <diewald@fortiss.org>
parent 4cca62cc
No related branches found
No related tags found
1 merge request!43209 javafx
Showing
with 86 additions and 67 deletions
DynamicTreeContentProviderBase.java d1786cd9aa0080db117d2efd5ed5f05f7b83e2aa RED
DynamicTreeItem.java fbaa05fd834fa23b586b31124987cf1b7dc7393e RED
DynamicTreeTableUIProviderBase.java fd9fce19a65eb1006ceacb0d869bbe90a8c578b3 RED
DynamicTreeTableViewer.java 748a6dcf5e61da5de65161fa7fd4e4fbcfbd0c10 RED
DynamicTreeUIProviderBase.java 796ebafa244c158c2b4b30b322228a0de74ddaed RED
DynamicTreeViewer.java c643043b746666830b2f6bbae24f1cf374a68bfe RED
DynamicTreeViewerBase.java fddff67e874074f48335f772d3ce3ccd8671aa6d RED
IDoubleClickHandler.java ba16696ee9f7074d5dbab126717e622a0ad5b3d5 RED
DynamicTreeContentProviderBase.java dff437afeaf7486af05460fa54eca4fa61d7eae6 YELLOW
DynamicTreeItem.java afc105cf5acf3d2506d89e0892555100c234ce5b YELLOW
DynamicTreeTableUIProviderBase.java fd9fce19a65eb1006ceacb0d869bbe90a8c578b3 YELLOW
DynamicTreeTableViewer.java 22bd5e5b13b959807596fff5b4024b3383737103 YELLOW
DynamicTreeUIProviderBase.java 56fe4df4577b35f1e5e6e4c4be189b706c852d52 YELLOW
DynamicTreeViewer.java 72945b28f34d9d268df4ce763fdabb7a8561fbc6 YELLOW
DynamicTreeViewerBase.java 47124c847de322a0ae26eb7a114f85ce4bd02d7e YELLOW
IDoubleClickHandler.java 447f7769dead9a106b3ea3139ef0da51eb0b9a89 YELLOW
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......@@ -24,9 +26,9 @@ import java.util.function.Predicate;
* Base class for implementing tree content providers used in {@link DynamicTreeViewer} and
* {@link DynamicTreeTableViewer}.
*/
public abstract class DynamicTreeContentProviderBase {
public abstract class DynamicTreeContentProviderBase<T> {
/** Returns the children of the given parent in the tree. */
protected abstract Collection<? extends Object> getChildren(Object parent);
protected abstract Collection<? extends T> getChildren(T parent);
/** Returns the filer predicate. */
protected Predicate<Object> getFilterPredicate() {
......@@ -39,8 +41,8 @@ public abstract class DynamicTreeContentProviderBase {
}
/** Returns the filtered children of the given element. */
public final Collection<? extends Object> getFilteredSortedChildren(Object parent) {
Collection<? extends Object> l = getChildren(parent);
public final Collection<? extends T> getFilteredSortedChildren(T parent) {
Collection<? extends T> l = getChildren(parent);
if(l == null) {
return emptyList();
}
......
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......@@ -22,12 +24,12 @@ import javafx.scene.control.TreeItem;
* {@link TreeItem} with support for dynamic children using the {@link DynamicTreeItem#update()}
* method.
*/
public class DynamicTreeItem extends TreeItem<Object> {
public class DynamicTreeItem<T> extends TreeItem<T> {
/** The viewer. */
private DynamicTreeViewerBase viewer;
private DynamicTreeViewerBase<T> viewer;
/** Constructor. */
public DynamicTreeItem(Object data, DynamicTreeViewerBase viewer) {
public DynamicTreeItem(T data, DynamicTreeViewerBase<T> viewer) {
super(data);
this.viewer = viewer;
}
......@@ -35,20 +37,20 @@ public class DynamicTreeItem extends TreeItem<Object> {
/** Updates the children of this item from the underlying content model. */
public void update() {
// remember expanded state of children
HashMap<Object, TreeItem<Object>> expanded = new HashMap<>();
for(TreeItem<Object> c : getChildren()) {
HashMap<T, TreeItem<T>> expanded = new HashMap<>();
for(TreeItem<T> c : getChildren()) {
if(c.isExpanded()) {
expanded.put(c.getValue(), c);
}
}
// get list of children and create tree items
getChildren().clear();
for(Object element : viewer.getContentProvider().getFilteredSortedChildren(getValue())) {
DynamicTreeItem dti;
for(T element : viewer.getContentProvider().getFilteredSortedChildren(getValue())) {
DynamicTreeItem<T> dti;
if(expanded.containsKey(element)) {
dti = (DynamicTreeItem)expanded.get(element);
dti = (DynamicTreeItem<T>)expanded.get(element);
} else {
dti = new DynamicTreeItem(element, viewer);
dti = new DynamicTreeItem<T>(element, viewer);
}
getChildren().add(dti);
dti.update();
......
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......@@ -26,28 +28,27 @@ import javafx.scene.control.TreeTableView;
* {@link DynamicTreeTableUIProviderBase}. This class is intended to be used as a wrapper for
* {@link TreeTableView} and its rather complex expert API.
* <P>
* This class currently supports only a static tree-table layout, i.e., there is no way to alter
* the columns unless the developer changes the underlying {@link TreeTableView} directly.
* Note that if a column is removed the index provided to the label provider might not be correct
* anymore.
* This class currently supports only a static tree-table layout, i.e., there is no way to alter the
* columns unless the developer changes the underlying {@link TreeTableView} directly. Note that if
* a column is removed the index provided to the label provider might not be correct anymore.
* <P>
* Furthermore, the selection model is currently fixed to be row selection.
*/
public final class DynamicTreeTableViewer extends DynamicTreeViewerBase {
public final class DynamicTreeTableViewer<T> extends DynamicTreeViewerBase<T> {
/** The {@link TreeTableView} control to be managed. */
private final TreeTableView<Object> view;
private final TreeTableView<T> view;
/** The UI provider of this tree-table. */
private final DynamicTreeTableUIProviderBase uiProvider;
/** Constructor. */
public DynamicTreeTableViewer(Object root, boolean showRoot, int revealLevel,
DynamicTreeContentProviderBase contentProvider,
public DynamicTreeTableViewer(T root, boolean showRoot, int revealLevel,
DynamicTreeContentProviderBase<T> contentProvider,
DynamicTreeTableUIProviderBase uiProvider) {
super(contentProvider);
this.uiProvider = uiProvider;
// construct view
this.view = new TreeTableView<Object>();
DynamicTreeItem rootItem = new DynamicTreeItem(root, this);
this.view = new TreeTableView<T>();
DynamicTreeItem<T> rootItem = new DynamicTreeItem<T>(root, this);
view.setRoot(rootItem);
view.setShowRoot(showRoot);
rootItem.update();
......@@ -58,18 +59,18 @@ public final class DynamicTreeTableViewer extends DynamicTreeViewerBase {
/** Updates the viewer content. */
public void update() {
// wild cast works: see constructor
DynamicTreeItem rootItem = (DynamicTreeItem)view.getRoot();
DynamicTreeItem<T> rootItem = (DynamicTreeItem<T>)view.getRoot();
rootItem.update();
}
/** Expands items up to the given level. */
private void expandItem(TreeItem<Object> parentItem, int revealLevel) {
private void expandItem(TreeItem<T> parentItem, int revealLevel) {
if(revealLevel <= 0) {
return;
}
parentItem.setExpanded(true);
revealLevel--;
for(TreeItem<Object> child : parentItem.getChildren()) {
for(TreeItem<T> child : parentItem.getChildren()) {
expandItem(child, revealLevel);
}
}
......@@ -77,21 +78,21 @@ public final class DynamicTreeTableViewer extends DynamicTreeViewerBase {
/** Adds a column to the table part of the view. */
public void addColumn(String headerLabel, int prefWidth) {
final int num = view.getColumns().size();
TreeTableColumn<Object, String> col = new TreeTableColumn<>(headerLabel);
TreeTableColumn<T, String> col = new TreeTableColumn<>(headerLabel);
col.setPrefWidth(prefWidth);
col.setCellValueFactory(param -> {
Object data = param.getValue().getValue();
return new ReadOnlyStringWrapper(uiProvider.getLabel(data, num));
});
col.setCellFactory(param -> {
TreeTableCell<Object, String> cell = new TreeTableCell<Object, String>() {
TreeTableCell<T, String> cell = new TreeTableCell<T, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
ContextMenu menu = null;
Node icon = null;
if(!empty && item != null) {
Object data = this.getTreeTableRow().getItem();
T data = this.getTreeTableRow().getItem();
menu = uiProvider.createContextMenu(data, num);
icon = uiProvider.getIconNode(data, num);
}
......@@ -106,7 +107,7 @@ public final class DynamicTreeTableViewer extends DynamicTreeViewerBase {
}
/** Returns the underlying {@link TreeTableView}. */
public TreeTableView<Object> getControl() {
public TreeTableView<T> getControl() {
return view;
}
}
......@@ -20,13 +20,13 @@ import javafx.scene.control.ContextMenu;
* This UI provider is responsible to return the label, the icon, and the context menu for each cell
* in the {@link DynamicTreeViewer} based on the data object.
*/
public abstract class DynamicTreeUIProviderBase {
public abstract class DynamicTreeUIProviderBase<T> {
/**
* @param element
* the displayed element
* @return the label to be displayed
*/
public String getLabel(Object element) {
public String getLabel(T element) {
return "";
}
......@@ -35,7 +35,7 @@ public abstract class DynamicTreeUIProviderBase {
* the displayed element
* @return the node to be displayed as the icon
*/
public Node getIconNode(Object element) {
public Node getIconNode(T element) {
return null;
}
......@@ -44,7 +44,7 @@ public abstract class DynamicTreeUIProviderBase {
* the displayed element
* @return the context menu
*/
public ContextMenu createContextMenu(Object element) {
public ContextMenu createContextMenu(T element) {
return null;
}
}
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......@@ -29,24 +31,25 @@ import javafx.scene.input.MouseEvent;
* {@link DynamicTreeUIProviderBase}. This class is intended to be used as a wrapper for
* {@link TreeView} and its rather complex expert API.
*/
public final class DynamicTreeViewer extends DynamicTreeViewerBase {
public final class DynamicTreeViewer<T> extends DynamicTreeViewerBase<T> {
/** The {@link TreeView} control to be managed. */
private final TreeView<Object> view;
private final TreeView<T> view;
/** The UI provider implementation. */
private final DynamicTreeUIProviderBase uiProvider;
private final DynamicTreeUIProviderBase<T> uiProvider;
/** The selection change listener. */
private ChangeListener<Object> selectionChangeListener = null;
/** The double click handler. */
private IDoubleClickHandler doubleClickHandler;
/** Constructor. */
public DynamicTreeViewer(Object root, boolean showRoot, int revealLevel,
DynamicTreeContentProviderBase contentProvider, DynamicTreeUIProviderBase uiProvider) {
public DynamicTreeViewer(TreeView<T> view, T root, boolean showRoot, int revealLevel,
DynamicTreeContentProviderBase<T> contentProvider,
DynamicTreeUIProviderBase<T> uiProvider) {
super(contentProvider);
this.uiProvider = uiProvider;
// construct view
this.view = new TreeView<Object>();
DynamicTreeItem rootItem = new DynamicTreeItem(root, this);
this.view = view;
DynamicTreeItem<T> rootItem = new DynamicTreeItem<T>(root, this);
view.setRoot(rootItem);
view.setShowRoot(showRoot);
configureCellFactory();
......@@ -62,33 +65,40 @@ public final class DynamicTreeViewer extends DynamicTreeViewerBase {
expandItem(rootItem, showRoot ? revealLevel : revealLevel + 1);
}
/** Constructor. */
public DynamicTreeViewer(T root, boolean showRoot, int revealLevel,
DynamicTreeContentProviderBase<T> contentProvider,
DynamicTreeUIProviderBase<T> uiProvider) {
this(new TreeView<T>(), root, showRoot, revealLevel, contentProvider, uiProvider);
}
/** Updates the tree view. */
public void update() {
// wild cast works: see constructor
DynamicTreeItem rootItem = (DynamicTreeItem)view.getRoot();
DynamicTreeItem<T> rootItem = (DynamicTreeItem<T>)view.getRoot();
rootItem.update();
}
/** Sets the selection of this tree view. */
public void setSelection(Object value) {
// wild cast works: see constructor
DynamicTreeItem rootItem = (DynamicTreeItem)view.getRoot();
DynamicTreeItem item = findItem(rootItem, value);
DynamicTreeItem<T> rootItem = (DynamicTreeItem<T>)view.getRoot();
DynamicTreeItem<T> item = findItem(rootItem, value);
int row = view.getRow(item);
view.getSelectionModel().select(row);
}
/** Searches the {@link DynamicTreeItem} for the given value. */
public DynamicTreeItem findItem(DynamicTreeItem item, Object value) {
public DynamicTreeItem<T> findItem(DynamicTreeItem<T> item, Object value) {
if(item == null || value == null) {
return null;
}
if(item.getValue().equals(value)) {
return item;
}
for(TreeItem<Object> subItem : item.getChildren()) {
for(TreeItem<T> subItem : item.getChildren()) {
if(subItem instanceof DynamicTreeItem) {
DynamicTreeItem i = findItem((DynamicTreeItem)subItem, value);
DynamicTreeItem<T> i = findItem((DynamicTreeItem<T>)subItem, value);
if(i != null) {
return i;
}
......@@ -110,9 +120,9 @@ public final class DynamicTreeViewer extends DynamicTreeViewerBase {
/** Configures the cell factory for the viewer. */
private void configureCellFactory() {
view.setCellFactory(param -> {
TreeCell<Object> cell = new TreeCell<Object>() {
TreeCell<T> cell = new TreeCell<T>() {
@Override
public void updateItem(Object item, boolean empty) {
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
ContextMenu menu = null;
if(!empty && item != null) {
......@@ -130,24 +140,24 @@ public final class DynamicTreeViewer extends DynamicTreeViewerBase {
}
/** Expands items up to the given level. */
private void expandItem(TreeItem<Object> parentItem, int revealLevel) {
private void expandItem(TreeItem<T> parentItem, int revealLevel) {
if(revealLevel <= 0) {
return;
}
parentItem.setExpanded(true);
revealLevel--;
for(TreeItem<Object> child : parentItem.getChildren()) {
for(TreeItem<T> child : parentItem.getChildren()) {
expandItem(child, revealLevel);
}
}
/** Returns the underlying {@link TreeView}. */
public TreeView<Object> getControl() {
public TreeView<T> getControl() {
return view;
}
/** Returns the UI provider. */
public DynamicTreeUIProviderBase getUIProvider() {
public DynamicTreeUIProviderBase<T> getUIProvider() {
return uiProvider;
}
......@@ -172,8 +182,8 @@ public final class DynamicTreeViewer extends DynamicTreeViewerBase {
if(mevt.getButton() == MouseButton.PRIMARY && mevt.getClickCount() >= 2) {
if(mevt.getEventType().equals(MouseEvent.MOUSE_CLICKED) &&
doubleClickHandler != null) {
DynamicTreeItem item =
(DynamicTreeItem)view.getSelectionModel().getSelectedItem();
DynamicTreeItem<T> item =
(DynamicTreeItem<T>)view.getSelectionModel().getSelectedItem();
if(item != null) {
doubleClickHandler.doubleClicked(item.getValue());
}
......
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......@@ -16,17 +18,17 @@ package org.fortiss.tooling.common.ui.javafx.control.treetableview;
/**
* Base class for {@link DynamicTreeViewer} and {@link DynamicTreeTableViewer}.
*/
abstract class DynamicTreeViewerBase {
abstract class DynamicTreeViewerBase<T> {
/** The content provider implementation. */
private final DynamicTreeContentProviderBase contentProvider;
private final DynamicTreeContentProviderBase<T> contentProvider;
/** Constructor. */
public DynamicTreeViewerBase(DynamicTreeContentProviderBase contentProvider) {
public DynamicTreeViewerBase(DynamicTreeContentProviderBase<T> contentProvider) {
this.contentProvider = contentProvider;
}
/** Returns the content provider. */
public final DynamicTreeContentProviderBase getContentProvider() {
public final DynamicTreeContentProviderBase<T> getContentProvider() {
return contentProvider;
}
}
......@@ -9,6 +9,8 @@
*
* Contributors:
* Florian Hoelzl (fortiss GmbH) - initial implementation
* Alexander Diewald (fortiss GmbH) - backport to AF3 & Integration
* improvements
*
*******************************************************************************/
package org.fortiss.tooling.common.ui.javafx.control.treetableview;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment