All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jidefx.scene.control.searchable.TreeViewSearchable Maven / Gradle / Ivy

/*
 * @(#)TreeViewSearchable.java 5/19/2013
 *
 * Copyright 2002 - 2013 JIDE Software Inc. All rights reserved.
 */

package jidefx.scene.control.searchable;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;

import java.util.ArrayList;
import java.util.List;

/**
 * {@code TreeViewSearchable} is an concrete implementation of {@link Searchable} that enables the search function
 * in TreeView. 

It's very simple to use it. Assuming you have a TreeView, all you need to do is to call *

{@code
 * TreeView tree = ....;
 * TreeViewSearchable searchable = new TreeViewSearchable(tree);
 * }
* Now the TreeView will have the search function. *

* There is very little customization you need to do to TreeSearchable. The only thing you might need is when the * element in the TreeView needs a special conversion to convert to string. If so, you can override * convertElementToString() to provide you own algorithm to do the conversion. *

{@code
 * TreeView tree = ....;
 * TreeViewSearchable searchable = new TreeViewSearchable(tree) {
 *      protected String convertElementToString(Object object) {
 *          ...
 *      }
 * };
 * }
* The other customization you might want to is to call {@link #setRecursive} to true. It is false by default. If * setting it true, we will automatically expand the TreeItem to look for the string to be searched. If your TreeView * has a huge number or unlimited number of rows when fully expanded, please do not set it to true as it will for sure * run out of memory. *

* Additional customization can be done on the base Searchable class such as background and foreground color, * keystrokes, case sensitivity.

* * @param the element type in the TreeView. */ @SuppressWarnings({"Convert2Lambda", "unchecked"}) public class TreeViewSearchable extends Searchable> { private BooleanProperty _recursiveProperty; private transient List _treeItems; private ChangeListener _rootChangeListener; public TreeViewSearchable(TreeView treeView) { super(treeView); recursiveProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { hidePopup(); resetTreeItems(); } }); } @Override public void installListeners() { super.installListeners(); if (_rootChangeListener == null) { _rootChangeListener = new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { hidePopup(); resetTreeItems(); } }; } ((TreeView) _node).rootProperty().addListener(_rootChangeListener); } @Override public void uninstallListeners() { if (_rootChangeListener != null) { ((TreeView) _node).rootProperty().removeListener(_rootChangeListener); _rootChangeListener = null; } super.uninstallListeners(); } public BooleanProperty recursiveProperty() { if (_recursiveProperty == null) { _recursiveProperty = new SimpleBooleanProperty(); } return _recursiveProperty; } /** * Checks if the searchable is recursive. * * @return true if searchable is recursive. */ public boolean isRecursive() { return recursiveProperty().get(); } /** * Sets the recursive attribute. *

* If TreeSearchable is recursive, it will all tree nodes including those which are not visible to find the matching * node. Obviously, if your tree has unlimited number of tree nodes or a potential huge number of tree nodes (such * as a tree to represent file system), the recursive attribute should be false. To avoid this potential problem in * this case, we default it to false. * * @param recursive the attribute */ public void setRecursive(boolean recursive) { recursiveProperty().set(recursive); } @Override protected void setSelectedIndex(int index, boolean incremental) { TreeView treeView = (TreeView) _node; if (!isRecursive()) { if (incremental) { treeView.getSelectionModel().select(index); } else { treeView.getSelectionModel().clearAndSelect(index); } treeView.scrollTo(index); } else { TreeItem item = getElementAt(index); if (item != null) { // else case should never happen if (incremental) { treeView.getSelectionModel().select(item); } else { treeView.getSelectionModel().clearSelection(); treeView.getSelectionModel().select(item); } treeView.scrollTo(treeView.getRow(item)); } } } @Override protected int getSelectedIndex() { return ((TreeView) _node).getSelectionModel().getSelectedIndex(); } @Override protected TreeItem getElementAt(int index) { if (index == -1) { return null; } if (!isRecursive()) { return ((TreeView) _node).getTreeItem(index); } else { return getTreeItems().get(index); } } @Override protected int getElementCount() { if (!isRecursive()) { return ((TreeView) _node).getExpandedItemCount(); } else { return getTreeItems().size(); } } /** * Recursively go through the tree to populate the tree paths into a list and cache them. *

* Tree paths list is only used when recursive attribute is true. */ protected void populateTreePaths() { _treeItems = new ArrayList<>(); TreeItem root = ((TreeView) _node).getRoot(); populateTreePaths0(root); } private void populateTreePaths0(TreeItem item) { _treeItems.add(item); ObservableList children = item.getChildren(); for (TreeItem child : children) { populateTreePaths0(child); } } /** * Reset the cached tree paths list. *

* Tree paths list is only used when recursive attributes true. */ protected void resetTreeItems() { _treeItems = null; } /** * Gets the cached tree paths list. If it has never been cached before, this method will create the cache. *

* Tree paths list is only used when recursive attributes true. * * @return the tree paths list. */ protected List getTreeItems() { if (_treeItems == null) { populateTreePaths(); } return _treeItems; } /** * Converts the element in TreeView to string. The element by default is TreePath. The returned value will be * {@code toString()} of the last path component in the TreePath. * * @param object the object to be converted * @return the string representing the TreePath in the TreeView. */ @Override protected String convertElementToString(TreeItem object) { if (object != null) { Object value = ((TreeItem) object).getValue(); return value != null ? value.toString() : ""; } else { return ""; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy