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

com.alee.laf.tree.WebTree Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of WebLookAndFeel library.
 *
 * WebLookAndFeel library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * WebLookAndFeel library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with WebLookAndFeel library.  If not, see .
 */

package com.alee.laf.tree;

import com.alee.api.jdk.Objects;
import com.alee.api.jdk.Predicate;
import com.alee.laf.tree.behavior.TreeHoverSelectionBehavior;
import com.alee.laf.tree.behavior.TreeSelectionExpandBehavior;
import com.alee.laf.tree.behavior.TreeSingleChildExpandBehavior;
import com.alee.managers.hotkey.HotkeyData;
import com.alee.managers.language.DictionaryListener;
import com.alee.managers.language.LanguageEventMethods;
import com.alee.managers.language.LanguageListener;
import com.alee.managers.language.UILanguageManager;
import com.alee.managers.settings.Configuration;
import com.alee.managers.settings.SettingsMethods;
import com.alee.managers.settings.SettingsProcessor;
import com.alee.managers.settings.UISettingsManager;
import com.alee.managers.style.*;
import com.alee.painter.Paintable;
import com.alee.painter.Painter;
import com.alee.utils.GeometryUtils;
import com.alee.utils.compare.Filter;
import com.alee.utils.swing.HoverListener;
import com.alee.utils.swing.MouseButton;
import com.alee.utils.swing.extensions.*;

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;

/**
 * {@link JTree} extension class.
 * It contains various useful methods to simplify core component usage.
 * 

* This component should never be used with a non-Web UIs as it might cause an unexpected behavior. * You could still use that component even if WebLaF is not your application LaF as this component will use Web-UI in any case. * * @param node type * @author Mikle Garin * @see JTree * @see WebTreeUI * @see TreePainter * @see WebTreeModel */ public class WebTree extends JTree implements Styleable, Paintable, ShapeMethods, MarginMethods, PaddingMethods, TreeEventMethods, EventMethods, LanguageEventMethods, SettingsMethods, FontMethods>, SizeMethods> { /** * Single selection mode. * Only one node can be selected. */ public static final int SINGLE_TREE_SELECTION = TreeSelectionModel.SINGLE_TREE_SELECTION; /** * Contiguous selection mode. * Any amount of nodes can be selected in a row. */ public static final int CONTIGUOUS_TREE_SELECTION = TreeSelectionModel.CONTIGUOUS_TREE_SELECTION; /** * Discontiguous selection mode. * Any amount of nodes can be selected anywhere. */ public static final int DISCONTIGUOUS_TREE_SELECTION = TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION; /** * Listener that forces tree to scroll view to selection. * It is disabled by default and null in that case. */ protected transient TreeSelectionListener scrollToSelectionListener = null; /** * Special state provider that can be set to check whether or not specific nodes are editable. */ protected transient Predicate editableStateProvider = null; /** * Custom WebLaF tooltip provider. */ protected transient TreeToolTipProvider toolTipProvider = null; /** * Constructs tree with default sample model. */ public WebTree () { this ( StyleId.auto ); } /** * Constructs tree with model based on specified values. * * @param data tree data */ public WebTree ( final Object[] data ) { this ( StyleId.auto, data ); } /** * Constructs tree with model based on specified values. * * @param data tree data */ public WebTree ( final Vector data ) { this ( StyleId.auto, data ); } /** * Constructs tree with model based on specified values. * * @param data tree data */ public WebTree ( final Hashtable data ) { this ( StyleId.auto, data ); } /** * Constructs tree with model based on specified root node. * * @param root tree root node */ public WebTree ( final N root ) { this ( StyleId.auto, root ); } /** * Constructs tree with model based on specified root node and which decides whether a node is a leaf node in the specified manner. * * @param root tree root node * @param asksAllowsChildren false if any node can have children, true if each node is asked to see if it can have children */ public WebTree ( final N root, final boolean asksAllowsChildren ) { this ( StyleId.auto, root, asksAllowsChildren ); } /** * Constructs tree with specified model. * * @param newModel tree model */ public WebTree ( final TreeModel newModel ) { this ( StyleId.auto, newModel ); } /** * Constructs tree with default sample model. * * @param id style ID */ public WebTree ( final StyleId id ) { this ( id, createDefaultTreeModel () ); } /** * Constructs tree with model based on specified values. * * @param id style ID * @param data tree data */ public WebTree ( final StyleId id, final Object[] data ) { this ( id, createTreeModel ( data ) ); } /** * Constructs tree with model based on specified values. * * @param id style ID * @param data tree data */ public WebTree ( final StyleId id, final Vector data ) { this ( id, createTreeModel ( data ) ); } /** * Constructs tree with model based on specified values. * * @param id style ID * @param data tree data */ public WebTree ( final StyleId id, final Hashtable data ) { this ( id, createTreeModel ( data ) ); } /** * Constructs tree with model based on specified root node. * * @param id style ID * @param root tree root node */ public WebTree ( final StyleId id, final N root ) { this ( id, new WebTreeModel ( root ) ); } /** * Constructs tree with model based on specified root node and which decides whether a node is a leaf node in the specified manner. * * @param id style ID * @param root tree root node * @param asksAllowsChildren false if any node can have children, true if each node is asked to see if it can have children */ public WebTree ( final StyleId id, final N root, final boolean asksAllowsChildren ) { this ( id, new WebTreeModel ( root, asksAllowsChildren ) ); } /** * Constructs tree with specified model. * * @param id style ID * @param newModel tree model */ public WebTree ( final StyleId id, final TreeModel newModel ) { super ( newModel ); setStyleId ( id ); } @Override public void setCellEditor ( final TreeCellEditor cellEditor ) { // Removing cell editor listeners from old cell editor if ( this.cellEditor != null ) { for ( final CellEditorListener listener : listenerList.getListeners ( CellEditorListener.class ) ) { this.cellEditor.removeCellEditorListener ( listener ); } } // Updating cell editor super.setCellEditor ( cellEditor ); // Adding cell editor listeners to new cell editor if ( cellEditor != null ) { for ( final CellEditorListener listener : listenerList.getListeners ( CellEditorListener.class ) ) { cellEditor.addCellEditorListener ( listener ); } } } /** * Unlike {@link JTree#getToolTipText()} this implementation takes row selection style into account. * That means that tooltips for {@link TreeSelectionStyle#line} will be displayed at any point in the row, not just on the node. * * @param event {@link MouseEvent} * @return tooltip text */ @Override public String getToolTipText ( final MouseEvent event ) { String tip = null; if ( event != null ) { final Point point = event.getPoint (); final WTreeUI ui = getUI (); final int row = ui.getExactRowForLocation ( point ); final TreeCellRenderer cellRenderer = getCellRenderer (); if ( row != -1 && cellRenderer != null ) { final TreePath path = getPathForRow ( row ); final Object value = path.getLastPathComponent (); final boolean selected = isRowSelected ( row ); final boolean expanded = isExpanded ( row ); final boolean leaf = getModel ().isLeaf ( value ); final Component renderer = cellRenderer.getTreeCellRendererComponent ( this, value, selected, expanded, leaf, row, true ); if ( renderer instanceof JComponent ) { final Rectangle pathBounds = getPathBounds ( path ); final MouseEvent newEvent = new MouseEvent ( renderer, event.getID (), event.getWhen (), event.getModifiers (), point.x - pathBounds.x, point.y - pathBounds.y, event.getXOnScreen (), event.getYOnScreen (), event.getClickCount (), event.isPopupTrigger (), MouseEvent.NOBUTTON ); final JComponent jComponent = ( JComponent ) renderer; tip = jComponent.getToolTipText ( newEvent ); } } } if ( tip == null ) { tip = getToolTipText (); } return tip; } /** * Adds tree cell editor listener. * These listeners act separately from the cell editor and will be moved to new tree cell editor automatically on set. * * @param listener cell editor listener to add */ public void addCellEditorListener ( final CellEditorListener listener ) { // Saving listener listenerList.add ( CellEditorListener.class, listener ); // Adding listener to the current cell editor if ( cellEditor != null ) { cellEditor.addCellEditorListener ( listener ); } } /** * Removes tree cell editor listener. * * @param listener cell editor listener to remove */ public void removeCellEditorListener ( final CellEditorListener listener ) { // Removing listener listenerList.remove ( CellEditorListener.class, listener ); // Removing listener from the current cell editor if ( cellEditor != null ) { cellEditor.removeCellEditorListener ( listener ); } } /** * Returns special state provider that can be set to check whether or not specific nodes are editable. * By default this provider is not specified and simply ignored by the tree. * * @return special state provider that can be set to check whether or not specific nodes are editable */ public Predicate getEditableStateProvider () { return editableStateProvider; } /** * Sets special state provider that can be set to check whether or not specific nodes are editable. * You can provide null to disable this state check at all. * * @param stateProvider special state provider that can be set to check whether or not specific nodes are editable */ public void setEditableStateProvider ( final Predicate stateProvider ) { this.editableStateProvider = stateProvider; } @Override public boolean isPathEditable ( final TreePath path ) { return super.isPathEditable ( path ) && isNodeEditable ( ( N ) path.getLastPathComponent () ); } /** * Returns whether the specified tree node is editable or not. * This method is an improved version of default JTree method isPathEditable. * * @param node node to check editable state for * @return true if the specified tree node is editable, false otherwise * @see #isPathEditable(javax.swing.tree.TreePath) */ public boolean isNodeEditable ( final N node ) { return editableStateProvider == null || editableStateProvider.test ( node ); } /** * Returns {@link TreeToolTipProvider}. * * @return {@link TreeToolTipProvider} */ public TreeToolTipProvider getToolTipProvider () { return toolTipProvider; } /** * Sets {@link TreeToolTipProvider}. * * @param provider {@link TreeToolTipProvider} */ public void setToolTipProvider ( final TreeToolTipProvider provider ) { this.toolTipProvider = provider; } /** * Expands the root path, assuming the current TreeModel has been set. */ public void expandRoot () { expandNode ( getRootNode () ); } /** * Expands all tree nodes in a single call. * It is not recommended to expand large trees this way since that might cause huge interface lags. */ public void expandAll () { int i = 0; while ( i < getRowCount () ) { expandRow ( i ); i++; } } /** * Expands all tree nodes accepted by filter in a single call. * It is not recommended to expand large trees this way since that might cause huge interface lags. * * @param shouldExpand expand filter */ public void expandAll ( final Filter shouldExpand ) { if ( shouldExpand == null ) { expandAll (); } else { final N rootNode = getRootNode (); expandAll ( rootNode, shouldExpand ); } } /** * Expands all child nodes of the specified node. * * @param node node to expand */ public void expandAll ( final N node ) { expandAll ( node, null ); } /** * Expands all child nodes accepted by filter in a single call. * * @param node node to expand * @param shouldExpand expand filter */ public void expandAll ( final N node, final Filter shouldExpand ) { if ( shouldExpand == null || shouldExpand.accept ( node ) ) { expandNode ( node ); for ( int i = 0; i < node.getChildCount (); i++ ) { expandAll ( ( N ) node.getChildAt ( i ), shouldExpand ); } } } /** * Expands all child nodes until the specified structure depth is reached. * Depth == 1 will force tree to expand all nodes under the root. * * @param depth max structure depth to be expanded */ public void expandAll ( final int depth ) { expandAllImpl ( getRootNode (), 0, depth ); } /** * Expands all child nodes until the specified max structure depth is reached. * * @param node current level parent node * @param currentDepth current depth level * @param maxDepth max depth level */ private void expandAllImpl ( final N node, final int currentDepth, final int maxDepth ) { final int depth = currentDepth + 1; for ( int i = 0; i < node.getChildCount (); i++ ) { final N child = ( N ) node.getChildAt ( i ); expandNode ( child ); if ( depth < maxDepth ) { expandAllImpl ( child, depth, maxDepth ); } } } /** * Expands the specified node. * * @param node node to expand */ public void expandNode ( final N node ) { expandPath ( getPathForNode ( node ) ); } /** * Returns whether node is expanded or not. * * @param node node to check * @return true if node is expanded, false otherwise */ public boolean isExpanded ( final N node ) { return isExpanded ( getPathForNode ( node ) ); } /** * Returns selected {@link MutableTreeNode} bounds. * * @return selected {@link MutableTreeNode} bounds */ public Rectangle getSelectedNodeBounds () { return getNodeBounds ( getSelectedNode () ); } /** * Returns {@link MutableTreeNode} bounds. * * @param node {@link MutableTreeNode} to retrieve bounds for * @return {@link MutableTreeNode} bounds */ public Rectangle getNodeBounds ( final N node ) { return getPathBounds ( getPathForNode ( node ) ); } /** * Returns combined bounds for the {@link List} of {@link MutableTreeNode}s. * * @param nodes {@link List} of {@link MutableTreeNode}s to combine bounds for * @return combined bounds for the {@link List} of {@link MutableTreeNode}s */ public Rectangle getNodeBounds ( final List nodes ) { if ( nodes == null || nodes.size () == 0 ) { return null; } else { Rectangle combined = null; for ( final N node : nodes ) { combined = GeometryUtils.getContainingRect ( combined, getNodeBounds ( node ) ); } return combined; } } /** * Returns row for the specified {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to find row for * @return row for the specified {@link MutableTreeNode} */ public int getRowForNode ( final N node ) { return getRowForPath ( getPathForNode ( node ) ); } /** * Returns {@link MutableTreeNode} for the specified row. * * @param row row to look for {@link MutableTreeNode} at * @return {@link MutableTreeNode} for the specified row */ public N getNodeForRow ( final int row ) { return getNodeForPath ( getPathForRow ( row ) ); } /** * Returns {@link TreePath} for specified {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to retrieve {@link TreePath} for * @return {@link TreePath} for specified {@link MutableTreeNode} */ public TreePath getPathForNode ( final N node ) { return node != null ? new TreePath ( TreeUtils.getPath ( node ) ) : null; } /** * Returns {@link MutableTreeNode} for specified {@link TreePath}. * * @param path {@link TreePath} to retrieve {@link MutableTreeNode} for * @return {@link MutableTreeNode} for specified {@link TreePath} */ public N getNodeForPath ( final TreePath path ) { return path != null ? ( N ) path.getLastPathComponent () : null; } /** * Returns {@link MutableTreeNode} at the exact location. * Could return {@code null} if there is no {@link MutableTreeNode} at the specified location. * Could also return {@code null} if there is no {@link TreeModel} or nothing is viewable. * * @param location location to process * @return {@link MutableTreeNode} at the exact location */ public N getNodeForLocation ( final Point location ) { return getNodeForLocation ( location.x, location.y ); } /** * Returns {@link MutableTreeNode} at the exact location. * Could return {@code null} if there is no {@link MutableTreeNode} at the specified location. * Could also return {@code null} if there is no {@link TreeModel} or nothing is viewable. * * @param x location X coordinate * @param y location Y coordinate * @return {@link MutableTreeNode} at the exact location */ public N getNodeForLocation ( final int x, final int y ) { return getNodeForPath ( getPathForLocation ( x, y ) ); } /** * Returns {@link TreePath} for the {@link MutableTreeNode} at the exact location. * Could return {@code null} if there is no {@link MutableTreeNode} at the specified location. * Could also return {@code null} if there is no {@link TreeModel} or nothing is viewable. * * @param location location to process * @return {@link TreePath} for the {@link MutableTreeNode} at the exact location */ public TreePath getPathForLocation ( final Point location ) { return getPathForLocation ( location.x, location.y ); } /** * Returns {@link MutableTreeNode} closest to the specified location. * * @param location location to process * @return {@link MutableTreeNode} closest to the specified location */ public N getClosestNodeForLocation ( final Point location ) { return getClosestNodeForLocation ( location.x, location.y ); } /** * Returns {@link MutableTreeNode} closest to the specified location. * * @param x location X coordinate * @param y location Y coordinate * @return {@link MutableTreeNode} closest to the specified location */ public N getClosestNodeForLocation ( final int x, final int y ) { return getNodeForPath ( getClosestPathForLocation ( x, y ) ); } /** * Returns {@link TreePath} for the {@link MutableTreeNode} closest to the specified location. * Could return {@code null} if there is no {@link TreeModel} or nothing is viewable. * * @param location location to process * @return {@link TreePath} for the {@link MutableTreeNode} closest to the specified location */ public TreePath getClosestPathForLocation ( final Point location ) { return getClosestPathForLocation ( location.x, location.y ); } /** * Returns whether specified {@link MutableTreeNode} is selected or not. * * @param node {@link MutableTreeNode} to check * @return {@code true} if specified {@link MutableTreeNode} is selected, {@code false} otherwise */ public boolean isSelected ( final N node ) { return isPathSelected ( getPathForNode ( node ) ); } /** * Returns selected {@link MutableTreeNode}. * * @return selected {@link MutableTreeNode} */ public N getSelectedNode () { return getNodeForPath ( getSelectionPath () ); } /** * Returns {@link List} of all selected {@link MutableTreeNode}s. * * @return {@link List} of all selected {@link MutableTreeNode}s * @see NodesAcceptPolicy#all */ public List getSelectedNodes () { return getSelectedNodes ( NodesAcceptPolicy.all ); } /** * Returns {@link List} of selected {@link MutableTreeNode}s filtered by {@link NodesAcceptPolicy}. * * @param policy {@link NodesAcceptPolicy} used for filtering {@link MutableTreeNode}s * @return {@link List} of selected {@link MutableTreeNode}s filtered by {@link NodesAcceptPolicy} * @see NodesAcceptPolicy */ public List getSelectedNodes ( final NodesAcceptPolicy policy ) { final TreePath[] selectionPaths = getSelectionPaths (); final List selectedNodes; if ( selectionPaths != null ) { selectedNodes = new ArrayList ( selectionPaths.length ); for ( final TreePath path : selectionPaths ) { selectedNodes.add ( getNodeForPath ( path ) ); } } else { selectedNodes = new ArrayList (); } if ( policy != null ) { policy.filter ( this, selectedNodes ); } return selectedNodes; } /** * Returns {@link List} of selected {@link MutableTreeNode}s which are currently within {@link #getVisibleRect()} of this tree. * This will include {@link MutableTreeNode}s that are fully visible and those that are partially visible as well. * * @return {@link List} of selected {@link MutableTreeNode}s which are currently within {@link #getVisibleRect()} of this tree */ public List getVisibleSelectedNodes () { final List selectedNodes = getSelectedNodes (); final Rectangle vr = getVisibleRect (); final Iterator iterator = selectedNodes.iterator (); while ( iterator.hasNext () ) { final N node = iterator.next (); if ( !vr.intersects ( getNodeBounds ( node ) ) ) { iterator.remove (); } } return selectedNodes; } /** * Returns user object extracted from the selected {@link MutableTreeNode}. * * @return user object extracted from the selected {@link MutableTreeNode} */ public U getSelectedUserObject () { return getUserObject ( getSelectedNode () ); } /** * Returns {@link List} of user objects extracted from all selected {@link MutableTreeNode}s. * * @return {@link List} of user objects extracted from all selected {@link MutableTreeNode}s * @see NodesAcceptPolicy#all */ public List getSelectedUserObjects () { return getSelectedUserObjects ( NodesAcceptPolicy.all ); } /** * Returns {@link List} of user objects extracted from selected {@link MutableTreeNode}s filtered by {@link NodesAcceptPolicy}. * * @param policy {@link NodesAcceptPolicy} used for filtering {@link MutableTreeNode}s * @return {@link List} of user objects extracted from selected {@link MutableTreeNode}s filtered by {@link NodesAcceptPolicy} * @see NodesAcceptPolicy */ public List getSelectedUserObjects ( final NodesAcceptPolicy policy ) { final List selectedNodes = getSelectedNodes ( policy ); final List selectedUserObjects = new ArrayList ( selectedNodes.size () ); for ( final N selectedNode : selectedNodes ) { selectedUserObjects.add ( ( U ) getUserObject ( selectedNode ) ); } return selectedUserObjects; } /** * Returns user object extracted from the specified {@link MutableTreeNode}. * Unfortunately {@code node.getUserObject()} method is not available in {@link TreeNode} or {@link MutableTreeNode} interfaces, * that is why we cannot rely on node having this method and have to manually check node type and extract user object. * Although this method can be overridden to provide more options for user object extraction from the {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to extract user object from * @param user object type * @return user object extracted from the specified {@link MutableTreeNode} */ protected U getUserObject ( final N node ) { final U selectedUserObject; if ( node instanceof WebTreeNode ) { selectedUserObject = ( U ) ( ( WebTreeNode ) node ).getUserObject (); } else if ( node instanceof DefaultMutableTreeNode ) { selectedUserObject = ( U ) ( ( DefaultMutableTreeNode ) node ).getUserObject (); } else { selectedUserObject = null; } return selectedUserObject; } /** * Selects {@link MutableTreeNode} under the specified point. * * @param point point to look for {@link MutableTreeNode} */ public void selectNodeUnderPoint ( final Point point ) { selectNodeUnderPoint ( point.x, point.y ); } /** * Selects {@link MutableTreeNode} under the specified point. * * @param x point X coordinate * @param y point Y coordinate */ public void selectNodeUnderPoint ( final int x, final int y ) { setSelectionPath ( getPathForLocation ( x, y ) ); } /** * Sets specified {@link MutableTreeNode} as selected. * Any other selected {@link MutableTreeNode}s will be deselected. * * @param node {@link MutableTreeNode} to select */ public void setSelectedNode ( final N node ) { final TreePath path = getPathForNode ( node ); if ( path != null ) { setSelectionPath ( path ); } } /** * Sets specified {@link List} of {@link MutableTreeNode}s as selected. * Any other selected {@link MutableTreeNode}s will be deselected. * * @param nodes {@link List} of {@link MutableTreeNode}s to select */ public void setSelectedNodes ( final List nodes ) { final TreePath[] paths = new TreePath[ nodes.size () ]; for ( int i = 0; i < nodes.size (); i++ ) { paths[ i ] = getPathForNode ( nodes.get ( i ) ); } setSelectionPaths ( paths ); } /** * Sets specified {@link MutableTreeNode}s as selected. * Any other selected {@link MutableTreeNode}s will be deselected. * * @param nodes {@link MutableTreeNode}s to select */ public void setSelectedNodes ( final N[] nodes ) { final TreePath[] paths = new TreePath[ nodes.length ]; for ( int i = 0; i < nodes.length; i++ ) { paths[ i ] = getPathForNode ( nodes[ i ] ); } setSelectionPaths ( paths ); } /** * Returns first visible leaf {@link MutableTreeNode} from the top of the tree. * This doesn't include {@link MutableTreeNode}s under collapsed paths. * This does include {@link MutableTreeNode}s which are not in visible rect. * * @return first visible leaf {@link MutableTreeNode} from the top of the tree */ public N getFirstVisibleLeafNode () { for ( int i = 0; i < getRowCount (); i++ ) { final N node = getNodeForRow ( i ); if ( getModel ().isLeaf ( node ) ) { return node; } } return null; } /** * Selects first visible leaf {@link MutableTreeNode} from the top of the tree. */ public void selectFirstVisibleLeafNode () { final N node = getFirstVisibleLeafNode (); if ( node != null ) { setSelectedNode ( node ); } } /** * Selects row next to currently selected. * First row will be selected if none or last row was selected. */ public void selectNextRow () { selectNextRow ( true ); } /** * Selects row next to currently selected. * First row will be selected if none was selected. * First row will be selected if last row was selected and cycling is allowed. * * @param cycle whether or not should allow cycled selection */ public void selectNextRow ( final boolean cycle ) { final int row = getLeadSelectionRow (); if ( row != -1 ) { if ( row < getRowCount () - 1 ) { setSelectionRow ( row + 1 ); } else if ( cycle ) { setSelectionRow ( 0 ); } } else { setSelectionRow ( 0 ); } } /** * Selects row next to currently selected. * Last row will be selected if none or first row was selected. */ public void selectPreviousRow () { selectPreviousRow ( true ); } /** * Selects row previous to currently selected. * Last row will be selected if none or last was selected. * Last row will be selected if first row was selected and cycling is allowed. * * @param cycle whether or not should allow cycled selection */ public void selectPreviousRow ( final boolean cycle ) { final int row = getLeadSelectionRow (); if ( row != -1 ) { if ( row > 0 ) { setSelectionRow ( row - 1 ); } else if ( cycle ) { setSelectionRow ( getRowCount () - 1 ); } } else { setSelectionRow ( getRowCount () - 1 ); } } /** * Returns root {@link MutableTreeNode}. * * @return root {@link MutableTreeNode} */ public N getRootNode () { return ( N ) getModel ().getRoot (); } /** * Returns {@link List} of all {@link MutableTreeNode}s available in this tree. * * @return {@link List} of all {@link MutableTreeNode}s available in this tree */ public List getAvailableNodes () { return getAvailableNodes ( getRootNode () ); } /** * Returns {@link List} of all {@link MutableTreeNode}s available under the specified {@link MutableTreeNode} including that node. * * @param parent {@link MutableTreeNode} to collect nodes for * @return {@link List} of all {@link MutableTreeNode}s available under the specified {@link MutableTreeNode} including that node */ public List getAvailableNodes ( final N parent ) { final List nodes = new ArrayList (); getAllNodesImpl ( nodes, getRootNode () ); return nodes; } /** * Collects {@link List} of all {@link MutableTreeNode}s available under the specified {@link MutableTreeNode} including that node. * * @param nodes {@link List} into which all {@link MutableTreeNode}s should be collected * @param parent {@link MutableTreeNode} to start collecting from */ private void getAllNodesImpl ( final List nodes, final N parent ) { nodes.add ( parent ); for ( int i = 0; i < parent.getChildCount (); i++ ) { getAllNodesImpl ( nodes, ( N ) parent.getChildAt ( i ) ); } } /** * Returns tree selection mode. * * @return tree selection mode * @see TreeSelectionModel#SINGLE_TREE_SELECTION * @see TreeSelectionModel#CONTIGUOUS_TREE_SELECTION * @see TreeSelectionModel#DISCONTIGUOUS_TREE_SELECTION */ public int getSelectionMode () { return getSelectionModel ().getSelectionMode (); } /** * Sets tree selection mode. * * @param mode tree selection mode * @see TreeSelectionModel#SINGLE_TREE_SELECTION * @see TreeSelectionModel#CONTIGUOUS_TREE_SELECTION * @see TreeSelectionModel#DISCONTIGUOUS_TREE_SELECTION */ public void setSelectionMode ( final int mode ) { getSelectionModel ().setSelectionMode ( mode ); } /** * Sets whether or not multiple nodes selection is allowed. * * @return {@code true} if multiple nodes selection is allowed, {@code false} otherwise * @see #getSelectionMode() */ public boolean isMultipleSelectionAllowed () { return Objects.equals ( getSelectionMode (), CONTIGUOUS_TREE_SELECTION, DISCONTIGUOUS_TREE_SELECTION ); } /** * Sets whether or not multiple nodes selection is allowed. * * @param allowed whether or not multiple nodes selection is allowed * @see #setSelectionMode(int) */ public void setMultipleSelectionAllowed ( final boolean allowed ) { setSelectionMode ( allowed ? DISCONTIGUOUS_TREE_SELECTION : SINGLE_TREE_SELECTION ); } /** * Returns whether tree automatically scrolls to selection or not. * * @return true if tree automatically scrolls to selection, false otherwise */ public boolean isScrollToSelection () { return scrollToSelectionListener != null; } /** * Sets whether or not tree should automatically scroll to selected {@link MutableTreeNode}s. * * @param scroll whether or not tree should automatically scroll to selected {@link MutableTreeNode}s */ public void setScrollToSelection ( final boolean scroll ) { if ( scroll ) { if ( !isScrollToSelection () ) { scrollToSelectionListener = new TreeSelectionListener () { @Override public void valueChanged ( final TreeSelectionEvent e ) { scrollToSelection (); } }; addTreeSelectionListener ( scrollToSelectionListener ); } } else { if ( isScrollToSelection () ) { removeTreeSelectionListener ( scrollToSelectionListener ); scrollToSelectionListener = null; } } } /** * Scrolls tree view to the beginning of the tree. */ public void scrollToStart () { scrollRectToVisible ( new Rectangle ( 0, 0, 1, 1 ) ); } /** * Scrolls tree view to selected nodes. */ public void scrollToSelection () { final Rectangle bounds = getPathBounds ( getSelectionPath () ); if ( bounds != null ) { // Ignore scroll action if node is already fully visible final Rectangle vr = getVisibleRect (); if ( !vr.contains ( bounds ) ) { // Leave additional 1/2 of visible height on top of the node // Otherwise it is hard to look where this node is located bounds.y = bounds.y + bounds.height / 2 - vr.height / 2; // Put node into the middle of visible area if ( vr.width > bounds.width ) { bounds.x = bounds.x + bounds.width / 2 - vr.width / 2; } // Setup width and height we want to see bounds.width = vr.width; bounds.height = vr.height; scrollRectToVisible ( bounds ); } } } /** * Scrolls tree view to specified {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to scroll tree view to */ public void scrollToNode ( final N node ) { scrollToNode ( node, false ); } /** * Scrolls tree view to specified {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to scroll tree view to * @param centered whether or not should vertically center specified {@link MutableTreeNode} in view bounds */ public void scrollToNode ( final N node, final boolean centered ) { final Rectangle nodeBounds = getNodeBounds ( node ); if ( nodeBounds != null ) { if ( node.getParent () != null ) { final int indent = ( getUI ().getLeftChildIndent () + getUI ().getRightChildIndent () ) * 2; nodeBounds.x -= indent; nodeBounds.width += indent; } final Dimension visibleBounds = getVisibleRect ().getSize (); if ( nodeBounds.width > visibleBounds.width ) { nodeBounds.width = visibleBounds.width; } if ( centered ) { nodeBounds.y = nodeBounds.y + nodeBounds.height / 2 - visibleBounds.height / 2; nodeBounds.height = visibleBounds.height; } scrollRectToVisible ( nodeBounds ); } } /** * Starts editing selected {@link MutableTreeNode}. */ public void startEditingSelectedNode () { startEditingNode ( getSelectedNode () ); } /** * Starts editing specified {@link MutableTreeNode}. * * @param node {@link MutableTreeNode} to edit */ public void startEditingNode ( final N node ) { if ( node != null ) { final TreePath path = getPathForNode ( node ); if ( path != null ) { if ( !isVisible ( path ) ) { expandPath ( path ); } startEditingAtPath ( path ); } } } /** * Forces specified {@link MutableTreeNode} view update. * This can be used to update {@link MutableTreeNode} renderer size/view if data it is based on has changed. * * @param node {@link MutableTreeNode} to update view for */ public void updateNode ( final N node ) { final TreeModel model = getModel (); if ( model instanceof WebTreeModel ) { ( ( WebTreeModel ) getModel () ).updateNode ( node ); } } /** * Forces specified {@link MutableTreeNode}s view update. * This can be used to update {@link MutableTreeNode}s renderer size/view if data it is based on has changed. * * @param nodes {@link MutableTreeNode}s to update view for */ public void updateNodes ( final N... nodes ) { final TreeModel model = getModel (); if ( model instanceof WebTreeModel ) { ( ( WebTreeModel ) model ).updateNodes ( nodes ); } } /** * Forces tree nodes to be updated. * This can be used to update nodes sizes/view if renderer has changed. * * @param nodes tree nodes to be updated */ public void updateNodes ( final List nodes ) { final TreeModel model = getModel (); if ( model instanceof WebTreeModel ) { ( ( WebTreeModel ) model ).updateNodes ( nodes ); } } /** * Updates all nodes visible in the tree. * This includes nodes which are off screen (hidden behind the scroll). * This can be used to update nodes sizes/view if renderer has changed. */ public void updateVisibleNodes () { final int rows = getRowCount (); final List nodes = new ArrayList ( rows ); for ( int i = 0; i < rows; i++ ) { nodes.add ( getNodeForRow ( i ) ); } updateNodes ( nodes ); } /** * Returns tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @return tree expansion and selection states */ public TreeState getTreeState () { return TreeUtils.getTreeState ( this ); } /** * Returns tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param saveSelection whether to save selection states or not * @return tree expansion and selection states */ public TreeState getTreeState ( final boolean saveSelection ) { return TreeUtils.getTreeState ( this, saveSelection ); } /** * Returns tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param node node to save state for * @return tree expansion and selection states */ public TreeState getTreeState ( final N node ) { return TreeUtils.getTreeState ( this, node ); } /** * Returns tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param node node to save state for * @param saveSelection whether to save selection states or not * @return tree expansion and selection states */ public TreeState getTreeState ( final N node, final boolean saveSelection ) { return TreeUtils.getTreeState ( this, node, saveSelection ); } /** * Restores tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param treeState tree expansion and selection states */ public void setTreeState ( final TreeState treeState ) { TreeUtils.setTreeState ( this, treeState ); } /** * Restores tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param treeState tree expansion and selection states * @param restoreSelection whether to restore selection states or not */ public void setTreeState ( final TreeState treeState, final boolean restoreSelection ) { TreeUtils.setTreeState ( this, treeState, restoreSelection ); } /** * Restores tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param treeState tree expansion and selection states * @param node node to restore state for */ public void setTreeState ( final TreeState treeState, final N node ) { TreeUtils.setTreeState ( this, treeState, node ); } /** * Restores tree expansion and selection states. * Tree nodes must be instances of UniqueNode class. * * @param treeState tree expansion and selection states * @param node node to restore state for * @param restoreSelection whether to restore selection states or not */ public void setTreeState ( final TreeState treeState, final N node, final boolean restoreSelection ) { TreeUtils.setTreeState ( this, treeState, node, restoreSelection ); } /** * Returns tree selection style. * * @return tree selection style */ public TreeSelectionStyle getSelectionStyle () { return getUI ().getSelectionStyle (); } /** * Sets tree selection style. * * @param style tree selection style */ public void setSelectionStyle ( final TreeSelectionStyle style ) { getUI ().setSelectionStyle ( style ); } /** * Returns whether tree should auto-expand nodes on selection or not. * * @return true if tree should auto-expand nodes on selection, false otherwise */ public boolean isExpandSelected () { return TreeSelectionExpandBehavior.isInstalled ( this ); } /** * Sets whether tree should auto-expand nodes on selection or not. * * @param expand whether tree should auto-expand nodes on selection or not */ public void setExpandSelected ( final boolean expand ) { if ( expand ) { if ( !isExpandSelected () ) { TreeSelectionExpandBehavior.install ( this ); } } else { if ( isExpandSelected () ) { TreeSelectionExpandBehavior.uninstall ( this ); } } } /** * Returns whether tree should auto-expand single child nodes or not. * If set to true when any node is expanded and there is only one single child node in it - it will be automatically expanded. * * @return true if tree should auto-expand single child nodes, false otherwise */ public boolean isAutoExpandSingleChildNode () { return TreeSingleChildExpandBehavior.isInstalled ( this ); } /** * Sets whether tree should auto-expand single child nodes or not. * If set to true when any node is expanded and there is only one single child node in it - it will be automatically expanded. * * @param expand whether tree should auto-expand single child nodes or not */ public void setAutoExpandSingleChildNode ( final boolean expand ) { if ( expand ) { if ( !isAutoExpandSingleChildNode () ) { TreeSingleChildExpandBehavior.install ( this ); } } else { if ( isAutoExpandSingleChildNode () ) { TreeSingleChildExpandBehavior.uninstall ( this ); } } } /** * Returns whether or not nodes should be selected on hover. * * @return true if nodes should be selected on hover, false otherwise */ public boolean isSelectOnHover () { return TreeHoverSelectionBehavior.isInstalled ( this ); } /** * Sets whether or not nodes should be selected on hover. * * @param select whether or not nodes should be selected on hover */ public void setSelectOnHover ( final boolean select ) { if ( select ) { if ( !isSelectOnHover () ) { TreeHoverSelectionBehavior.install ( this ); } } else { if ( isSelectOnHover () ) { TreeHoverSelectionBehavior.uninstall ( this ); } } } @Override public StyleId getDefaultStyleId () { return StyleId.tree; } @Override public StyleId getStyleId () { return StyleManager.getStyleId ( this ); } @Override public StyleId setStyleId ( final StyleId id ) { return StyleManager.setStyleId ( this, id ); } @Override public StyleId resetStyleId () { return StyleManager.resetStyleId ( this ); } @Override public Skin getSkin () { return StyleManager.getSkin ( this ); } @Override public Skin setSkin ( final Skin skin ) { return StyleManager.setSkin ( this, skin ); } @Override public Skin setSkin ( final Skin skin, final boolean recursively ) { return StyleManager.setSkin ( this, skin, recursively ); } @Override public Skin resetSkin () { return StyleManager.resetSkin ( this ); } @Override public void addStyleListener ( final StyleListener listener ) { StyleManager.addStyleListener ( this, listener ); } @Override public void removeStyleListener ( final StyleListener listener ) { StyleManager.removeStyleListener ( this, listener ); } @Override public Painter getCustomPainter () { return StyleManager.getCustomPainter ( this ); } @Override public Painter setCustomPainter ( final Painter painter ) { return StyleManager.setCustomPainter ( this, painter ); } @Override public boolean resetCustomPainter () { return StyleManager.resetCustomPainter ( this ); } @Override public Shape getShape () { return ShapeMethodsImpl.getShape ( this ); } @Override public boolean isShapeDetectionEnabled () { return ShapeMethodsImpl.isShapeDetectionEnabled ( this ); } @Override public void setShapeDetectionEnabled ( final boolean enabled ) { ShapeMethodsImpl.setShapeDetectionEnabled ( this, enabled ); } @Override public Insets getMargin () { return MarginMethodsImpl.getMargin ( this ); } @Override public void setMargin ( final int margin ) { MarginMethodsImpl.setMargin ( this, margin ); } @Override public void setMargin ( final int top, final int left, final int bottom, final int right ) { MarginMethodsImpl.setMargin ( this, top, left, bottom, right ); } @Override public void setMargin ( final Insets margin ) { MarginMethodsImpl.setMargin ( this, margin ); } @Override public Insets getPadding () { return PaddingMethodsImpl.getPadding ( this ); } @Override public void setPadding ( final int padding ) { PaddingMethodsImpl.setPadding ( this, padding ); } @Override public void setPadding ( final int top, final int left, final int bottom, final int right ) { PaddingMethodsImpl.setPadding ( this, top, left, bottom, right ); } @Override public void setPadding ( final Insets padding ) { PaddingMethodsImpl.setPadding ( this, padding ); } /** * Adds hover listener. * * @param listener hover listener to add */ public void addHoverListener ( final HoverListener listener ) { listenerList.add ( HoverListener.class, listener ); } /** * Removes hover listener. * * @param listener hover listener to remove */ public void removeHoverListener ( final HoverListener listener ) { listenerList.remove ( HoverListener.class, listener ); } /** * Returns hover listeners. * * @return hover listeners */ public HoverListener[] getHoverListeners () { return listenerList.getListeners ( HoverListener.class ); } /** * Informs about hover node change. * * @param previous previous hover node * @param current current hover node */ public void fireHoverChanged ( final N previous, final N current ) { for ( final HoverListener listener : getHoverListeners () ) { listener.hoverChanged ( previous, current ); } } @Override public int getScrollableUnitIncrement ( final Rectangle visibleRect, final int orientation, final int direction ) { int increment = super.getScrollableUnitIncrement ( visibleRect, orientation, direction ); // Minor fix for Swing JTree scrollable issue // Without this we will always scroll to first row bounds, but will never get to actual zero Y on visible rect // This will ensure to add top insets to the increment in case we are scrolling the tree up and we got to first node if ( orientation == SwingConstants.VERTICAL && direction < 0 ) { final Insets i = getInsets (); if ( visibleRect.y - increment == i.top ) { increment += i.top; } } return increment; } /** * Repaints specified tree row. * * @param row row index */ public void repaint ( final int row ) { repaint ( getUI ().getRowBounds ( row ) ); } /** * Repaints all tree rows in specified range. * * @param from first row index * @param to last row index */ public void repaint ( final int from, final int to ) { final WTreeUI ui = getUI (); final Rectangle fromBounds = ui.getRowBounds ( from ); final Rectangle toBounds = ui.getRowBounds ( to ); final Rectangle rect = GeometryUtils.getContainingRect ( fromBounds, toBounds ); if ( rect != null ) { repaint ( rect ); } } /** * Repaints specified node. * * @param node node to repaint */ public void repaint ( final N node ) { if ( node != null ) { final Rectangle bounds = getNodeBounds ( node ); if ( bounds != null ) { repaint ( bounds ); } } } /** * Repaints specified node. * * @param nodes nodes to repaint */ public void repaint ( final List nodes ) { if ( nodes != null && nodes.size () > 0 ) { Rectangle summ = null; for ( final N node : nodes ) { summ = GeometryUtils.getContainingRect ( summ, getNodeBounds ( node ) ); } if ( summ != null ) { repaint ( summ ); } } } @Override public MouseAdapter onNodeDoubleClick ( final TreeNodeEventRunnable runnable ) { return TreeEventMethodsImpl.onNodeDoubleClick ( this, runnable ); } @Override public MouseAdapter onNodeDoubleClick ( final Predicate condition, final TreeNodeEventRunnable runnable ) { return TreeEventMethodsImpl.onNodeDoubleClick ( this, condition, runnable ); } @Override public MouseAdapter onMousePress ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMousePress ( this, runnable ); } @Override public MouseAdapter onMousePress ( final MouseButton mouseButton, final MouseEventRunnable runnable ) { return EventMethodsImpl.onMousePress ( this, mouseButton, runnable ); } @Override public MouseAdapter onMouseEnter ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseEnter ( this, runnable ); } @Override public MouseAdapter onMouseExit ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseExit ( this, runnable ); } @Override public MouseAdapter onMouseDrag ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseDrag ( this, runnable ); } @Override public MouseAdapter onMouseDrag ( final MouseButton mouseButton, final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseDrag ( this, mouseButton, runnable ); } @Override public MouseAdapter onMouseClick ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseClick ( this, runnable ); } @Override public MouseAdapter onMouseClick ( final MouseButton mouseButton, final MouseEventRunnable runnable ) { return EventMethodsImpl.onMouseClick ( this, mouseButton, runnable ); } @Override public MouseAdapter onDoubleClick ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onDoubleClick ( this, runnable ); } @Override public MouseAdapter onMenuTrigger ( final MouseEventRunnable runnable ) { return EventMethodsImpl.onMenuTrigger ( this, runnable ); } @Override public KeyAdapter onKeyType ( final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyType ( this, runnable ); } @Override public KeyAdapter onKeyType ( final HotkeyData hotkey, final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyType ( this, hotkey, runnable ); } @Override public KeyAdapter onKeyPress ( final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyPress ( this, runnable ); } @Override public KeyAdapter onKeyPress ( final HotkeyData hotkey, final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyPress ( this, hotkey, runnable ); } @Override public KeyAdapter onKeyRelease ( final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyRelease ( this, runnable ); } @Override public KeyAdapter onKeyRelease ( final HotkeyData hotkey, final KeyEventRunnable runnable ) { return EventMethodsImpl.onKeyRelease ( this, hotkey, runnable ); } @Override public FocusAdapter onFocusGain ( final FocusEventRunnable runnable ) { return EventMethodsImpl.onFocusGain ( this, runnable ); } @Override public FocusAdapter onFocusLoss ( final FocusEventRunnable runnable ) { return EventMethodsImpl.onFocusLoss ( this, runnable ); } @Override public MouseAdapter onDragStart ( final int shift, final MouseEventRunnable runnable ) { return EventMethodsImpl.onDragStart ( this, shift, runnable ); } @Override public MouseAdapter onDragStart ( final int shift, final MouseButton mouseButton, final MouseEventRunnable runnable ) { return EventMethodsImpl.onDragStart ( this, shift, mouseButton, runnable ); } @Override public void addLanguageListener ( final LanguageListener listener ) { UILanguageManager.addLanguageListener ( this, listener ); } @Override public void removeLanguageListener ( final LanguageListener listener ) { UILanguageManager.removeLanguageListener ( this, listener ); } @Override public void removeLanguageListeners () { UILanguageManager.removeLanguageListeners ( this ); } @Override public void addDictionaryListener ( final DictionaryListener listener ) { UILanguageManager.addDictionaryListener ( this, listener ); } @Override public void removeDictionaryListener ( final DictionaryListener listener ) { UILanguageManager.removeDictionaryListener ( this, listener ); } @Override public void removeDictionaryListeners () { UILanguageManager.removeDictionaryListeners ( this ); } @Override public void registerSettings ( final Configuration configuration ) { UISettingsManager.registerComponent ( this, configuration ); } @Override public void registerSettings ( final SettingsProcessor processor ) { UISettingsManager.registerComponent ( this, processor ); } @Override public void unregisterSettings () { UISettingsManager.unregisterComponent ( this ); } @Override public void loadSettings () { UISettingsManager.loadSettings ( this ); } @Override public void saveSettings () { UISettingsManager.saveSettings ( this ); } @Override public WebTree setPlainFont () { return FontMethodsImpl.setPlainFont ( this ); } @Override public WebTree setPlainFont ( final boolean apply ) { return FontMethodsImpl.setPlainFont ( this, apply ); } @Override public boolean isPlainFont () { return FontMethodsImpl.isPlainFont ( this ); } @Override public WebTree setBoldFont () { return FontMethodsImpl.setBoldFont ( this ); } @Override public WebTree setBoldFont ( final boolean apply ) { return FontMethodsImpl.setBoldFont ( this, apply ); } @Override public boolean isBoldFont () { return FontMethodsImpl.isBoldFont ( this ); } @Override public WebTree setItalicFont () { return FontMethodsImpl.setItalicFont ( this ); } @Override public WebTree setItalicFont ( final boolean apply ) { return FontMethodsImpl.setItalicFont ( this, apply ); } @Override public boolean isItalicFont () { return FontMethodsImpl.isItalicFont ( this ); } @Override public WebTree setFontStyle ( final boolean bold, final boolean italic ) { return FontMethodsImpl.setFontStyle ( this, bold, italic ); } @Override public WebTree setFontStyle ( final int style ) { return FontMethodsImpl.setFontStyle ( this, style ); } @Override public WebTree setFontSize ( final int fontSize ) { return FontMethodsImpl.setFontSize ( this, fontSize ); } @Override public WebTree changeFontSize ( final int change ) { return FontMethodsImpl.changeFontSize ( this, change ); } @Override public int getFontSize () { return FontMethodsImpl.getFontSize ( this ); } @Override public WebTree setFontSizeAndStyle ( final int fontSize, final boolean bold, final boolean italic ) { return FontMethodsImpl.setFontSizeAndStyle ( this, fontSize, bold, italic ); } @Override public WebTree setFontSizeAndStyle ( final int fontSize, final int style ) { return FontMethodsImpl.setFontSizeAndStyle ( this, fontSize, style ); } @Override public WebTree setFontName ( final String fontName ) { return FontMethodsImpl.setFontName ( this, fontName ); } @Override public String getFontName () { return FontMethodsImpl.getFontName ( this ); } @Override public int getPreferredWidth () { return SizeMethodsImpl.getPreferredWidth ( this ); } @Override public WebTree setPreferredWidth ( final int preferredWidth ) { return SizeMethodsImpl.setPreferredWidth ( this, preferredWidth ); } @Override public int getPreferredHeight () { return SizeMethodsImpl.getPreferredHeight ( this ); } @Override public WebTree setPreferredHeight ( final int preferredHeight ) { return SizeMethodsImpl.setPreferredHeight ( this, preferredHeight ); } @Override public int getMinimumWidth () { return SizeMethodsImpl.getMinimumWidth ( this ); } @Override public WebTree setMinimumWidth ( final int minimumWidth ) { return SizeMethodsImpl.setMinimumWidth ( this, minimumWidth ); } @Override public int getMinimumHeight () { return SizeMethodsImpl.getMinimumHeight ( this ); } @Override public WebTree setMinimumHeight ( final int minimumHeight ) { return SizeMethodsImpl.setMinimumHeight ( this, minimumHeight ); } @Override public int getMaximumWidth () { return SizeMethodsImpl.getMaximumWidth ( this ); } @Override public WebTree setMaximumWidth ( final int maximumWidth ) { return SizeMethodsImpl.setMaximumWidth ( this, maximumWidth ); } @Override public int getMaximumHeight () { return SizeMethodsImpl.getMaximumHeight ( this ); } @Override public WebTree setMaximumHeight ( final int maximumHeight ) { return SizeMethodsImpl.setMaximumHeight ( this, maximumHeight ); } @Override public Dimension getPreferredSize () { return SizeMethodsImpl.getPreferredSize ( this, super.getPreferredSize () ); } @Override public Dimension getOriginalPreferredSize () { return SizeMethodsImpl.getOriginalPreferredSize ( this, super.getPreferredSize () ); } @Override public WebTree setPreferredSize ( final int width, final int height ) { return SizeMethodsImpl.setPreferredSize ( this, width, height ); } /** * Returns the look and feel (LaF) object that renders this component. * * @return the {@link WTreeUI} object that renders this component */ @Override public WTreeUI getUI () { return ( WTreeUI ) super.getUI (); } /** * Sets the LaF object that renders this component. * * @param ui {@link WTreeUI} */ public void setUI ( final WTreeUI ui ) { super.setUI ( ui ); } @Override public void updateUI () { StyleManager.getDescriptor ( this ).updateUI ( this ); } @Override public String getUIClassID () { return StyleManager.getDescriptor ( this ).getUIClassId (); } /** * Returns a TreeModel wrapping the specified object. * If the object is an array of Object, Hashtable or Vector then a new root node is created with each of the incoming objects as * children. Otherwise, a new root is created with the specified object as its value. * * @param data data object used as the foundation for the TreeModel * @return a TreeModel wrapping the specified object */ protected static TreeModel createTreeModel ( final Object data ) { final DefaultMutableTreeNode root; if ( data instanceof Object[] || data instanceof Hashtable || data instanceof Vector ) { root = new DefaultMutableTreeNode ( "root" ); DynamicUtilTreeNode.createChildren ( root, data ); } else { root = new DynamicUtilTreeNode ( "root", data ); } return new WebTreeModel ( root, false ); } /** * Creates and returns a sample TreeModel. * Used primarily for beanbuilders to show something interesting. * * @return the default TreeModel */ public static TreeModel createDefaultTreeModel () { final UniqueNode root = new UniqueNode ( "JTree" ); UniqueNode parent = new UniqueNode ( "colors" ); parent.add ( new UniqueNode ( "blue" ) ); parent.add ( new UniqueNode ( "violet" ) ); parent.add ( new UniqueNode ( "red" ) ); parent.add ( new UniqueNode ( "yellow" ) ); root.add ( parent ); parent = new UniqueNode ( "sports" ); parent.add ( new UniqueNode ( "basketball" ) ); parent.add ( new UniqueNode ( "soccer" ) ); parent.add ( new UniqueNode ( "football" ) ); parent.add ( new UniqueNode ( "hockey" ) ); root.add ( parent ); parent = new UniqueNode ( "food" ); parent.add ( new UniqueNode ( "hot dogs" ) ); parent.add ( new UniqueNode ( "pizza" ) ); parent.add ( new UniqueNode ( "ravioli" ) ); parent.add ( new UniqueNode ( "bananas" ) ); root.add ( parent ); return new WebTreeModel ( root ); } }