mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 01:54:47 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,534 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.event.TreeModelEvent;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.BeanProperty;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public abstract class AbstractLayoutCache implements RowMapper {
|
||||
/** Object responsible for getting the size of a node. */
|
||||
protected NodeDimensions nodeDimensions;
|
||||
|
||||
/** Model providing information. */
|
||||
protected TreeModel treeModel;
|
||||
|
||||
/** Selection model. */
|
||||
protected TreeSelectionModel treeSelectionModel;
|
||||
|
||||
/**
|
||||
* True if the root node is displayed, false if its children are
|
||||
* the highest visible nodes.
|
||||
*/
|
||||
protected boolean rootVisible;
|
||||
|
||||
/**
|
||||
* Height to use for each row. If this is <= 0 the renderer will be
|
||||
* used to determine the height for each row.
|
||||
*/
|
||||
protected int rowHeight;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the renderer that is responsible for drawing nodes in the tree
|
||||
* and which is therefore responsible for calculating the dimensions of
|
||||
* individual nodes.
|
||||
*
|
||||
* @param nd a <code>NodeDimensions</code> object
|
||||
*/
|
||||
public void setNodeDimensions(NodeDimensions nd) {
|
||||
this.nodeDimensions = nd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object that renders nodes in the tree, and which is
|
||||
* responsible for calculating the dimensions of individual nodes.
|
||||
*
|
||||
* @return the <code>NodeDimensions</code> object
|
||||
*/
|
||||
public NodeDimensions getNodeDimensions() {
|
||||
return nodeDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>TreeModel</code> that will provide the data.
|
||||
*
|
||||
* @param newModel the <code>TreeModel</code> that is to
|
||||
* provide the data
|
||||
*/
|
||||
public void setModel(TreeModel newModel) {
|
||||
treeModel = newModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>TreeModel</code> that is providing the data.
|
||||
*
|
||||
* @return the <code>TreeModel</code> that is providing the data
|
||||
*/
|
||||
public TreeModel getModel() {
|
||||
return treeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the root node from
|
||||
* the <code>TreeModel</code> is visible.
|
||||
*
|
||||
* @param rootVisible true if the root node of the tree is to be displayed
|
||||
* @see #rootVisible
|
||||
*/
|
||||
@BeanProperty(description
|
||||
= "Whether or not the root node from the TreeModel is visible.")
|
||||
public void setRootVisible(boolean rootVisible) {
|
||||
this.rootVisible = rootVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the root node of the tree is displayed.
|
||||
*
|
||||
* @return true if the root node of the tree is displayed
|
||||
* @see #rootVisible
|
||||
*/
|
||||
public boolean isRootVisible() {
|
||||
return rootVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height of each cell. If the specified value
|
||||
* is less than or equal to zero the current cell renderer is
|
||||
* queried for each row's height.
|
||||
*
|
||||
* @param rowHeight the height of each cell, in pixels
|
||||
*/
|
||||
@BeanProperty(description
|
||||
= "The height of each cell.")
|
||||
public void setRowHeight(int rowHeight) {
|
||||
this.rowHeight = rowHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of each row. If the returned value is less than
|
||||
* or equal to 0 the height for each row is determined by the
|
||||
* renderer.
|
||||
*
|
||||
* @return the height of each row
|
||||
*/
|
||||
public int getRowHeight() {
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>TreeSelectionModel</code> used to manage the
|
||||
* selection to new LSM.
|
||||
*
|
||||
* @param newLSM the new <code>TreeSelectionModel</code>
|
||||
*/
|
||||
public void setSelectionModel(TreeSelectionModel newLSM) {
|
||||
if(treeSelectionModel != null)
|
||||
treeSelectionModel.setRowMapper(null);
|
||||
treeSelectionModel = newLSM;
|
||||
if(treeSelectionModel != null)
|
||||
treeSelectionModel.setRowMapper(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model used to maintain the selection.
|
||||
*
|
||||
* @return the <code>treeSelectionModel</code>
|
||||
*/
|
||||
public TreeSelectionModel getSelectionModel() {
|
||||
return treeSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred height.
|
||||
*
|
||||
* @return the preferred height
|
||||
*/
|
||||
public int getPreferredHeight() {
|
||||
// Get the height
|
||||
int rowCount = getRowCount();
|
||||
|
||||
if(rowCount > 0) {
|
||||
Rectangle bounds = getBounds(getPathForRow(rowCount - 1),
|
||||
null);
|
||||
|
||||
if(bounds != null)
|
||||
return bounds.y + bounds.height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred width for the passed in region.
|
||||
* The region is defined by the path closest to
|
||||
* <code>(bounds.x, bounds.y)</code> and
|
||||
* ends at <code>bounds.height + bounds.y</code>.
|
||||
* If <code>bounds</code> is <code>null</code>,
|
||||
* the preferred width for all the nodes
|
||||
* will be returned (and this may be a VERY expensive
|
||||
* computation).
|
||||
*
|
||||
* @param bounds the region being queried
|
||||
* @return the preferred width for the passed in region
|
||||
*/
|
||||
public int getPreferredWidth(Rectangle bounds) {
|
||||
int rowCount = getRowCount();
|
||||
|
||||
if(rowCount > 0) {
|
||||
// Get the width
|
||||
TreePath firstPath;
|
||||
int endY;
|
||||
|
||||
if(bounds == null) {
|
||||
firstPath = getPathForRow(0);
|
||||
endY = Integer.MAX_VALUE;
|
||||
}
|
||||
else {
|
||||
firstPath = getPathClosestTo(bounds.x, bounds.y);
|
||||
endY = bounds.height + bounds.y;
|
||||
}
|
||||
|
||||
Enumeration<TreePath> paths = getVisiblePathsFrom(firstPath);
|
||||
|
||||
if(paths != null && paths.hasMoreElements()) {
|
||||
Rectangle pBounds = getBounds(paths.nextElement(),
|
||||
null);
|
||||
int width;
|
||||
|
||||
if(pBounds != null) {
|
||||
width = pBounds.x + pBounds.width;
|
||||
if (pBounds.y >= endY) {
|
||||
return width;
|
||||
}
|
||||
}
|
||||
else
|
||||
width = 0;
|
||||
while (pBounds != null && paths.hasMoreElements()) {
|
||||
pBounds = getBounds(paths.nextElement(),
|
||||
pBounds);
|
||||
if (pBounds != null && pBounds.y < endY) {
|
||||
width = Math.max(width, pBounds.x + pBounds.width);
|
||||
}
|
||||
else {
|
||||
pBounds = null;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Abstract methods that must be implemented to be concrete.
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns true if the value identified by row is currently expanded.
|
||||
*
|
||||
* @param path TreePath to check
|
||||
* @return whether TreePath is expanded
|
||||
*/
|
||||
public abstract boolean isExpanded(TreePath path);
|
||||
|
||||
/**
|
||||
* Returns a rectangle giving the bounds needed to draw path.
|
||||
*
|
||||
* @param path a <code>TreePath</code> specifying a node
|
||||
* @param placeIn a <code>Rectangle</code> object giving the
|
||||
* available space
|
||||
* @return a <code>Rectangle</code> object specifying the space to be used
|
||||
*/
|
||||
public abstract Rectangle getBounds(TreePath path, Rectangle placeIn);
|
||||
|
||||
/**
|
||||
* Returns the path for passed in row. If row is not visible
|
||||
* <code>null</code> is returned.
|
||||
*
|
||||
* @param row the row being queried
|
||||
* @return the <code>TreePath</code> for the given row
|
||||
*/
|
||||
public abstract TreePath getPathForRow(int row);
|
||||
|
||||
/**
|
||||
* Returns the row that the last item identified in path is visible
|
||||
* at. Will return -1 if any of the elements in path are not
|
||||
* currently visible.
|
||||
*
|
||||
* @param path the <code>TreePath</code> being queried
|
||||
* @return the row where the last item in path is visible or -1
|
||||
* if any elements in path aren't currently visible
|
||||
*/
|
||||
public abstract int getRowForPath(TreePath path);
|
||||
|
||||
/**
|
||||
* Returns the path to the node that is closest to x,y. If
|
||||
* there is nothing currently visible this will return <code>null</code>,
|
||||
* otherwise it'll always return a valid path.
|
||||
* If you need to test if the
|
||||
* returned object is exactly at x, y you should get the bounds for
|
||||
* the returned path and test x, y against that.
|
||||
*
|
||||
* @param x the horizontal component of the desired location
|
||||
* @param y the vertical component of the desired location
|
||||
* @return the <code>TreePath</code> closest to the specified point
|
||||
*/
|
||||
public abstract TreePath getPathClosestTo(int x, int y);
|
||||
|
||||
/**
|
||||
* Returns an <code>Enumerator</code> that increments over the visible
|
||||
* paths starting at the passed in location. The ordering of the
|
||||
* enumeration is based on how the paths are displayed.
|
||||
* The first element of the returned enumeration will be path,
|
||||
* unless it isn't visible,
|
||||
* in which case <code>null</code> will be returned.
|
||||
*
|
||||
* @param path the starting location for the enumeration
|
||||
* @return the <code>Enumerator</code> starting at the desired location
|
||||
*/
|
||||
public abstract Enumeration<TreePath> getVisiblePathsFrom(TreePath path);
|
||||
|
||||
/**
|
||||
* Returns the number of visible children for row.
|
||||
*
|
||||
* @param path the path being queried
|
||||
* @return the number of visible children for the specified path
|
||||
*/
|
||||
public abstract int getVisibleChildCount(TreePath path);
|
||||
|
||||
/**
|
||||
* Marks the path <code>path</code> expanded state to
|
||||
* <code>isExpanded</code>.
|
||||
*
|
||||
* @param path the path being expanded or collapsed
|
||||
* @param isExpanded true if the path should be expanded, false otherwise
|
||||
*/
|
||||
public abstract void setExpandedState(TreePath path, boolean isExpanded);
|
||||
|
||||
/**
|
||||
* Returns true if the path is expanded, and visible.
|
||||
*
|
||||
* @param path the path being queried
|
||||
* @return true if the path is expanded and visible, false otherwise
|
||||
*/
|
||||
public abstract boolean getExpandedState(TreePath path);
|
||||
|
||||
/**
|
||||
* Number of rows being displayed.
|
||||
*
|
||||
* @return the number of rows being displayed
|
||||
*/
|
||||
public abstract int getRowCount();
|
||||
|
||||
/**
|
||||
* Informs the <code>TreeState</code> that it needs to recalculate
|
||||
* all the sizes it is referencing.
|
||||
*/
|
||||
public abstract void invalidateSizes();
|
||||
|
||||
/**
|
||||
* Instructs the <code>LayoutCache</code> that the bounds for
|
||||
* <code>path</code> are invalid, and need to be updated.
|
||||
*
|
||||
* @param path the path being updated
|
||||
*/
|
||||
public abstract void invalidatePathBounds(TreePath path);
|
||||
|
||||
//
|
||||
// TreeModelListener methods
|
||||
// AbstractTreeState does not directly become a TreeModelListener on
|
||||
// the model, it is up to some other object to forward these methods.
|
||||
//
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Invoked after a node (or a set of siblings) has changed in some
|
||||
* way. The node(s) have not changed locations in the tree or
|
||||
* altered their children arrays, but other attributes have
|
||||
* changed and may affect presentation. Example: the name of a
|
||||
* file has changed, but it is in the same location in the file
|
||||
* system.</p>
|
||||
*
|
||||
* <p>e.path() returns the path the parent of the changed node(s).</p>
|
||||
*
|
||||
* <p>e.childIndices() returns the index(es) of the changed node(s).</p>
|
||||
*
|
||||
* @param e the <code>TreeModelEvent</code>
|
||||
*/
|
||||
public abstract void treeNodesChanged(TreeModelEvent e);
|
||||
|
||||
/**
|
||||
* <p>Invoked after nodes have been inserted into the tree.</p>
|
||||
*
|
||||
* <p>e.path() returns the parent of the new nodes</p>
|
||||
* <p>e.childIndices() returns the indices of the new nodes in
|
||||
* ascending order.</p>
|
||||
*
|
||||
* @param e the <code>TreeModelEvent</code>
|
||||
*/
|
||||
public abstract void treeNodesInserted(TreeModelEvent e);
|
||||
|
||||
/**
|
||||
* <p>Invoked after nodes have been removed from the tree. Note that
|
||||
* if a subtree is removed from the tree, this method may only be
|
||||
* invoked once for the root of the removed subtree, not once for
|
||||
* each individual set of siblings removed.</p>
|
||||
*
|
||||
* <p>e.path() returns the former parent of the deleted nodes.</p>
|
||||
*
|
||||
* <p>e.childIndices() returns the indices the nodes had before they were deleted in ascending order.</p>
|
||||
*
|
||||
* @param e the <code>TreeModelEvent</code>
|
||||
*/
|
||||
public abstract void treeNodesRemoved(TreeModelEvent e);
|
||||
|
||||
/**
|
||||
* <p>Invoked after the tree has drastically changed structure from a
|
||||
* given node down. If the path returned by <code>e.getPath()</code>
|
||||
* is of length one and the first element does not identify the
|
||||
* current root node the first element should become the new root
|
||||
* of the tree.</p>
|
||||
*
|
||||
* <p>e.path() holds the path to the node.</p>
|
||||
* <p>e.childIndices() returns null.</p>
|
||||
*
|
||||
* @param e the <code>TreeModelEvent</code>
|
||||
*/
|
||||
public abstract void treeStructureChanged(TreeModelEvent e);
|
||||
|
||||
//
|
||||
// RowMapper
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the rows that the <code>TreePath</code> instances in
|
||||
* <code>path</code> are being displayed at.
|
||||
* This method should return an array of the same length as that passed
|
||||
* in, and if one of the <code>TreePaths</code>
|
||||
* in <code>path</code> is not valid its entry in the array should
|
||||
* be set to -1.
|
||||
*
|
||||
* @param paths the array of <code>TreePath</code>s being queried
|
||||
* @return an array of the same length that is passed in containing
|
||||
* the rows that each corresponding where each
|
||||
* <code>TreePath</code> is displayed; if <code>paths</code>
|
||||
* is <code>null</code>, <code>null</code> is returned
|
||||
*/
|
||||
public int[] getRowsForPaths(TreePath[] paths) {
|
||||
if(paths == null)
|
||||
return null;
|
||||
|
||||
int numPaths = paths.length;
|
||||
int[] rows = new int[numPaths];
|
||||
|
||||
for(int counter = 0; counter < numPaths; counter++)
|
||||
rows[counter] = getRowForPath(paths[counter]);
|
||||
return rows;
|
||||
}
|
||||
|
||||
//
|
||||
// Local methods that subclassers may wish to use that are primarly
|
||||
// convenience methods.
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns, by reference in <code>placeIn</code>,
|
||||
* the size needed to represent <code>value</code>.
|
||||
* If <code>inPlace</code> is <code>null</code>, a newly created
|
||||
* <code>Rectangle</code> should be returned, otherwise the value
|
||||
* should be placed in <code>inPlace</code> and returned. This will
|
||||
* return <code>null</code> if there is no renderer.
|
||||
*
|
||||
* @param value the <code>value</code> to be represented
|
||||
* @param row row being queried
|
||||
* @param depth the depth of the row
|
||||
* @param expanded true if row is expanded, false otherwise
|
||||
* @param placeIn a <code>Rectangle</code> containing the size needed
|
||||
* to represent <code>value</code>
|
||||
* @return a <code>Rectangle</code> containing the node dimensions,
|
||||
* or <code>null</code> if node has no dimension
|
||||
*/
|
||||
protected Rectangle getNodeDimensions(Object value, int row, int depth,
|
||||
boolean expanded,
|
||||
Rectangle placeIn) {
|
||||
NodeDimensions nd = getNodeDimensions();
|
||||
|
||||
if(nd != null) {
|
||||
return nd.getNodeDimensions(value, row, depth, expanded, placeIn);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the height of each row is a fixed size.
|
||||
*
|
||||
* @return whether the height of each row is a fixed size
|
||||
*/
|
||||
protected boolean isFixedRowHeight() {
|
||||
return (rowHeight > 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by <code>AbstractLayoutCache</code> to determine the size
|
||||
* and x origin of a particular node.
|
||||
*/
|
||||
public abstract static class NodeDimensions {
|
||||
/**
|
||||
* Returns, by reference in bounds, the size and x origin to
|
||||
* place value at. The calling method is responsible for determining
|
||||
* the Y location. If bounds is <code>null</code>, a newly created
|
||||
* <code>Rectangle</code> should be returned,
|
||||
* otherwise the value should be placed in bounds and returned.
|
||||
*
|
||||
* @param value the <code>value</code> to be represented
|
||||
* @param row row being queried
|
||||
* @param depth the depth of the row
|
||||
* @param expanded true if row is expanded, false otherwise
|
||||
* @param bounds a <code>Rectangle</code> containing the size needed
|
||||
* to represent <code>value</code>
|
||||
* @return a <code>Rectangle</code> containing the node dimensions,
|
||||
* or <code>null</code> if node has no dimension
|
||||
*/
|
||||
public abstract Rectangle getNodeDimensions(Object value, int row,
|
||||
int depth,
|
||||
boolean expanded,
|
||||
Rectangle bounds);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,766 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.BeanProperty;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* A <code>TreeCellEditor</code>. You need to supply an
|
||||
* instance of <code>DefaultTreeCellRenderer</code>
|
||||
* so that the icons can be obtained. You can optionally supply
|
||||
* a <code>TreeCellEditor</code> that will be layed out according
|
||||
* to the icon in the <code>DefaultTreeCellRenderer</code>.
|
||||
* If you do not supply a <code>TreeCellEditor</code>,
|
||||
* a <code>TextField</code> will be used. Editing is started
|
||||
* on a triple mouse click, or after a click, pause, click and
|
||||
* a delay of 1200 milliseconds.
|
||||
*<p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @see javax.swing.JTree
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public class DefaultTreeCellEditor implements ActionListener, TreeCellEditor,
|
||||
TreeSelectionListener {
|
||||
/** Editor handling the editing. */
|
||||
protected TreeCellEditor realEditor;
|
||||
|
||||
/** Renderer, used to get border and offsets from. */
|
||||
protected DefaultTreeCellRenderer renderer;
|
||||
|
||||
/** Editing container, will contain the <code>editorComponent</code>. */
|
||||
protected Container editingContainer;
|
||||
|
||||
/**
|
||||
* Component used in editing, obtained from the
|
||||
* <code>editingContainer</code>.
|
||||
*/
|
||||
protected transient Component editingComponent;
|
||||
|
||||
/**
|
||||
* As of Java 2 platform v1.4 this field should no longer be used. If
|
||||
* you wish to provide similar behavior you should directly override
|
||||
* <code>isCellEditable</code>.
|
||||
*/
|
||||
protected boolean canEdit;
|
||||
|
||||
/**
|
||||
* Used in editing. Indicates x position to place
|
||||
* <code>editingComponent</code>.
|
||||
*/
|
||||
protected transient int offset;
|
||||
|
||||
/** <code>JTree</code> instance listening too. */
|
||||
protected transient JTree tree;
|
||||
|
||||
/** Last path that was selected. */
|
||||
protected transient TreePath lastPath;
|
||||
|
||||
/** Used before starting the editing session. */
|
||||
protected transient Timer timer;
|
||||
|
||||
/**
|
||||
* Row that was last passed into
|
||||
* <code>getTreeCellEditorComponent</code>.
|
||||
*/
|
||||
protected transient int lastRow;
|
||||
|
||||
/** True if the border selection color should be drawn. */
|
||||
protected Color borderSelectionColor;
|
||||
|
||||
/** Icon to use when editing. */
|
||||
protected transient Icon editingIcon;
|
||||
|
||||
/**
|
||||
* Font to paint with, <code>null</code> indicates
|
||||
* font of renderer is to be used.
|
||||
*/
|
||||
protected Font font;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a <code>DefaultTreeCellEditor</code>
|
||||
* object for a JTree using the specified renderer and
|
||||
* a default editor. (Use this constructor for normal editing.)
|
||||
*
|
||||
* @param tree a <code>JTree</code> object
|
||||
* @param renderer a <code>DefaultTreeCellRenderer</code> object
|
||||
*/
|
||||
public DefaultTreeCellEditor(JTree tree,
|
||||
DefaultTreeCellRenderer renderer) {
|
||||
this(tree, renderer, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>DefaultTreeCellEditor</code>
|
||||
* object for a <code>JTree</code> using the
|
||||
* specified renderer and the specified editor. (Use this constructor
|
||||
* for specialized editing.)
|
||||
*
|
||||
* @param tree a <code>JTree</code> object
|
||||
* @param renderer a <code>DefaultTreeCellRenderer</code> object
|
||||
* @param editor a <code>TreeCellEditor</code> object
|
||||
*/
|
||||
public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
|
||||
TreeCellEditor editor) {
|
||||
this.renderer = renderer;
|
||||
realEditor = editor;
|
||||
if(realEditor == null)
|
||||
realEditor = createTreeCellEditor();
|
||||
editingContainer = createContainer();
|
||||
setTree(tree);
|
||||
setBorderSelectionColor(UIManager.getColor
|
||||
("Tree.editorBorderSelectionColor"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color to use for the border.
|
||||
* @param newColor the new border color
|
||||
*/
|
||||
public void setBorderSelectionColor(Color newColor) {
|
||||
borderSelectionColor = newColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color the border is drawn.
|
||||
* @return the border selection color
|
||||
*/
|
||||
public Color getBorderSelectionColor() {
|
||||
return borderSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font to edit with. <code>null</code> indicates
|
||||
* the renderers font should be used. This will NOT
|
||||
* override any font you have set in the editor
|
||||
* the receiver was instantiated with. If <code>null</code>
|
||||
* for an editor was passed in a default editor will be
|
||||
* created that will pick up this font.
|
||||
*
|
||||
* @param font the editing <code>Font</code>
|
||||
* @see #getFont
|
||||
*/
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font used for editing.
|
||||
*
|
||||
* @return the editing <code>Font</code>
|
||||
* @see #setFont
|
||||
*/
|
||||
public Font getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
//
|
||||
// TreeCellEditor
|
||||
//
|
||||
|
||||
/**
|
||||
* Configures the editor. Passed onto the <code>realEditor</code>.
|
||||
*/
|
||||
public Component getTreeCellEditorComponent(JTree tree, Object value,
|
||||
boolean isSelected,
|
||||
boolean expanded,
|
||||
boolean leaf, int row) {
|
||||
setTree(tree);
|
||||
lastRow = row;
|
||||
determineOffset(tree, value, isSelected, expanded, leaf, row);
|
||||
|
||||
if (editingComponent != null) {
|
||||
editingContainer.remove(editingComponent);
|
||||
}
|
||||
editingComponent = realEditor.getTreeCellEditorComponent(tree, value,
|
||||
isSelected, expanded,leaf, row);
|
||||
|
||||
|
||||
// this is kept for backwards compatibility but isn't really needed
|
||||
// with the current BasicTreeUI implementation.
|
||||
TreePath newPath = tree.getPathForRow(row);
|
||||
|
||||
canEdit = (lastPath != null && newPath != null &&
|
||||
lastPath.equals(newPath));
|
||||
|
||||
Font font = getFont();
|
||||
|
||||
if(font == null) {
|
||||
if(renderer != null)
|
||||
font = renderer.getFont();
|
||||
if(font == null)
|
||||
font = tree.getFont();
|
||||
}
|
||||
editingContainer.setFont(font);
|
||||
prepareForEditing();
|
||||
return editingContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value currently being edited.
|
||||
* @return the value currently being edited
|
||||
*/
|
||||
public Object getCellEditorValue() {
|
||||
return realEditor.getCellEditorValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the <code>realEditor</code> returns true to this
|
||||
* message, <code>prepareForEditing</code>
|
||||
* is messaged and true is returned.
|
||||
*/
|
||||
public boolean isCellEditable(EventObject event) {
|
||||
boolean retValue = false;
|
||||
boolean editable = false;
|
||||
|
||||
if (event != null) {
|
||||
if (event.getSource() instanceof JTree) {
|
||||
setTree((JTree)event.getSource());
|
||||
if (event instanceof MouseEvent) {
|
||||
TreePath path = tree.getPathForLocation(
|
||||
((MouseEvent)event).getX(),
|
||||
((MouseEvent)event).getY());
|
||||
editable = (lastPath != null && path != null &&
|
||||
lastPath.equals(path));
|
||||
if (path!=null) {
|
||||
lastRow = tree.getRowForPath(path);
|
||||
Object value = path.getLastPathComponent();
|
||||
boolean isSelected = tree.isRowSelected(lastRow);
|
||||
boolean expanded = tree.isExpanded(path);
|
||||
TreeModel treeModel = tree.getModel();
|
||||
boolean leaf = treeModel.isLeaf(value);
|
||||
determineOffset(tree, value, isSelected,
|
||||
expanded, leaf, lastRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!realEditor.isCellEditable(event))
|
||||
return false;
|
||||
if(canEditImmediately(event))
|
||||
retValue = true;
|
||||
else if(editable && shouldStartEditingTimer(event)) {
|
||||
startEditingTimer();
|
||||
}
|
||||
else if(timer != null && timer.isRunning())
|
||||
timer.stop();
|
||||
if(retValue)
|
||||
prepareForEditing();
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages the <code>realEditor</code> for the return value.
|
||||
*/
|
||||
public boolean shouldSelectCell(EventObject event) {
|
||||
return realEditor.shouldSelectCell(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the <code>realEditor</code> will allow editing to stop,
|
||||
* the <code>realEditor</code> is removed and true is returned,
|
||||
* otherwise false is returned.
|
||||
*/
|
||||
public boolean stopCellEditing() {
|
||||
if(realEditor.stopCellEditing()) {
|
||||
cleanupAfterEditing();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages <code>cancelCellEditing</code> to the
|
||||
* <code>realEditor</code> and removes it from this instance.
|
||||
*/
|
||||
public void cancelCellEditing() {
|
||||
realEditor.cancelCellEditing();
|
||||
cleanupAfterEditing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the <code>CellEditorListener</code>.
|
||||
* @param l the listener to be added
|
||||
*/
|
||||
public void addCellEditorListener(CellEditorListener l) {
|
||||
realEditor.addCellEditorListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the previously added <code>CellEditorListener</code>.
|
||||
* @param l the listener to be removed
|
||||
*/
|
||||
public void removeCellEditorListener(CellEditorListener l) {
|
||||
realEditor.removeCellEditorListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the <code>CellEditorListener</code>s added
|
||||
* to this DefaultTreeCellEditor with addCellEditorListener().
|
||||
*
|
||||
* @return all of the <code>CellEditorListener</code>s added or an empty
|
||||
* array if no listeners have been added
|
||||
* @since 1.4
|
||||
*/
|
||||
public CellEditorListener[] getCellEditorListeners() {
|
||||
return ((DefaultCellEditor)realEditor).getCellEditorListeners();
|
||||
}
|
||||
|
||||
//
|
||||
// TreeSelectionListener
|
||||
//
|
||||
|
||||
/**
|
||||
* Resets <code>lastPath</code>.
|
||||
*/
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
if(tree != null) {
|
||||
if(tree.getSelectionCount() == 1)
|
||||
lastPath = tree.getSelectionPath();
|
||||
else
|
||||
lastPath = null;
|
||||
}
|
||||
if(timer != null) {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ActionListener (for Timer).
|
||||
//
|
||||
|
||||
/**
|
||||
* Messaged when the timer fires, this will start the editing
|
||||
* session.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if(tree != null && lastPath != null) {
|
||||
tree.startEditingAtPath(lastPath);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Local methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Sets the tree currently editing for. This is needed to add
|
||||
* a selection listener.
|
||||
* @param newTree the new tree to be edited
|
||||
*/
|
||||
protected void setTree(JTree newTree) {
|
||||
if(tree != newTree) {
|
||||
if(tree != null)
|
||||
tree.removeTreeSelectionListener(this);
|
||||
tree = newTree;
|
||||
if(tree != null)
|
||||
tree.addTreeSelectionListener(this);
|
||||
if(timer != null) {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if <code>event</code> is a <code>MouseEvent</code>
|
||||
* and the click count is 1.
|
||||
*
|
||||
* @param event the event being studied
|
||||
* @return whether {@code event} should starts the editing timer
|
||||
*/
|
||||
protected boolean shouldStartEditingTimer(EventObject event) {
|
||||
if((event instanceof MouseEvent) &&
|
||||
SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
|
||||
MouseEvent me = (MouseEvent)event;
|
||||
|
||||
return (me.getClickCount() == 1 &&
|
||||
inHitRegion(me.getX(), me.getY()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the editing timer.
|
||||
*/
|
||||
protected void startEditingTimer() {
|
||||
if(timer == null) {
|
||||
timer = new Timer(1200, this);
|
||||
timer.setRepeats(false);
|
||||
}
|
||||
timer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if <code>event</code> is <code>null</code>,
|
||||
* or it is a <code>MouseEvent</code> with a click count > 2
|
||||
* and <code>inHitRegion</code> returns true.
|
||||
*
|
||||
* @param event the event being studied
|
||||
* @return whether editing can be started for the given {@code event}
|
||||
*/
|
||||
protected boolean canEditImmediately(EventObject event) {
|
||||
if((event instanceof MouseEvent) &&
|
||||
SwingUtilities.isLeftMouseButton((MouseEvent)event)) {
|
||||
MouseEvent me = (MouseEvent)event;
|
||||
|
||||
return ((me.getClickCount() > 2) &&
|
||||
inHitRegion(me.getX(), me.getY()));
|
||||
}
|
||||
return (event == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed in location is a valid mouse location
|
||||
* to start editing from. This is implemented to return false if
|
||||
* <code>x</code> is <= the width of the icon and icon gap displayed
|
||||
* by the renderer. In other words this returns true if the user
|
||||
* clicks over the text part displayed by the renderer, and false
|
||||
* otherwise.
|
||||
* @param x the x-coordinate of the point
|
||||
* @param y the y-coordinate of the point
|
||||
* @return true if the passed in location is a valid mouse location
|
||||
*/
|
||||
protected boolean inHitRegion(int x, int y) {
|
||||
if(lastRow != -1 && tree != null) {
|
||||
Rectangle bounds = tree.getRowBounds(lastRow);
|
||||
ComponentOrientation treeOrientation = tree.getComponentOrientation();
|
||||
|
||||
if ( treeOrientation.isLeftToRight() ) {
|
||||
if (bounds != null && x <= (bounds.x + offset) &&
|
||||
offset < (bounds.width - 5)) {
|
||||
return false;
|
||||
}
|
||||
} else if ( bounds != null &&
|
||||
( x >= (bounds.x+bounds.width-offset+5) ||
|
||||
x <= (bounds.x + 5) ) &&
|
||||
offset < (bounds.width - 5) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the offset.
|
||||
* @param tree a <code>JTree</code> object
|
||||
* @param value a value
|
||||
* @param isSelected selection status
|
||||
* @param expanded expansion status
|
||||
* @param leaf leaf status
|
||||
* @param row current row
|
||||
*/
|
||||
protected void determineOffset(JTree tree, Object value,
|
||||
boolean isSelected, boolean expanded,
|
||||
boolean leaf, int row) {
|
||||
if(renderer != null) {
|
||||
if(leaf)
|
||||
editingIcon = renderer.getLeafIcon();
|
||||
else if(expanded)
|
||||
editingIcon = renderer.getOpenIcon();
|
||||
else
|
||||
editingIcon = renderer.getClosedIcon();
|
||||
if(editingIcon != null)
|
||||
offset = renderer.getIconTextGap() +
|
||||
editingIcon.getIconWidth();
|
||||
else
|
||||
offset = renderer.getIconTextGap();
|
||||
}
|
||||
else {
|
||||
editingIcon = null;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked just before editing is to start. Will add the
|
||||
* <code>editingComponent</code> to the
|
||||
* <code>editingContainer</code>.
|
||||
*/
|
||||
protected void prepareForEditing() {
|
||||
if (editingComponent != null) {
|
||||
editingContainer.add(editingComponent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the container to manage placement of
|
||||
* <code>editingComponent</code>.
|
||||
*
|
||||
* @return new Container object
|
||||
*/
|
||||
protected Container createContainer() {
|
||||
return new EditorContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is invoked if a <code>TreeCellEditor</code>
|
||||
* is not supplied in the constructor.
|
||||
* It returns a <code>TextField</code> editor.
|
||||
* @return a new <code>TextField</code> editor
|
||||
*/
|
||||
protected TreeCellEditor createTreeCellEditor() {
|
||||
Border aBorder = UIManager.getBorder("Tree.editorBorder");
|
||||
@SuppressWarnings("serial") // Safe: outer class is non-serializable
|
||||
DefaultCellEditor editor = new DefaultCellEditor
|
||||
(new DefaultTextField(aBorder)) {
|
||||
public boolean shouldSelectCell(EventObject event) {
|
||||
boolean retValue = super.shouldSelectCell(event);
|
||||
return retValue;
|
||||
}
|
||||
};
|
||||
|
||||
// One click to edit.
|
||||
editor.setClickCountToStart(1);
|
||||
return editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up any state after editing has completed. Removes the
|
||||
* <code>editingComponent</code> the <code>editingContainer</code>.
|
||||
*/
|
||||
private void cleanupAfterEditing() {
|
||||
if (editingComponent != null) {
|
||||
editingContainer.remove(editingComponent);
|
||||
}
|
||||
editingComponent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>TextField</code> used when no editor is supplied.
|
||||
* This textfield locks into the border it is constructed with.
|
||||
* It also prefers its parents font over its font. And if the
|
||||
* renderer is not <code>null</code> and no font
|
||||
* has been specified the preferred height is that of the renderer.
|
||||
*/
|
||||
@SuppressWarnings("serial") // Safe: outer class is non-serializable
|
||||
public class DefaultTextField extends JTextField {
|
||||
/** Border to use. */
|
||||
protected Border border;
|
||||
|
||||
/**
|
||||
* Constructs a
|
||||
* <code>DefaultTreeCellEditor.DefaultTextField</code> object.
|
||||
*
|
||||
* @param border a <code>Border</code> object
|
||||
* @since 1.4
|
||||
*/
|
||||
public DefaultTextField(Border border) {
|
||||
setBorder(border);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the border of this component.<p>
|
||||
* This is a bound property.
|
||||
*
|
||||
* @param border the border to be rendered for this component
|
||||
* @see Border
|
||||
* @see CompoundBorder
|
||||
*/
|
||||
@BeanProperty(preferred = true, visualUpdate = true, description
|
||||
= "The component's border.")
|
||||
public void setBorder(Border border) {
|
||||
super.setBorder(border);
|
||||
this.border = border;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides <code>JComponent.getBorder</code> to
|
||||
* returns the current border.
|
||||
*/
|
||||
public Border getBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
// implements java.awt.MenuContainer
|
||||
public Font getFont() {
|
||||
Font font = super.getFont();
|
||||
|
||||
// Prefer the parent containers font if our font is a
|
||||
// FontUIResource
|
||||
if(font instanceof FontUIResource) {
|
||||
Container parent = getParent();
|
||||
|
||||
if(parent != null && parent.getFont() != null)
|
||||
font = parent.getFont();
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides <code>JTextField.getPreferredSize</code> to
|
||||
* return the preferred size based on current font, if set,
|
||||
* or else use renderer's font.
|
||||
* @return a <code>Dimension</code> object containing
|
||||
* the preferred size
|
||||
*/
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
|
||||
// If not font has been set, prefer the renderers height.
|
||||
if(renderer != null &&
|
||||
DefaultTreeCellEditor.this.getFont() == null) {
|
||||
Dimension rSize = renderer.getPreferredSize();
|
||||
|
||||
size.height = rSize.height;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Container responsible for placing the <code>editingComponent</code>.
|
||||
*/
|
||||
@SuppressWarnings("serial") // Safe: outer class is non-serializable
|
||||
public class EditorContainer extends Container {
|
||||
/**
|
||||
* Constructs an <code>EditorContainer</code> object.
|
||||
*/
|
||||
public EditorContainer() {
|
||||
setLayout(null);
|
||||
}
|
||||
|
||||
// This should not be used. It will be removed when new API is
|
||||
// allowed.
|
||||
/**
|
||||
* Do not use.
|
||||
*/
|
||||
public void EditorContainer() {
|
||||
setLayout(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides <code>Container.paint</code> to paint the node's
|
||||
* icon and use the selection color for the background.
|
||||
*/
|
||||
public void paint(Graphics g) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
// Then the icon.
|
||||
if(editingIcon != null) {
|
||||
int yLoc = calculateIconY(editingIcon);
|
||||
|
||||
if (getComponentOrientation().isLeftToRight()) {
|
||||
editingIcon.paintIcon(this, g, 0, yLoc);
|
||||
} else {
|
||||
editingIcon.paintIcon(
|
||||
this, g, width - editingIcon.getIconWidth(),
|
||||
yLoc);
|
||||
}
|
||||
}
|
||||
|
||||
// Border selection color
|
||||
Color background = getBorderSelectionColor();
|
||||
if(background != null) {
|
||||
g.setColor(background);
|
||||
g.drawRect(0, 0, width - 1, height - 1);
|
||||
}
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lays out this <code>Container</code>. If editing,
|
||||
* the editor will be placed at
|
||||
* <code>offset</code> in the x direction and 0 for y.
|
||||
*/
|
||||
public void doLayout() {
|
||||
if(editingComponent != null) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
if (getComponentOrientation().isLeftToRight()) {
|
||||
editingComponent.setBounds(
|
||||
offset, 0, width - offset, height);
|
||||
} else {
|
||||
editingComponent.setBounds(
|
||||
0, 0, width - offset, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the y location for the icon.
|
||||
*/
|
||||
private int calculateIconY(Icon icon) {
|
||||
// To make sure the icon position matches that of the
|
||||
// renderer, use the same algorithm as JLabel
|
||||
// (SwingUtilities.layoutCompoundLabel).
|
||||
int iconHeight = icon.getIconHeight();
|
||||
int textHeight = editingComponent.getFontMetrics(
|
||||
editingComponent.getFont()).getHeight();
|
||||
int textY = iconHeight / 2 - textHeight / 2;
|
||||
int totalY = Math.min(0, textY);
|
||||
int totalHeight = Math.max(iconHeight, textY + textHeight) -
|
||||
totalY;
|
||||
return getHeight() / 2 - (totalY + (totalHeight / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred size for the <code>Container</code>.
|
||||
* This will be at least preferred size of the editor plus
|
||||
* <code>offset</code>.
|
||||
* @return a <code>Dimension</code> containing the preferred
|
||||
* size for the <code>Container</code>; if
|
||||
* <code>editingComponent</code> is <code>null</code> the
|
||||
* <code>Dimension</code> returned is 0, 0
|
||||
*/
|
||||
public Dimension getPreferredSize() {
|
||||
if(editingComponent != null) {
|
||||
Dimension pSize = editingComponent.getPreferredSize();
|
||||
|
||||
pSize.width += offset + 5;
|
||||
|
||||
Dimension rSize = (renderer != null) ?
|
||||
renderer.getPreferredSize() : null;
|
||||
|
||||
if(rSize != null)
|
||||
pSize.height = Math.max(pSize.height, rSize.height);
|
||||
if(editingIcon != null)
|
||||
pSize.height = Math.max(pSize.height,
|
||||
editingIcon.getIconHeight());
|
||||
|
||||
// Make sure width is at least 100.
|
||||
pSize.width = Math.max(pSize.width, 100);
|
||||
return pSize;
|
||||
}
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,741 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.plaf.ColorUIResource;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicGraphicsUtils;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import sun.swing.DefaultLookup;
|
||||
|
||||
/**
|
||||
* Displays an entry in a tree.
|
||||
* <code>DefaultTreeCellRenderer</code> is not opaque and
|
||||
* unless you subclass paint you should not change this.
|
||||
* See <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial</em>
|
||||
* for examples of customizing node display using this class.
|
||||
* <p>
|
||||
* The set of icons and colors used by {@code DefaultTreeCellRenderer}
|
||||
* can be configured using the various setter methods. The value for
|
||||
* each property is initialized from the defaults table. When the
|
||||
* look and feel changes ({@code updateUI} is invoked), any properties
|
||||
* that have a value of type {@code UIResource} are refreshed from the
|
||||
* defaults table. The following table lists the mapping between
|
||||
* {@code DefaultTreeCellRenderer} property and defaults table key:
|
||||
*
|
||||
* <table class="striped">
|
||||
* <caption>Properties</caption>
|
||||
* <thead>
|
||||
* <tr>
|
||||
* <th>Property:
|
||||
* <th>Key:
|
||||
* </tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td>"leafIcon"<td>"Tree.leafIcon"
|
||||
* <tr><td>"closedIcon"<td>"Tree.closedIcon"
|
||||
* <tr><td>"openIcon"<td>"Tree.openIcon"
|
||||
* <tr><td>"textSelectionColor"<td>"Tree.selectionForeground"
|
||||
* <tr><td>"textNonSelectionColor"<td>"Tree.textForeground"
|
||||
* <tr><td>"backgroundSelectionColor"<td>"Tree.selectionBackground"
|
||||
* <tr><td>"backgroundNonSelectionColor"<td>"Tree.textBackground"
|
||||
* <tr><td>"borderSelectionColor"<td>"Tree.selectionBorderColor"
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* <strong><a id="override">Implementation Note:</a></strong>
|
||||
* This class overrides
|
||||
* <code>invalidate</code>,
|
||||
* <code>validate</code>,
|
||||
* <code>revalidate</code>,
|
||||
* <code>repaint</code>,
|
||||
* and
|
||||
* <code>firePropertyChange</code>
|
||||
* solely to improve performance.
|
||||
* If not overridden, these frequently called methods would execute code paths
|
||||
* that are unnecessary for the default tree cell renderer.
|
||||
* If you write your own renderer,
|
||||
* take care to weigh the benefits and
|
||||
* drawbacks of overriding these methods.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Ray Ryan
|
||||
* @author Scott Violet
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public class DefaultTreeCellRenderer extends JLabel implements TreeCellRenderer
|
||||
{
|
||||
/** Last tree the renderer was painted in. */
|
||||
private JTree tree;
|
||||
|
||||
/** Is the value currently selected. */
|
||||
protected boolean selected;
|
||||
/** True if has focus. */
|
||||
protected boolean hasFocus;
|
||||
/** True if draws focus border around icon as well. */
|
||||
private boolean drawsFocusBorderAroundIcon;
|
||||
/** If true, a dashed line is drawn as the focus indicator. */
|
||||
private boolean drawDashedFocusIndicator;
|
||||
|
||||
// If drawDashedFocusIndicator is true, the following are used.
|
||||
/**
|
||||
* Background color of the tree.
|
||||
*/
|
||||
private Color treeBGColor;
|
||||
/**
|
||||
* Color to draw the focus indicator in, determined from the background.
|
||||
* color.
|
||||
*/
|
||||
private Color focusBGColor;
|
||||
|
||||
// Icons
|
||||
/** Icon used to show non-leaf nodes that aren't expanded. */
|
||||
protected transient Icon closedIcon;
|
||||
|
||||
/** Icon used to show leaf nodes. */
|
||||
protected transient Icon leafIcon;
|
||||
|
||||
/** Icon used to show non-leaf nodes that are expanded. */
|
||||
protected transient Icon openIcon;
|
||||
|
||||
// Colors
|
||||
/** Color to use for the foreground for selected nodes. */
|
||||
protected Color textSelectionColor;
|
||||
|
||||
/** Color to use for the foreground for non-selected nodes. */
|
||||
protected Color textNonSelectionColor;
|
||||
|
||||
/** Color to use for the background when a node is selected. */
|
||||
protected Color backgroundSelectionColor;
|
||||
|
||||
/** Color to use for the background when the node isn't selected. */
|
||||
protected Color backgroundNonSelectionColor;
|
||||
|
||||
/** Color to use for the focus indicator when the node has focus. */
|
||||
protected Color borderSelectionColor;
|
||||
|
||||
private boolean isDropCell;
|
||||
private boolean fillBackground;
|
||||
|
||||
/**
|
||||
* Set to true after the constructor has run.
|
||||
*/
|
||||
private boolean inited;
|
||||
|
||||
/**
|
||||
* Creates a {@code DefaultTreeCellRenderer}. Icons and text color are
|
||||
* determined from the {@code UIManager}.
|
||||
*/
|
||||
public DefaultTreeCellRenderer() {
|
||||
inited = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
// To avoid invoking new methods from the constructor, the
|
||||
// inited field is first checked. If inited is false, the constructor
|
||||
// has not run and there is no point in checking the value. As
|
||||
// all look and feels have a non-null value for these properties,
|
||||
// a null value means the developer has specifically set it to
|
||||
// null. As such, if the value is null, this does not reset the
|
||||
// value.
|
||||
if (!inited || (getLeafIcon() instanceof UIResource)) {
|
||||
setLeafIcon(DefaultLookup.getIcon(this, ui, "Tree.leafIcon"));
|
||||
}
|
||||
if (!inited || (getClosedIcon() instanceof UIResource)) {
|
||||
setClosedIcon(DefaultLookup.getIcon(this, ui, "Tree.closedIcon"));
|
||||
}
|
||||
if (!inited || (getOpenIcon() instanceof UIResource)) {
|
||||
setOpenIcon(DefaultLookup.getIcon(this, ui, "Tree.openIcon"));
|
||||
}
|
||||
if (!inited || (getTextSelectionColor() instanceof UIResource)) {
|
||||
setTextSelectionColor(
|
||||
DefaultLookup.getColor(this, ui, "Tree.selectionForeground"));
|
||||
}
|
||||
if (!inited || (getTextNonSelectionColor() instanceof UIResource)) {
|
||||
setTextNonSelectionColor(
|
||||
DefaultLookup.getColor(this, ui, "Tree.textForeground"));
|
||||
}
|
||||
if (!inited || (getBackgroundSelectionColor() instanceof UIResource)) {
|
||||
setBackgroundSelectionColor(
|
||||
DefaultLookup.getColor(this, ui, "Tree.selectionBackground"));
|
||||
}
|
||||
if (!inited ||
|
||||
(getBackgroundNonSelectionColor() instanceof UIResource)) {
|
||||
setBackgroundNonSelectionColor(
|
||||
DefaultLookup.getColor(this, ui, "Tree.textBackground"));
|
||||
}
|
||||
if (!inited || (getBorderSelectionColor() instanceof UIResource)) {
|
||||
setBorderSelectionColor(
|
||||
DefaultLookup.getColor(this, ui, "Tree.selectionBorderColor"));
|
||||
}
|
||||
drawsFocusBorderAroundIcon = DefaultLookup.getBoolean(
|
||||
this, ui, "Tree.drawsFocusBorderAroundIcon", false);
|
||||
drawDashedFocusIndicator = DefaultLookup.getBoolean(
|
||||
this, ui, "Tree.drawDashedFocusIndicator", false);
|
||||
|
||||
fillBackground = DefaultLookup.getBoolean(this, ui, "Tree.rendererFillBackground", true);
|
||||
Insets margins = DefaultLookup.getInsets(this, ui, "Tree.rendererMargins");
|
||||
if (margins != null) {
|
||||
setBorder(new EmptyBorder(margins.top, margins.left,
|
||||
margins.bottom, margins.right));
|
||||
}
|
||||
|
||||
setName("Tree.cellRenderer");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default icon, for the current laf, that is used to
|
||||
* represent non-leaf nodes that are expanded.
|
||||
*
|
||||
* @return the default icon, for the current laf, that is used to
|
||||
* represent non-leaf nodes that are expanded.
|
||||
*/
|
||||
public Icon getDefaultOpenIcon() {
|
||||
return DefaultLookup.getIcon(this, ui, "Tree.openIcon");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default icon, for the current laf, that is used to
|
||||
* represent non-leaf nodes that are not expanded.
|
||||
*
|
||||
* @return the default icon, for the current laf, that is used to
|
||||
* represent non-leaf nodes that are not expanded.
|
||||
*/
|
||||
public Icon getDefaultClosedIcon() {
|
||||
return DefaultLookup.getIcon(this, ui, "Tree.closedIcon");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default icon, for the current laf, that is used to
|
||||
* represent leaf nodes.
|
||||
*
|
||||
* @return the default icon, for the current laf, that is used to
|
||||
* represent leaf nodes.
|
||||
*/
|
||||
public Icon getDefaultLeafIcon() {
|
||||
return DefaultLookup.getIcon(this, ui, "Tree.leafIcon");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon used to represent non-leaf nodes that are expanded.
|
||||
*
|
||||
* @param newIcon the icon to be used for expanded non-leaf nodes
|
||||
*/
|
||||
public void setOpenIcon(Icon newIcon) {
|
||||
openIcon = newIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon used to represent non-leaf nodes that are expanded.
|
||||
*
|
||||
* @return the icon used to represent non-leaf nodes that are expanded
|
||||
*/
|
||||
public Icon getOpenIcon() {
|
||||
return openIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon used to represent non-leaf nodes that are not expanded.
|
||||
*
|
||||
* @param newIcon the icon to be used for not expanded non-leaf nodes
|
||||
*/
|
||||
public void setClosedIcon(Icon newIcon) {
|
||||
closedIcon = newIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon used to represent non-leaf nodes that are not
|
||||
* expanded.
|
||||
*
|
||||
* @return the icon used to represent non-leaf nodes that are not
|
||||
* expanded
|
||||
*/
|
||||
public Icon getClosedIcon() {
|
||||
return closedIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon used to represent leaf nodes.
|
||||
*
|
||||
* @param newIcon icon to be used for leaf nodes
|
||||
*/
|
||||
public void setLeafIcon(Icon newIcon) {
|
||||
leafIcon = newIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon used to represent leaf nodes.
|
||||
*
|
||||
* @return the icon used to represent leaf nodes
|
||||
*/
|
||||
public Icon getLeafIcon() {
|
||||
return leafIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color the text is drawn with when the node is selected.
|
||||
*
|
||||
* @param newColor color to be used for text when the node is selected
|
||||
*/
|
||||
public void setTextSelectionColor(Color newColor) {
|
||||
textSelectionColor = newColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color the text is drawn with when the node is selected.
|
||||
*
|
||||
* @return the color the text is drawn with when the node is selected
|
||||
*/
|
||||
public Color getTextSelectionColor() {
|
||||
return textSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color the text is drawn with when the node isn't selected.
|
||||
*
|
||||
* @param newColor color to be used for text when the node isn't selected
|
||||
*/
|
||||
public void setTextNonSelectionColor(Color newColor) {
|
||||
textNonSelectionColor = newColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color the text is drawn with when the node isn't selected.
|
||||
*
|
||||
* @return the color the text is drawn with when the node isn't selected.
|
||||
*/
|
||||
public Color getTextNonSelectionColor() {
|
||||
return textNonSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color to use for the background if node is selected.
|
||||
*
|
||||
* @param newColor to be used for the background if the node is selected
|
||||
*/
|
||||
public void setBackgroundSelectionColor(Color newColor) {
|
||||
backgroundSelectionColor = newColor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the color to use for the background if node is selected.
|
||||
*
|
||||
* @return the color to use for the background if node is selected
|
||||
*/
|
||||
public Color getBackgroundSelectionColor() {
|
||||
return backgroundSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background color to be used for non selected nodes.
|
||||
*
|
||||
* @param newColor color to be used for the background for non selected nodes
|
||||
*/
|
||||
public void setBackgroundNonSelectionColor(Color newColor) {
|
||||
backgroundNonSelectionColor = newColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the background color to be used for non selected nodes.
|
||||
*
|
||||
* @return the background color to be used for non selected nodes.
|
||||
*/
|
||||
public Color getBackgroundNonSelectionColor() {
|
||||
return backgroundNonSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color to use for the border.
|
||||
*
|
||||
* @param newColor color to be used for the border
|
||||
*/
|
||||
public void setBorderSelectionColor(Color newColor) {
|
||||
borderSelectionColor = newColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color the border is drawn.
|
||||
*
|
||||
* @return the color the border is drawn
|
||||
*/
|
||||
public Color getBorderSelectionColor() {
|
||||
return borderSelectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclassed to map <code>FontUIResource</code>s to null. If
|
||||
* <code>font</code> is null, or a <code>FontUIResource</code>, this
|
||||
* has the effect of letting the font of the JTree show
|
||||
* through. On the other hand, if <code>font</code> is non-null, and not
|
||||
* a <code>FontUIResource</code>, the font becomes <code>font</code>.
|
||||
*/
|
||||
public void setFont(Font font) {
|
||||
if(font instanceof FontUIResource)
|
||||
font = null;
|
||||
super.setFont(font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font of this component.
|
||||
* @return this component's font; if a font has not been set
|
||||
* for this component, the font of its parent is returned
|
||||
*/
|
||||
public Font getFont() {
|
||||
Font font = super.getFont();
|
||||
|
||||
if (font == null && tree != null) {
|
||||
// Strive to return a non-null value, otherwise the html support
|
||||
// will typically pick up the wrong font in certain situations.
|
||||
font = tree.getFont();
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclassed to map <code>ColorUIResource</code>s to null. If
|
||||
* <code>color</code> is null, or a <code>ColorUIResource</code>, this
|
||||
* has the effect of letting the background color of the JTree show
|
||||
* through. On the other hand, if <code>color</code> is non-null, and not
|
||||
* a <code>ColorUIResource</code>, the background becomes
|
||||
* <code>color</code>.
|
||||
*/
|
||||
public void setBackground(Color color) {
|
||||
if(color instanceof ColorUIResource)
|
||||
color = null;
|
||||
super.setBackground(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the renderer based on the passed in components.
|
||||
* The value is set from messaging the tree with
|
||||
* <code>convertValueToText</code>, which ultimately invokes
|
||||
* <code>toString</code> on <code>value</code>.
|
||||
* The foreground color is set based on the selection and the icon
|
||||
* is set based on the <code>leaf</code> and <code>expanded</code>
|
||||
* parameters.
|
||||
*/
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean sel,
|
||||
boolean expanded,
|
||||
boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
String stringValue = tree.convertValueToText(value, sel,
|
||||
expanded, leaf, row, hasFocus);
|
||||
|
||||
this.tree = tree;
|
||||
this.hasFocus = hasFocus;
|
||||
setText(stringValue);
|
||||
|
||||
Color fg = null;
|
||||
isDropCell = false;
|
||||
|
||||
JTree.DropLocation dropLocation = tree.getDropLocation();
|
||||
if (dropLocation != null
|
||||
&& dropLocation.getChildIndex() == -1
|
||||
&& tree.getRowForPath(dropLocation.getPath()) == row) {
|
||||
|
||||
Color col = DefaultLookup.getColor(this, ui, "Tree.dropCellForeground");
|
||||
if (col != null) {
|
||||
fg = col;
|
||||
} else {
|
||||
fg = getTextSelectionColor();
|
||||
}
|
||||
|
||||
isDropCell = true;
|
||||
} else if (sel) {
|
||||
fg = getTextSelectionColor();
|
||||
} else {
|
||||
fg = getTextNonSelectionColor();
|
||||
}
|
||||
|
||||
setForeground(fg);
|
||||
|
||||
Icon icon = null;
|
||||
if (leaf) {
|
||||
icon = getLeafIcon();
|
||||
} else if (expanded) {
|
||||
icon = getOpenIcon();
|
||||
} else {
|
||||
icon = getClosedIcon();
|
||||
}
|
||||
|
||||
if (!tree.isEnabled()) {
|
||||
setEnabled(false);
|
||||
LookAndFeel laf = UIManager.getLookAndFeel();
|
||||
Icon disabledIcon = laf.getDisabledIcon(tree, icon);
|
||||
if (disabledIcon != null) icon = disabledIcon;
|
||||
setDisabledIcon(icon);
|
||||
} else {
|
||||
setEnabled(true);
|
||||
setIcon(icon);
|
||||
}
|
||||
setComponentOrientation(tree.getComponentOrientation());
|
||||
|
||||
selected = sel;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints the value. The background is filled based on selected.
|
||||
*/
|
||||
public void paint(Graphics g) {
|
||||
Color bColor;
|
||||
|
||||
if (isDropCell) {
|
||||
bColor = DefaultLookup.getColor(this, ui, "Tree.dropCellBackground");
|
||||
if (bColor == null) {
|
||||
bColor = getBackgroundSelectionColor();
|
||||
}
|
||||
} else if (selected) {
|
||||
bColor = getBackgroundSelectionColor();
|
||||
} else {
|
||||
bColor = getBackgroundNonSelectionColor();
|
||||
if (bColor == null) {
|
||||
bColor = getBackground();
|
||||
}
|
||||
}
|
||||
|
||||
int imageOffset = -1;
|
||||
if (bColor != null && fillBackground) {
|
||||
imageOffset = getLabelStart();
|
||||
g.setColor(bColor);
|
||||
if(getComponentOrientation().isLeftToRight()) {
|
||||
g.fillRect(imageOffset, 0, getWidth() - imageOffset,
|
||||
getHeight());
|
||||
} else {
|
||||
g.fillRect(0, 0, getWidth() - imageOffset,
|
||||
getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFocus) {
|
||||
if (drawsFocusBorderAroundIcon) {
|
||||
imageOffset = 0;
|
||||
}
|
||||
else if (imageOffset == -1) {
|
||||
imageOffset = getLabelStart();
|
||||
}
|
||||
if(getComponentOrientation().isLeftToRight()) {
|
||||
paintFocus(g, imageOffset, 0, getWidth() - imageOffset,
|
||||
getHeight(), bColor);
|
||||
} else {
|
||||
paintFocus(g, 0, 0, getWidth() - imageOffset, getHeight(), bColor);
|
||||
}
|
||||
}
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
private void paintFocus(Graphics g, int x, int y, int w, int h, Color notColor) {
|
||||
Color bsColor = getBorderSelectionColor();
|
||||
|
||||
if (bsColor != null && (selected || !drawDashedFocusIndicator)) {
|
||||
g.setColor(bsColor);
|
||||
g.drawRect(x, y, w - 1, h - 1);
|
||||
}
|
||||
if (drawDashedFocusIndicator && notColor != null) {
|
||||
if (treeBGColor != notColor) {
|
||||
treeBGColor = notColor;
|
||||
focusBGColor = new Color(~notColor.getRGB());
|
||||
}
|
||||
g.setColor(focusBGColor);
|
||||
BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
private int getLabelStart() {
|
||||
Icon currentI = getIcon();
|
||||
if(currentI != null && getText() != null) {
|
||||
return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides <code>JComponent.getPreferredSize</code> to
|
||||
* return slightly wider preferred size value.
|
||||
*/
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension retDimension = super.getPreferredSize();
|
||||
|
||||
if(retDimension != null)
|
||||
retDimension = new Dimension(retDimension.width + 3,
|
||||
retDimension.height);
|
||||
return retDimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void validate() {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public void invalidate() {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void revalidate() {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void repaint(long tm, int x, int y, int width, int height) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void repaint(Rectangle r) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public void repaint() {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
|
||||
// Strings get interned...
|
||||
if (propertyName == "text"
|
||||
|| ((propertyName == "font" || propertyName == "foreground")
|
||||
&& oldValue != newValue
|
||||
&& getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
|
||||
|
||||
super.firePropertyChange(propertyName, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, char oldValue, char newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, short oldValue, short newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, int oldValue, int newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, long oldValue, long newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, float oldValue, float newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, double oldValue, double newValue) {}
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
* See the <a href="#override">Implementation Note</a>
|
||||
* for more information.
|
||||
*/
|
||||
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
|
||||
|
||||
}
|
|
@ -0,0 +1,717 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.util.*;
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.io.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* A simple tree data model that uses TreeNodes.
|
||||
* For further information and examples that use DefaultTreeModel,
|
||||
* see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial.</em>
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Ray Ryan
|
||||
* @author Scott Violet
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public class DefaultTreeModel implements Serializable, TreeModel {
|
||||
/** Root of the tree. */
|
||||
protected TreeNode root;
|
||||
/** Listeners. */
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
/**
|
||||
* Determines how the <code>isLeaf</code> method figures
|
||||
* out if a node is a leaf node. If true, a node is a leaf
|
||||
* node if it does not allow children. (If it allows
|
||||
* children, it is not a leaf node, even if no children
|
||||
* are present.) That lets you distinguish between <i>folder</i>
|
||||
* nodes and <i>file</i> nodes in a file system, for example.
|
||||
* <p>
|
||||
* If this value is false, then any node which has no
|
||||
* children is a leaf node, and any node may acquire
|
||||
* children.
|
||||
*
|
||||
* @see TreeNode#getAllowsChildren
|
||||
* @see TreeModel#isLeaf
|
||||
* @see #setAsksAllowsChildren
|
||||
*/
|
||||
protected boolean asksAllowsChildren;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a tree in which any node can have children.
|
||||
*
|
||||
* @param root a TreeNode object that is the root of the tree
|
||||
* @see #DefaultTreeModel(TreeNode, boolean)
|
||||
*/
|
||||
@ConstructorProperties({"root"})
|
||||
public DefaultTreeModel(TreeNode root) {
|
||||
this(root, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tree specifying whether any node can have children,
|
||||
* or whether only certain nodes can have children.
|
||||
*
|
||||
* @param root a TreeNode object that is the root of the tree
|
||||
* @param asksAllowsChildren a boolean, false if any node can
|
||||
* have children, true if each node is asked to see if
|
||||
* it can have children
|
||||
* @see #asksAllowsChildren
|
||||
*/
|
||||
public DefaultTreeModel(TreeNode root, boolean asksAllowsChildren) {
|
||||
super();
|
||||
this.root = root;
|
||||
this.asksAllowsChildren = asksAllowsChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not to test leafness by asking getAllowsChildren()
|
||||
* or isLeaf() to the TreeNodes. If newvalue is true, getAllowsChildren()
|
||||
* is messaged, otherwise isLeaf() is messaged.
|
||||
*
|
||||
* @param newValue if true, getAllowsChildren() is messaged, otherwise
|
||||
* isLeaf() is messaged
|
||||
*/
|
||||
public void setAsksAllowsChildren(boolean newValue) {
|
||||
asksAllowsChildren = newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells how leaf nodes are determined.
|
||||
*
|
||||
* @return true if only nodes which do not allow children are
|
||||
* leaf nodes, false if nodes which have no children
|
||||
* (even if allowed) are leaf nodes
|
||||
* @see #asksAllowsChildren
|
||||
*/
|
||||
public boolean asksAllowsChildren() {
|
||||
return asksAllowsChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root to <code>root</code>. A null <code>root</code> implies
|
||||
* the tree is to display nothing, and is legal.
|
||||
*
|
||||
* @param root new value of tree root
|
||||
*/
|
||||
public void setRoot(TreeNode root) {
|
||||
Object oldRoot = this.root;
|
||||
this.root = root;
|
||||
if (root == null && oldRoot != null) {
|
||||
fireTreeStructureChanged(this, null);
|
||||
}
|
||||
else {
|
||||
nodeStructureChanged(root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root of the tree. Returns null only if the tree has
|
||||
* no nodes.
|
||||
*
|
||||
* @return the root of the tree
|
||||
*/
|
||||
public Object getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of child in parent.
|
||||
* If either the parent or child is <code>null</code>, returns -1.
|
||||
* @param parent a note in the tree, obtained from this data source
|
||||
* @param child the node we are interested in
|
||||
* @return the index of the child in the parent, or -1
|
||||
* if either the parent or the child is <code>null</code>
|
||||
*/
|
||||
public int getIndexOfChild(Object parent, Object child) {
|
||||
if(parent == null || child == null)
|
||||
return -1;
|
||||
return ((TreeNode)parent).getIndex((TreeNode)child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child of <I>parent</I> at index <I>index</I> in the parent's
|
||||
* child array. <I>parent</I> must be a node previously obtained from
|
||||
* this data source. This should not return null if <i>index</i>
|
||||
* is a valid index for <i>parent</i> (that is <i>index</i> >= 0 &&
|
||||
* <i>index</i> < getChildCount(<i>parent</i>)).
|
||||
*
|
||||
* @param parent a node in the tree, obtained from this data source
|
||||
* @return the child of <I>parent</I> at index <I>index</I>
|
||||
*/
|
||||
public Object getChild(Object parent, int index) {
|
||||
return ((TreeNode)parent).getChildAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of children of <I>parent</I>. Returns 0 if the node
|
||||
* is a leaf or if it has no children. <I>parent</I> must be a node
|
||||
* previously obtained from this data source.
|
||||
*
|
||||
* @param parent a node in the tree, obtained from this data source
|
||||
* @return the number of children of the node <I>parent</I>
|
||||
*/
|
||||
public int getChildCount(Object parent) {
|
||||
return ((TreeNode)parent).getChildCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified node is a leaf node.
|
||||
* The way the test is performed depends on the
|
||||
* <code>askAllowsChildren</code> setting.
|
||||
*
|
||||
* @param node the node to check
|
||||
* @return true if the node is a leaf node
|
||||
*
|
||||
* @see #asksAllowsChildren
|
||||
* @see TreeModel#isLeaf
|
||||
*/
|
||||
public boolean isLeaf(Object node) {
|
||||
if(asksAllowsChildren)
|
||||
return !((TreeNode)node).getAllowsChildren();
|
||||
return ((TreeNode)node).isLeaf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method if you've modified the {@code TreeNode}s upon which
|
||||
* this model depends. The model will notify all of its listeners that the
|
||||
* model has changed.
|
||||
*/
|
||||
public void reload() {
|
||||
reload(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the user object of the TreeNode identified by path
|
||||
* and posts a node changed. If you use custom user objects in
|
||||
* the TreeModel you're going to need to subclass this and
|
||||
* set the user object of the changed node to something meaningful.
|
||||
*/
|
||||
public void valueForPathChanged(TreePath path, Object newValue) {
|
||||
MutableTreeNode aNode = (MutableTreeNode)path.getLastPathComponent();
|
||||
|
||||
aNode.setUserObject(newValue);
|
||||
nodeChanged(aNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked this to insert newChild at location index in parents children.
|
||||
* This will then message nodesWereInserted to create the appropriate
|
||||
* event. This is the preferred way to add children as it will create
|
||||
* the appropriate event.
|
||||
*
|
||||
* @param newChild child node to be inserted
|
||||
* @param parent node to which children new node will be added
|
||||
* @param index index of parent's children
|
||||
*/
|
||||
public void insertNodeInto(MutableTreeNode newChild,
|
||||
MutableTreeNode parent, int index){
|
||||
parent.insert(newChild, index);
|
||||
|
||||
int[] newIndexs = new int[1];
|
||||
|
||||
newIndexs[0] = index;
|
||||
nodesWereInserted(parent, newIndexs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Message this to remove node from its parent. This will message
|
||||
* nodesWereRemoved to create the appropriate event. This is the
|
||||
* preferred way to remove a node as it handles the event creation
|
||||
* for you.
|
||||
*
|
||||
* @param node the node to be removed from it's parrent
|
||||
*/
|
||||
public void removeNodeFromParent(MutableTreeNode node) {
|
||||
MutableTreeNode parent = (MutableTreeNode)node.getParent();
|
||||
|
||||
if(parent == null)
|
||||
throw new IllegalArgumentException("node does not have a parent.");
|
||||
|
||||
int[] childIndex = new int[1];
|
||||
Object[] removedArray = new Object[1];
|
||||
|
||||
childIndex[0] = parent.getIndex(node);
|
||||
parent.remove(childIndex[0]);
|
||||
removedArray[0] = node;
|
||||
nodesWereRemoved(parent, childIndex, removedArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method after you've changed how node is to be
|
||||
* represented in the tree.
|
||||
*
|
||||
* @param node the changed node
|
||||
*/
|
||||
public void nodeChanged(TreeNode node) {
|
||||
if(listenerList != null && node != null) {
|
||||
TreeNode parent = node.getParent();
|
||||
|
||||
if(parent != null) {
|
||||
int anIndex = parent.getIndex(node);
|
||||
if(anIndex != -1) {
|
||||
int[] cIndexs = new int[1];
|
||||
|
||||
cIndexs[0] = anIndex;
|
||||
nodesChanged(parent, cIndexs);
|
||||
}
|
||||
}
|
||||
else if (node == getRoot()) {
|
||||
nodesChanged(node, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method if you've modified the {@code TreeNode}s upon which
|
||||
* this model depends. The model will notify all of its listeners that the
|
||||
* model has changed below the given node.
|
||||
*
|
||||
* @param node the node below which the model has changed
|
||||
*/
|
||||
public void reload(TreeNode node) {
|
||||
if(node != null) {
|
||||
fireTreeStructureChanged(this, getPathToRoot(node), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method after you've inserted some TreeNodes into
|
||||
* node. childIndices should be the index of the new elements and
|
||||
* must be sorted in ascending order.
|
||||
*
|
||||
* @param node parent node which children count been incremented
|
||||
* @param childIndices indexes of inserted children
|
||||
*/
|
||||
public void nodesWereInserted(TreeNode node, int[] childIndices) {
|
||||
if(listenerList != null && node != null && childIndices != null
|
||||
&& childIndices.length > 0) {
|
||||
int cCount = childIndices.length;
|
||||
Object[] newChildren = new Object[cCount];
|
||||
|
||||
for(int counter = 0; counter < cCount; counter++)
|
||||
newChildren[counter] = node.getChildAt(childIndices[counter]);
|
||||
fireTreeNodesInserted(this, getPathToRoot(node), childIndices,
|
||||
newChildren);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method after you've removed some TreeNodes from
|
||||
* node. childIndices should be the index of the removed elements and
|
||||
* must be sorted in ascending order. And removedChildren should be
|
||||
* the array of the children objects that were removed.
|
||||
*
|
||||
* @param node parent node which childred were removed
|
||||
* @param childIndices indexes of removed childs
|
||||
* @param removedChildren array of the children objects that were removed
|
||||
*/
|
||||
public void nodesWereRemoved(TreeNode node, int[] childIndices,
|
||||
Object[] removedChildren) {
|
||||
if(node != null && childIndices != null) {
|
||||
fireTreeNodesRemoved(this, getPathToRoot(node), childIndices,
|
||||
removedChildren);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method after you've changed how the children identified by
|
||||
* childIndicies are to be represented in the tree.
|
||||
*
|
||||
* @param node changed node
|
||||
* @param childIndices indexes of changed children
|
||||
*/
|
||||
public void nodesChanged(TreeNode node, int[] childIndices) {
|
||||
if(node != null) {
|
||||
if (childIndices != null) {
|
||||
int cCount = childIndices.length;
|
||||
|
||||
if(cCount > 0) {
|
||||
Object[] cChildren = new Object[cCount];
|
||||
|
||||
for(int counter = 0; counter < cCount; counter++)
|
||||
cChildren[counter] = node.getChildAt
|
||||
(childIndices[counter]);
|
||||
fireTreeNodesChanged(this, getPathToRoot(node),
|
||||
childIndices, cChildren);
|
||||
}
|
||||
}
|
||||
else if (node == getRoot()) {
|
||||
fireTreeNodesChanged(this, getPathToRoot(node), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke this method if you've totally changed the children of
|
||||
* node and its children's children... This will post a
|
||||
* treeStructureChanged event.
|
||||
*
|
||||
* @param node changed node
|
||||
*/
|
||||
public void nodeStructureChanged(TreeNode node) {
|
||||
if(node != null) {
|
||||
fireTreeStructureChanged(this, getPathToRoot(node), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the parents of node up to and including the root node,
|
||||
* where the original node is the last element in the returned array.
|
||||
* The length of the returned array gives the node's depth in the
|
||||
* tree.
|
||||
*
|
||||
* @param aNode the TreeNode to get the path for
|
||||
* @return an array of TreeNodes giving the path from the root
|
||||
*/
|
||||
public TreeNode[] getPathToRoot(TreeNode aNode) {
|
||||
return getPathToRoot(aNode, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the parents of node up to and including the root node,
|
||||
* where the original node is the last element in the returned array.
|
||||
* The length of the returned array gives the node's depth in the
|
||||
* tree.
|
||||
*
|
||||
* @param aNode the TreeNode to get the path for
|
||||
* @param depth an int giving the number of steps already taken towards
|
||||
* the root (on recursive calls), used to size the returned array
|
||||
* @return an array of TreeNodes giving the path from the root to the
|
||||
* specified node
|
||||
*/
|
||||
protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) {
|
||||
TreeNode[] retNodes;
|
||||
// This method recurses, traversing towards the root in order
|
||||
// size the array. On the way back, it fills in the nodes,
|
||||
// starting from the root and working back to the original node.
|
||||
|
||||
/* Check for null, in case someone passed in a null node, or
|
||||
they passed in an element that isn't rooted at root. */
|
||||
if(aNode == null) {
|
||||
if(depth == 0)
|
||||
return null;
|
||||
else
|
||||
retNodes = new TreeNode[depth];
|
||||
}
|
||||
else {
|
||||
depth++;
|
||||
if(aNode == root)
|
||||
retNodes = new TreeNode[depth];
|
||||
else
|
||||
retNodes = getPathToRoot(aNode.getParent(), depth);
|
||||
retNodes[retNodes.length - depth] = aNode;
|
||||
}
|
||||
return retNodes;
|
||||
}
|
||||
|
||||
//
|
||||
// Events
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds a listener for the TreeModelEvent posted after the tree changes.
|
||||
*
|
||||
* @see #removeTreeModelListener
|
||||
* @param l the listener to add
|
||||
*/
|
||||
public void addTreeModelListener(TreeModelListener l) {
|
||||
listenerList.add(TreeModelListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener previously added with <B>addTreeModelListener()</B>.
|
||||
*
|
||||
* @see #addTreeModelListener
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
public void removeTreeModelListener(TreeModelListener l) {
|
||||
listenerList.remove(TreeModelListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the tree model listeners
|
||||
* registered on this model.
|
||||
*
|
||||
* @return all of this model's <code>TreeModelListener</code>s
|
||||
* or an empty
|
||||
* array if no tree model listeners are currently registered
|
||||
*
|
||||
* @see #addTreeModelListener
|
||||
* @see #removeTreeModelListener
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public TreeModelListener[] getTreeModelListeners() {
|
||||
return listenerList.getListeners(TreeModelListener.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
*
|
||||
* @param source the source of the {@code TreeModelEvent};
|
||||
* typically {@code this}
|
||||
* @param path the path to the parent of the nodes that changed; use
|
||||
* {@code null} to identify the root has changed
|
||||
* @param childIndices the indices of the changed elements
|
||||
* @param children the changed elements
|
||||
*/
|
||||
protected void fireTreeNodesChanged(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
*
|
||||
* @param source the source of the {@code TreeModelEvent};
|
||||
* typically {@code this}
|
||||
* @param path the path to the parent the nodes were added to
|
||||
* @param childIndices the indices of the new elements
|
||||
* @param children the new elements
|
||||
*/
|
||||
protected void fireTreeNodesInserted(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
*
|
||||
* @param source the source of the {@code TreeModelEvent};
|
||||
* typically {@code this}
|
||||
* @param path the path to the parent the nodes were removed from
|
||||
* @param childIndices the indices of the removed elements
|
||||
* @param children the removed elements
|
||||
*/
|
||||
protected void fireTreeNodesRemoved(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
*
|
||||
* @param source the source of the {@code TreeModelEvent};
|
||||
* typically {@code this}
|
||||
* @param path the path to the parent of the structure that has changed;
|
||||
* use {@code null} to identify the root has changed
|
||||
* @param childIndices the indices of the affected elements
|
||||
* @param children the affected elements
|
||||
*/
|
||||
protected void fireTreeStructureChanged(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
*
|
||||
* @param source the source of the {@code TreeModelEvent};
|
||||
* typically {@code this}
|
||||
* @param path the path to the parent of the structure that has changed;
|
||||
* use {@code null} to identify the root has changed
|
||||
*/
|
||||
private void fireTreeStructureChanged(Object source, TreePath path) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path);
|
||||
((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the objects currently registered
|
||||
* as <code><em>Foo</em>Listener</code>s
|
||||
* upon this model.
|
||||
* <code><em>Foo</em>Listener</code>s are registered using the
|
||||
* <code>add<em>Foo</em>Listener</code> method.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* You can specify the <code>listenerType</code> argument
|
||||
* with a class literal,
|
||||
* such as
|
||||
* <code><em>Foo</em>Listener.class</code>.
|
||||
* For example, you can query a
|
||||
* <code>DefaultTreeModel</code> <code>m</code>
|
||||
* for its tree model listeners with the following code:
|
||||
*
|
||||
* <pre>TreeModelListener[] tmls = (TreeModelListener[])(m.getListeners(TreeModelListener.class));</pre>
|
||||
*
|
||||
* If no such listeners exist, this method returns an empty array.
|
||||
*
|
||||
* @param <T> the listener type
|
||||
* @param listenerType the type of listeners requested
|
||||
* @return an array of all objects registered as
|
||||
* <code><em>Foo</em>Listener</code>s on this component,
|
||||
* or an empty array if no such
|
||||
* listeners have been added
|
||||
* @exception ClassCastException if <code>listenerType</code>
|
||||
* doesn't specify a class or interface that implements
|
||||
* <code>java.util.EventListener</code>
|
||||
*
|
||||
* @see #getTreeModelListeners
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
|
||||
return listenerList.getListeners(listenerType);
|
||||
}
|
||||
|
||||
// Serialization support.
|
||||
private void writeObject(ObjectOutputStream s) throws IOException {
|
||||
Vector<Object> values = new Vector<Object>();
|
||||
|
||||
s.defaultWriteObject();
|
||||
// Save the root, if its Serializable.
|
||||
if(root != null && root instanceof Serializable) {
|
||||
values.addElement("root");
|
||||
values.addElement(root);
|
||||
}
|
||||
s.writeObject(values);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream.GetField f = s.readFields();
|
||||
EventListenerList newListenerList = (EventListenerList) f.get("listenerList", null);
|
||||
if (newListenerList == null) {
|
||||
throw new InvalidObjectException("Null listenerList");
|
||||
}
|
||||
listenerList = newListenerList;
|
||||
asksAllowsChildren = f.get("asksAllowsChildren", false);
|
||||
|
||||
Vector<?> values = (Vector)s.readObject();
|
||||
int indexCounter = 0;
|
||||
int maxCounter = values.size();
|
||||
|
||||
if(indexCounter < maxCounter && values.elementAt(indexCounter).
|
||||
equals("root")) {
|
||||
TreeNode newRoot = (TreeNode)values.elementAt(++indexCounter);
|
||||
if (newRoot == null) {
|
||||
throw new InvalidObjectException("Null root");
|
||||
}
|
||||
root = newRoot;
|
||||
indexCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // End of class DefaultTreeModel
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
|
||||
/**
|
||||
* Exception used to stop an expand/collapse from happening.
|
||||
* See <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/events/treewillexpandlistener.html">How to Write a Tree-Will-Expand Listener</a>
|
||||
* in <em>The Java Tutorial</em>
|
||||
* for further information and examples.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public class ExpandVetoException extends Exception {
|
||||
/** The event that the exception was created for. */
|
||||
protected TreeExpansionEvent event;
|
||||
|
||||
/**
|
||||
* Constructs an ExpandVetoException object with no message.
|
||||
*
|
||||
* @param event a TreeExpansionEvent object
|
||||
*/
|
||||
|
||||
public ExpandVetoException(TreeExpansionEvent event) {
|
||||
this(event, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an ExpandVetoException object with the specified message.
|
||||
*
|
||||
* @param event a TreeExpansionEvent object
|
||||
* @param message a String containing the message
|
||||
*/
|
||||
public ExpandVetoException(TreeExpansionEvent event, String message) {
|
||||
super(message);
|
||||
this.event = event;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
/**
|
||||
* Defines the requirements for a tree node object that can change --
|
||||
* by adding or removing child nodes, or by changing the contents
|
||||
* of a user object stored in the node.
|
||||
*
|
||||
* @see DefaultMutableTreeNode
|
||||
* @see javax.swing.JTree
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Scott Violet
|
||||
*/
|
||||
|
||||
public interface MutableTreeNode extends TreeNode
|
||||
{
|
||||
/**
|
||||
* Adds <code>child</code> to the receiver at <code>index</code>.
|
||||
* <code>child</code> will be messaged with <code>setParent</code>.
|
||||
*
|
||||
* @param child node to be added
|
||||
* @param index index of the receiver
|
||||
*/
|
||||
void insert(MutableTreeNode child, int index);
|
||||
|
||||
/**
|
||||
* Removes the child at <code>index</code> from the receiver.
|
||||
*
|
||||
* @param index index of child to be removed
|
||||
*/
|
||||
void remove(int index);
|
||||
|
||||
/**
|
||||
* Removes <code>node</code> from the receiver. <code>setParent</code>
|
||||
* will be messaged on <code>node</code>.
|
||||
*
|
||||
* @param node node to be removed from the receiver
|
||||
*/
|
||||
void remove(MutableTreeNode node);
|
||||
|
||||
/**
|
||||
* Resets the user object of the receiver to <code>object</code>.
|
||||
*
|
||||
* @param object object to be set as a receiver
|
||||
*/
|
||||
void setUserObject(Object object);
|
||||
|
||||
/**
|
||||
* Removes the receiver from its parent.
|
||||
*/
|
||||
void removeFromParent();
|
||||
|
||||
/**
|
||||
* Sets the parent of the receiver to <code>newParent</code>.
|
||||
*
|
||||
* @param newParent node to be set as parent of the receiver
|
||||
*/
|
||||
void setParent(MutableTreeNode newParent);
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
/**
|
||||
* Defines the requirements for an object that translates paths in
|
||||
* the tree into display rows.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public interface RowMapper
|
||||
{
|
||||
/**
|
||||
* Returns the rows that the TreePath instances in <code>path</code>
|
||||
* are being displayed at. The receiver should return an array of
|
||||
* the same length as that passed in, and if one of the TreePaths
|
||||
* in <code>path</code> is not valid its entry in the array should
|
||||
* be set to -1.
|
||||
*
|
||||
* @param path array of TreePath to parse
|
||||
* @return the rows that the TreePath instances in {@code path} are
|
||||
* being displayed at
|
||||
*/
|
||||
int[] getRowsForPaths(TreePath[] path);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.CellEditor;
|
||||
import javax.swing.JTree;
|
||||
|
||||
/**
|
||||
* Adds to CellEditor the extensions necessary to configure an editor
|
||||
* in a tree.
|
||||
*
|
||||
* @see javax.swing.JTree
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
|
||||
public interface TreeCellEditor extends CellEditor
|
||||
{
|
||||
/**
|
||||
* Sets an initial <I>value</I> for the editor. This will cause
|
||||
* the editor to stopEditing and lose any partially edited value
|
||||
* if the editor is editing when this method is called. <p>
|
||||
*
|
||||
* Returns the component that should be added to the client's
|
||||
* Component hierarchy. Once installed in the client's hierarchy
|
||||
* this component will then be able to draw and receive user input.
|
||||
*
|
||||
* @param tree the JTree that is asking the editor to edit;
|
||||
* this parameter can be null
|
||||
* @param value the value of the cell to be edited
|
||||
* @param isSelected true if the cell is to be rendered with
|
||||
* selection highlighting
|
||||
* @param expanded true if the node is expanded
|
||||
* @param leaf true if the node is a leaf node
|
||||
* @param row the row index of the node being edited
|
||||
* @return the component for editing
|
||||
*/
|
||||
Component getTreeCellEditorComponent(JTree tree, Object value,
|
||||
boolean isSelected, boolean expanded,
|
||||
boolean leaf, int row);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.JTree;
|
||||
|
||||
/**
|
||||
* Defines the requirements for an object that displays a tree node.
|
||||
* See <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial</em>
|
||||
* for an example of implementing a tree cell renderer
|
||||
* that displays custom icons.
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Ray Ryan
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public interface TreeCellRenderer {
|
||||
|
||||
/**
|
||||
* Sets the value of the current tree cell to <code>value</code>.
|
||||
* If <code>selected</code> is true, the cell will be drawn as if
|
||||
* selected. If <code>expanded</code> is true the node is currently
|
||||
* expanded and if <code>leaf</code> is true the node represents a
|
||||
* leaf and if <code>hasFocus</code> is true the node currently has
|
||||
* focus. <code>tree</code> is the <code>JTree</code> the receiver is being
|
||||
* configured for. Returns the <code>Component</code> that the renderer
|
||||
* uses to draw the value.
|
||||
* <p>
|
||||
* The <code>TreeCellRenderer</code> is also responsible for rendering the
|
||||
* the cell representing the tree's current DnD drop location if
|
||||
* it has one. If this renderer cares about rendering
|
||||
* the DnD drop location, it should query the tree directly to
|
||||
* see if the given row represents the drop location:
|
||||
* <pre>
|
||||
* JTree.DropLocation dropLocation = tree.getDropLocation();
|
||||
* if (dropLocation != null
|
||||
* && dropLocation.getChildIndex() == -1
|
||||
* && tree.getRowForPath(dropLocation.getPath()) == row) {
|
||||
*
|
||||
* // this row represents the current drop location
|
||||
* // so render it specially, perhaps with a different color
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param tree the receiver is being configured for
|
||||
* @param value the value to render
|
||||
* @param selected whether node is selected
|
||||
* @param expanded whether node is expanded
|
||||
* @param leaf whether node is a lead node
|
||||
* @param row row index
|
||||
* @param hasFocus whether node has focus
|
||||
* @return the {@code Component} that the renderer uses to draw the value
|
||||
*/
|
||||
Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean selected, boolean expanded,
|
||||
boolean leaf, int row, boolean hasFocus);
|
||||
|
||||
}
|
161
src/java.desktop/share/classes/javax/swing/tree/TreeModel.java
Normal file
161
src/java.desktop/share/classes/javax/swing/tree/TreeModel.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* The model used by <code>JTree</code>.
|
||||
* <p>
|
||||
* <code>JTree</code> and its related classes make extensive use of
|
||||
* <code>TreePath</code>s for identifying nodes in the <code>TreeModel</code>.
|
||||
* If a <code>TreeModel</code> returns the same object, as compared by
|
||||
* <code>equals</code>, at two different indices under the same parent
|
||||
* than the resulting <code>TreePath</code> objects will be considered equal
|
||||
* as well. Some implementations may assume that if two
|
||||
* <code>TreePath</code>s are equal, they identify the same node. If this
|
||||
* condition is not met, painting problems and other oddities may result.
|
||||
* In other words, if <code>getChild</code> for a given parent returns
|
||||
* the same Object (as determined by <code>equals</code>) problems may
|
||||
* result, and it is recommended you avoid doing this.
|
||||
* <p>
|
||||
* Similarly <code>JTree</code> and its related classes place
|
||||
* <code>TreePath</code>s in <code>Map</code>s. As such if
|
||||
* a node is requested twice, the return values must be equal
|
||||
* (using the <code>equals</code> method) and have the same
|
||||
* <code>hashCode</code>.
|
||||
* <p>
|
||||
* For further information on tree models,
|
||||
* including an example of a custom implementation,
|
||||
* see <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial.</em>
|
||||
*
|
||||
* @see TreePath
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Ray Ryan
|
||||
*/
|
||||
public interface TreeModel
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns the root of the tree. Returns <code>null</code>
|
||||
* only if the tree has no nodes.
|
||||
*
|
||||
* @return the root of the tree
|
||||
*/
|
||||
public Object getRoot();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the child of <code>parent</code> at index <code>index</code>
|
||||
* in the parent's
|
||||
* child array. <code>parent</code> must be a node previously obtained
|
||||
* from this data source. This should not return <code>null</code>
|
||||
* if <code>index</code>
|
||||
* is a valid index for <code>parent</code> (that is <code>index >= 0 &&
|
||||
* index < getChildCount(parent</code>)).
|
||||
*
|
||||
* @param parent a node in the tree, obtained from this data source
|
||||
* @param index index of child to be returned
|
||||
* @return the child of {@code parent} at index {@code index}
|
||||
*/
|
||||
public Object getChild(Object parent, int index);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of children of <code>parent</code>.
|
||||
* Returns 0 if the node
|
||||
* is a leaf or if it has no children. <code>parent</code> must be a node
|
||||
* previously obtained from this data source.
|
||||
*
|
||||
* @param parent a node in the tree, obtained from this data source
|
||||
* @return the number of children of the node <code>parent</code>
|
||||
*/
|
||||
public int getChildCount(Object parent);
|
||||
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if <code>node</code> is a leaf.
|
||||
* It is possible for this method to return <code>false</code>
|
||||
* even if <code>node</code> has no children.
|
||||
* A directory in a filesystem, for example,
|
||||
* may contain no files; the node representing
|
||||
* the directory is not a leaf, but it also has no children.
|
||||
*
|
||||
* @param node a node in the tree, obtained from this data source
|
||||
* @return true if <code>node</code> is a leaf
|
||||
*/
|
||||
public boolean isLeaf(Object node);
|
||||
|
||||
/**
|
||||
* Messaged when the user has altered the value for the item identified
|
||||
* by <code>path</code> to <code>newValue</code>.
|
||||
* If <code>newValue</code> signifies a truly new value
|
||||
* the model should post a <code>treeNodesChanged</code> event.
|
||||
*
|
||||
* @param path path to the node that the user has altered
|
||||
* @param newValue the new value from the TreeCellEditor
|
||||
*/
|
||||
public void valueForPathChanged(TreePath path, Object newValue);
|
||||
|
||||
/**
|
||||
* Returns the index of child in parent. If either <code>parent</code>
|
||||
* or <code>child</code> is <code>null</code>, returns -1.
|
||||
* If either <code>parent</code> or <code>child</code> don't
|
||||
* belong to this tree model, returns -1.
|
||||
*
|
||||
* @param parent a node in the tree, obtained from this data source
|
||||
* @param child the node we are interested in
|
||||
* @return the index of the child in the parent, or -1 if either
|
||||
* <code>child</code> or <code>parent</code> are <code>null</code>
|
||||
* or don't belong to this tree model
|
||||
*/
|
||||
public int getIndexOfChild(Object parent, Object child);
|
||||
|
||||
//
|
||||
// Change Events
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds a listener for the <code>TreeModelEvent</code>
|
||||
* posted after the tree changes.
|
||||
*
|
||||
* @param l the listener to add
|
||||
* @see #removeTreeModelListener
|
||||
*/
|
||||
void addTreeModelListener(TreeModelListener l);
|
||||
|
||||
/**
|
||||
* Removes a listener previously added with
|
||||
* <code>addTreeModelListener</code>.
|
||||
*
|
||||
* @see #addTreeModelListener
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
void removeTreeModelListener(TreeModelListener l);
|
||||
|
||||
}
|
103
src/java.desktop/share/classes/javax/swing/tree/TreeNode.java
Normal file
103
src/java.desktop/share/classes/javax/swing/tree/TreeNode.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Defines the requirements for an object that can be used as a
|
||||
* tree node in a JTree.
|
||||
* <p>
|
||||
* Implementations of <code>TreeNode</code> that override <code>equals</code>
|
||||
* will typically need to override <code>hashCode</code> as well. Refer
|
||||
* to {@link javax.swing.tree.TreeModel} for more information.
|
||||
*
|
||||
* For further information and examples of using tree nodes,
|
||||
* see <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Tree Nodes</a>
|
||||
* in <em>The Java Tutorial.</em>
|
||||
*
|
||||
* @author Rob Davis
|
||||
* @author Scott Violet
|
||||
*/
|
||||
|
||||
public interface TreeNode
|
||||
{
|
||||
/**
|
||||
* Returns the child <code>TreeNode</code> at index
|
||||
* <code>childIndex</code>.
|
||||
*
|
||||
* @param childIndex index of child
|
||||
* @return the child node at given index
|
||||
*/
|
||||
TreeNode getChildAt(int childIndex);
|
||||
|
||||
/**
|
||||
* Returns the number of children <code>TreeNode</code>s the receiver
|
||||
* contains.
|
||||
*
|
||||
* @return the number of children the receiver contains
|
||||
*/
|
||||
int getChildCount();
|
||||
|
||||
/**
|
||||
* Returns the parent <code>TreeNode</code> of the receiver.
|
||||
*
|
||||
* @return the parent of the receiver
|
||||
*/
|
||||
TreeNode getParent();
|
||||
|
||||
/**
|
||||
* Returns the index of <code>node</code> in the receivers children.
|
||||
* If the receiver does not contain <code>node</code>, -1 will be
|
||||
* returned.
|
||||
*
|
||||
* @param node node to be loked for
|
||||
* @return index of specified node
|
||||
*/
|
||||
int getIndex(TreeNode node);
|
||||
|
||||
/**
|
||||
* Returns true if the receiver allows children.
|
||||
*
|
||||
* @return whether the receiver allows children
|
||||
*/
|
||||
boolean getAllowsChildren();
|
||||
|
||||
/**
|
||||
* Returns true if the receiver is a leaf.
|
||||
*
|
||||
* @return whether the receiver is a leaf
|
||||
*/
|
||||
boolean isLeaf();
|
||||
|
||||
/**
|
||||
* Returns the children of the receiver as an <code>Enumeration</code>.
|
||||
*
|
||||
* @return the children of the receiver as an {@code Enumeration}
|
||||
*/
|
||||
Enumeration<? extends TreeNode> children();
|
||||
}
|
363
src/java.desktop/share/classes/javax/swing/tree/TreePath.java
Normal file
363
src/java.desktop/share/classes/javax/swing/tree/TreePath.java
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import java.io.*;
|
||||
import java.beans.ConstructorProperties;
|
||||
|
||||
/**
|
||||
* {@code TreePath} represents an array of objects that uniquely
|
||||
* identify the path to a node in a tree. The elements of the array
|
||||
* are ordered with the root as the first element of the array. For
|
||||
* example, a file on the file system is uniquely identified based on
|
||||
* the array of parent directories and the name of the file. The path
|
||||
* {@code /tmp/foo/bar} could be represented by a {@code TreePath} as
|
||||
* {@code new TreePath(new Object[] {"tmp", "foo", "bar"})}.
|
||||
* <p>
|
||||
* {@code TreePath} is used extensively by {@code JTree} and related classes.
|
||||
* For example, {@code JTree} represents the selection as an array of
|
||||
* {@code TreePath}s. When used with {@code JTree}, the elements of the
|
||||
* path are the objects returned from the {@code TreeModel}. When {@code JTree}
|
||||
* is paired with {@code DefaultTreeModel}, the elements of the
|
||||
* path are {@code TreeNode}s. The following example illustrates extracting
|
||||
* the user object from the selection of a {@code JTree}:
|
||||
* <pre>
|
||||
* DefaultMutableTreeNode root = ...;
|
||||
* DefaultTreeModel model = new DefaultTreeModel(root);
|
||||
* JTree tree = new JTree(model);
|
||||
* ...
|
||||
* TreePath selectedPath = tree.getSelectionPath();
|
||||
* DefaultMutableTreeNode selectedNode =
|
||||
* ((DefaultMutableTreeNode)selectedPath.getLastPathComponent()).
|
||||
* getUserObject();
|
||||
* </pre>
|
||||
* Subclasses typically need override only {@code
|
||||
* getLastPathComponent}, and {@code getParentPath}. As {@code JTree}
|
||||
* internally creates {@code TreePath}s at various points, it's
|
||||
* generally not useful to subclass {@code TreePath} and use with
|
||||
* {@code JTree}.
|
||||
* <p>
|
||||
* While {@code TreePath} is serializable, a {@code
|
||||
* NotSerializableException} is thrown if any elements of the path are
|
||||
* not serializable.
|
||||
* <p>
|
||||
* For further information and examples of using tree paths,
|
||||
* see <a
|
||||
href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial.</em>
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @author Scott Violet
|
||||
* @author Philip Milne
|
||||
*/
|
||||
@SuppressWarnings("serial") // Same-version serialization only
|
||||
public class TreePath extends Object implements Serializable {
|
||||
/** Path representing the parent, null if lastPathComponent represents
|
||||
* the root. */
|
||||
private TreePath parentPath;
|
||||
/** Last path component. */
|
||||
private Object lastPathComponent;
|
||||
|
||||
/**
|
||||
* Creates a {@code TreePath} from an array. The array uniquely
|
||||
* identifies the path to a node.
|
||||
*
|
||||
* @param path an array of objects representing the path to a node
|
||||
* @throws IllegalArgumentException if {@code path} is {@code null},
|
||||
* empty, or contains a {@code null} value
|
||||
*/
|
||||
@ConstructorProperties({"path"})
|
||||
public TreePath(Object[] path) {
|
||||
if(path == null || path.length == 0)
|
||||
throw new IllegalArgumentException("path in TreePath must be non null and not empty.");
|
||||
lastPathComponent = path[path.length - 1];
|
||||
if (lastPathComponent == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Last path component must be non-null");
|
||||
}
|
||||
if(path.length > 1)
|
||||
parentPath = new TreePath(path, path.length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TreePath} containing a single element. This is
|
||||
* used to construct a {@code TreePath} identifying the root.
|
||||
*
|
||||
* @param lastPathComponent the root
|
||||
* @see #TreePath(Object[])
|
||||
* @throws IllegalArgumentException if {@code lastPathComponent} is
|
||||
* {@code null}
|
||||
*/
|
||||
public TreePath(Object lastPathComponent) {
|
||||
if(lastPathComponent == null)
|
||||
throw new IllegalArgumentException("path in TreePath must be non null.");
|
||||
this.lastPathComponent = lastPathComponent;
|
||||
parentPath = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TreePath} with the specified parent and element.
|
||||
*
|
||||
* @param parent the path to the parent, or {@code null} to indicate
|
||||
* the root
|
||||
* @param lastPathComponent the last path element
|
||||
* @throws IllegalArgumentException if {@code lastPathComponent} is
|
||||
* {@code null}
|
||||
*/
|
||||
protected TreePath(TreePath parent, Object lastPathComponent) {
|
||||
if(lastPathComponent == null)
|
||||
throw new IllegalArgumentException("path in TreePath must be non null.");
|
||||
parentPath = parent;
|
||||
this.lastPathComponent = lastPathComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TreePath} from an array. The returned
|
||||
* {@code TreePath} represents the elements of the array from
|
||||
* {@code 0} to {@code length - 1}.
|
||||
* <p>
|
||||
* This constructor is used internally, and generally not useful outside
|
||||
* of subclasses.
|
||||
*
|
||||
* @param path the array to create the {@code TreePath} from
|
||||
* @param length identifies the number of elements in {@code path} to
|
||||
* create the {@code TreePath} from
|
||||
* @throws NullPointerException if {@code path} is {@code null}
|
||||
* @throws ArrayIndexOutOfBoundsException if {@code length - 1} is
|
||||
* outside the range of the array
|
||||
* @throws IllegalArgumentException if any of the elements from
|
||||
* {@code 0} to {@code length - 1} are {@code null}
|
||||
*/
|
||||
protected TreePath(Object[] path, int length) {
|
||||
lastPathComponent = path[length - 1];
|
||||
if (lastPathComponent == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Path elements must be non-null");
|
||||
}
|
||||
if(length > 1)
|
||||
parentPath = new TreePath(path, length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@code TreePath}. This is provided for
|
||||
* subclasses that represent paths in a different
|
||||
* manner. Subclasses that use this constructor must override
|
||||
* {@code getLastPathComponent}, and {@code getParentPath}.
|
||||
*/
|
||||
protected TreePath() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered array of the elements of this {@code TreePath}.
|
||||
* The first element is the root.
|
||||
*
|
||||
* @return an array of the elements in this {@code TreePath}
|
||||
*/
|
||||
public Object[] getPath() {
|
||||
int i = getPathCount();
|
||||
Object[] result = new Object[i--];
|
||||
|
||||
for(TreePath path = this; path != null; path = path.getParentPath()) {
|
||||
result[i--] = path.getLastPathComponent();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element of this path.
|
||||
*
|
||||
* @return the last element in the path
|
||||
*/
|
||||
public Object getLastPathComponent() {
|
||||
return lastPathComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the path.
|
||||
*
|
||||
* @return the number of elements in the path
|
||||
*/
|
||||
public int getPathCount() {
|
||||
int result = 0;
|
||||
for(TreePath path = this; path != null; path = path.getParentPath()) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path element at the specified index.
|
||||
*
|
||||
* @param index the index of the element requested
|
||||
* @return the element at the specified index
|
||||
* @throws IllegalArgumentException if the index is outside the
|
||||
* range of this path
|
||||
*/
|
||||
public Object getPathComponent(int index) {
|
||||
int pathLength = getPathCount();
|
||||
|
||||
if(index < 0 || index >= pathLength)
|
||||
throw new IllegalArgumentException("Index " + index +
|
||||
" is out of the specified range");
|
||||
|
||||
TreePath path = this;
|
||||
|
||||
for(int i = pathLength-1; i != index; i--) {
|
||||
path = path.getParentPath();
|
||||
}
|
||||
return path.getLastPathComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code TreePath} to the specified object. This returns
|
||||
* {@code true} if {@code o} is a {@code TreePath} with the exact
|
||||
* same elements (as determined by using {@code equals} on each
|
||||
* element of the path).
|
||||
*
|
||||
* @param o the object to compare
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
if(o == this)
|
||||
return true;
|
||||
if(o instanceof TreePath) {
|
||||
TreePath oTreePath = (TreePath)o;
|
||||
|
||||
if(getPathCount() != oTreePath.getPathCount())
|
||||
return false;
|
||||
for(TreePath path = this; path != null;
|
||||
path = path.getParentPath()) {
|
||||
if (!(path.getLastPathComponent().equals
|
||||
(oTreePath.getLastPathComponent()))) {
|
||||
return false;
|
||||
}
|
||||
oTreePath = oTreePath.getParentPath();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code of this {@code TreePath}. The hash code of a
|
||||
* {@code TreePath} is the hash code of the last element in the path.
|
||||
*
|
||||
* @return the hashCode for the object
|
||||
*/
|
||||
public int hashCode() {
|
||||
return getLastPathComponent().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if <code>aTreePath</code> is a
|
||||
* descendant of this
|
||||
* {@code TreePath}. A {@code TreePath} {@code P1} is a descendant of a
|
||||
* {@code TreePath} {@code P2}
|
||||
* if {@code P1} contains all of the elements that make up
|
||||
* {@code P2's} path.
|
||||
* For example, if this object has the path {@code [a, b]},
|
||||
* and <code>aTreePath</code> has the path {@code [a, b, c]},
|
||||
* then <code>aTreePath</code> is a descendant of this object.
|
||||
* However, if <code>aTreePath</code> has the path {@code [a]},
|
||||
* then it is not a descendant of this object. By this definition
|
||||
* a {@code TreePath} is always considered a descendant of itself.
|
||||
* That is, <code>aTreePath.isDescendant(aTreePath)</code> returns
|
||||
* {@code true}.
|
||||
*
|
||||
* @param aTreePath the {@code TreePath} to check
|
||||
* @return true if <code>aTreePath</code> is a descendant of this path
|
||||
*/
|
||||
public boolean isDescendant(TreePath aTreePath) {
|
||||
if(aTreePath == this)
|
||||
return true;
|
||||
|
||||
if(aTreePath != null) {
|
||||
int pathLength = getPathCount();
|
||||
int oPathLength = aTreePath.getPathCount();
|
||||
|
||||
if(oPathLength < pathLength)
|
||||
// Can't be a descendant, has fewer components in the path.
|
||||
return false;
|
||||
while(oPathLength-- > pathLength)
|
||||
aTreePath = aTreePath.getParentPath();
|
||||
return equals(aTreePath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new path containing all the elements of this path
|
||||
* plus <code>child</code>. <code>child</code> is the last element
|
||||
* of the newly created {@code TreePath}.
|
||||
*
|
||||
* @param child the path element to add
|
||||
* @throws NullPointerException if {@code child} is {@code null}
|
||||
* @return a new path containing all the elements of this path
|
||||
* plus {@code child}
|
||||
*/
|
||||
public TreePath pathByAddingChild(Object child) {
|
||||
if(child == null)
|
||||
throw new NullPointerException("Null child not allowed");
|
||||
|
||||
return new TreePath(this, child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code TreePath} of the parent. A return value of
|
||||
* {@code null} indicates this is the root node.
|
||||
*
|
||||
* @return the parent path
|
||||
*/
|
||||
public TreePath getParentPath() {
|
||||
return parentPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string that displays and identifies this
|
||||
* object's properties.
|
||||
*
|
||||
* @return a String representation of this object
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder tempSpot = new StringBuilder("[");
|
||||
|
||||
for(int counter = 0, maxCounter = getPathCount();counter < maxCounter;
|
||||
counter++) {
|
||||
if(counter > 0)
|
||||
tempSpot.append(", ");
|
||||
tempSpot.append(getPathComponent(counter));
|
||||
}
|
||||
tempSpot.append("]");
|
||||
return tempSpot.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.tree;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
/**
|
||||
* This interface represents the current state of the selection for
|
||||
* the tree component.
|
||||
* For information and examples of using tree selection models,
|
||||
* see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html">How to Use Trees</a>
|
||||
* in <em>The Java Tutorial.</em>
|
||||
*
|
||||
* <p>
|
||||
* The state of the tree selection is characterized by
|
||||
* a set of TreePaths, and optionally a set of integers. The mapping
|
||||
* from TreePath to integer is done by way of an instance of RowMapper.
|
||||
* It is not necessary for a TreeSelectionModel to have a RowMapper to
|
||||
* correctly operate, but without a RowMapper <code>getSelectionRows</code>
|
||||
* will return null.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* A TreeSelectionModel can be configured to allow only one
|
||||
* path (<code>SINGLE_TREE_SELECTION</code>) a number of
|
||||
* contiguous paths (<code>CONTIGUOUS_TREE_SELECTION</code>) or a number of
|
||||
* discontiguous paths (<code>DISCONTIGUOUS_TREE_SELECTION</code>).
|
||||
* A <code>RowMapper</code> is used to determine if TreePaths are
|
||||
* contiguous.
|
||||
* In the absence of a RowMapper <code>CONTIGUOUS_TREE_SELECTION</code> and
|
||||
* <code>DISCONTIGUOUS_TREE_SELECTION</code> behave the same, that is they
|
||||
* allow any number of paths to be contained in the TreeSelectionModel.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* For a selection model of <code>CONTIGUOUS_TREE_SELECTION</code> any
|
||||
* time the paths are changed (<code>setSelectionPath</code>,
|
||||
* <code>addSelectionPath</code> ...) the TreePaths are again checked to
|
||||
* make they are contiguous. A check of the TreePaths can also be forced
|
||||
* by invoking <code>resetRowSelection</code>. How a set of discontiguous
|
||||
* TreePaths is mapped to a contiguous set is left to implementors of
|
||||
* this interface to enforce a particular policy.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* Implementations should combine duplicate TreePaths that are
|
||||
* added to the selection. For example, the following code
|
||||
* <pre>
|
||||
* TreePath[] paths = new TreePath[] { treePath, treePath };
|
||||
* treeSelectionModel.setSelectionPaths(paths);
|
||||
* </pre>
|
||||
* should result in only one path being selected:
|
||||
* <code>treePath</code>, and
|
||||
* not two copies of <code>treePath</code>.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* The lead TreePath is the last path that was added (or set). The lead
|
||||
* row is then the row that corresponds to the TreePath as determined
|
||||
* from the RowMapper.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
|
||||
public interface TreeSelectionModel
|
||||
{
|
||||
/** Selection can only contain one path at a time. */
|
||||
public static final int SINGLE_TREE_SELECTION = 1;
|
||||
|
||||
/** Selection can only be contiguous. This will only be enforced if
|
||||
* a RowMapper instance is provided. That is, if no RowMapper is set
|
||||
* this behaves the same as DISCONTIGUOUS_TREE_SELECTION. */
|
||||
public static final int CONTIGUOUS_TREE_SELECTION = 2;
|
||||
|
||||
/** Selection can contain any number of items that are not necessarily
|
||||
* contiguous. */
|
||||
public static final int DISCONTIGUOUS_TREE_SELECTION = 4;
|
||||
|
||||
/**
|
||||
* Sets the selection model, which must be one of SINGLE_TREE_SELECTION,
|
||||
* CONTIGUOUS_TREE_SELECTION or DISCONTIGUOUS_TREE_SELECTION.
|
||||
* <p>
|
||||
* This may change the selection if the current selection is not valid
|
||||
* for the new mode. For example, if three TreePaths are
|
||||
* selected when the mode is changed to <code>SINGLE_TREE_SELECTION</code>,
|
||||
* only one TreePath will remain selected. It is up to the particular
|
||||
* implementation to decide what TreePath remains selected.
|
||||
*
|
||||
* @param mode selection mode to be set
|
||||
*/
|
||||
void setSelectionMode(int mode);
|
||||
|
||||
/**
|
||||
* Returns the current selection mode, one of
|
||||
* <code>SINGLE_TREE_SELECTION</code>,
|
||||
* <code>CONTIGUOUS_TREE_SELECTION</code> or
|
||||
* <code>DISCONTIGUOUS_TREE_SELECTION</code>.
|
||||
*
|
||||
* @return the current selection mode
|
||||
*/
|
||||
int getSelectionMode();
|
||||
|
||||
/**
|
||||
* Sets the selection to path. If this represents a change, then
|
||||
* the TreeSelectionListeners are notified. If <code>path</code> is
|
||||
* null, this has the same effect as invoking <code>clearSelection</code>.
|
||||
*
|
||||
* @param path new path to select
|
||||
*/
|
||||
void setSelectionPath(TreePath path);
|
||||
|
||||
/**
|
||||
* Sets the selection to path. If this represents a change, then
|
||||
* the TreeSelectionListeners are notified. If <code>paths</code> is
|
||||
* null, this has the same effect as invoking <code>clearSelection</code>.
|
||||
*
|
||||
* @param paths new selection
|
||||
*/
|
||||
void setSelectionPaths(TreePath[] paths);
|
||||
|
||||
/**
|
||||
* Adds path to the current selection. If path is not currently
|
||||
* in the selection the TreeSelectionListeners are notified. This has
|
||||
* no effect if <code>path</code> is null.
|
||||
*
|
||||
* @param path the new path to add to the current selection
|
||||
*/
|
||||
void addSelectionPath(TreePath path);
|
||||
|
||||
/**
|
||||
* Adds paths to the current selection. If any of the paths in
|
||||
* paths are not currently in the selection the TreeSelectionListeners
|
||||
* are notified. This has
|
||||
* no effect if <code>paths</code> is null.
|
||||
*
|
||||
* @param paths the new paths to add to the current selection
|
||||
*/
|
||||
void addSelectionPaths(TreePath[] paths);
|
||||
|
||||
/**
|
||||
* Removes path from the selection. If path is in the selection
|
||||
* The TreeSelectionListeners are notified. This has no effect if
|
||||
* <code>path</code> is null.
|
||||
*
|
||||
* @param path the path to remove from the selection
|
||||
*/
|
||||
void removeSelectionPath(TreePath path);
|
||||
|
||||
/**
|
||||
* Removes paths from the selection. If any of the paths in
|
||||
* <code>paths</code>
|
||||
* are in the selection, the TreeSelectionListeners are notified.
|
||||
* This method has no effect if <code>paths</code> is null.
|
||||
*
|
||||
* @param paths the path to remove from the selection
|
||||
*/
|
||||
void removeSelectionPaths(TreePath[] paths);
|
||||
|
||||
/**
|
||||
* Returns the first path in the selection. How first is defined is
|
||||
* up to implementors, and may not necessarily be the TreePath with
|
||||
* the smallest integer value as determined from the
|
||||
* <code>RowMapper</code>.
|
||||
*
|
||||
* @return the first path in the selection
|
||||
*/
|
||||
TreePath getSelectionPath();
|
||||
|
||||
/**
|
||||
* Returns the paths in the selection. This will return null (or an
|
||||
* empty array) if nothing is currently selected.
|
||||
*
|
||||
* @return the paths in the selection
|
||||
*/
|
||||
TreePath[] getSelectionPaths();
|
||||
|
||||
/**
|
||||
* Returns the number of paths that are selected.
|
||||
*
|
||||
* @return the number of paths that are selected
|
||||
*/
|
||||
int getSelectionCount();
|
||||
|
||||
/**
|
||||
* Returns true if the path, <code>path</code>, is in the current
|
||||
* selection.
|
||||
*
|
||||
* @param path the path to be loked for
|
||||
* @return whether the {@code path} is in the current selection
|
||||
*/
|
||||
boolean isPathSelected(TreePath path);
|
||||
|
||||
/**
|
||||
* Returns true if the selection is currently empty.
|
||||
*
|
||||
* @return whether the selection is currently empty
|
||||
*/
|
||||
boolean isSelectionEmpty();
|
||||
|
||||
/**
|
||||
* Empties the current selection. If this represents a change in the
|
||||
* current selection, the selection listeners are notified.
|
||||
*/
|
||||
void clearSelection();
|
||||
|
||||
/**
|
||||
* Sets the RowMapper instance. This instance is used to determine
|
||||
* the row for a particular TreePath.
|
||||
*
|
||||
* @param newMapper RowMapper to be set
|
||||
*/
|
||||
void setRowMapper(RowMapper newMapper);
|
||||
|
||||
/**
|
||||
* Returns the RowMapper instance that is able to map a TreePath to a
|
||||
* row.
|
||||
*
|
||||
* @return the RowMapper instance that is able to map a TreePath
|
||||
* to a row
|
||||
*/
|
||||
RowMapper getRowMapper();
|
||||
|
||||
/**
|
||||
* Returns all of the currently selected rows. This will return
|
||||
* null (or an empty array) if there are no selected TreePaths or
|
||||
* a RowMapper has not been set.
|
||||
*
|
||||
* @return all of the currently selected rows
|
||||
*/
|
||||
int[] getSelectionRows();
|
||||
|
||||
/**
|
||||
* Returns the smallest value obtained from the RowMapper for the
|
||||
* current set of selected TreePaths. If nothing is selected,
|
||||
* or there is no RowMapper, this will return -1.
|
||||
*
|
||||
* @return the smallest value obtained from the RowMapper
|
||||
* for the current set of selected TreePaths
|
||||
*/
|
||||
int getMinSelectionRow();
|
||||
|
||||
/**
|
||||
* Returns the largest value obtained from the RowMapper for the
|
||||
* current set of selected TreePaths. If nothing is selected,
|
||||
* or there is no RowMapper, this will return -1.
|
||||
*
|
||||
* @return the largest value obtained from the RowMapper
|
||||
* for the current set of selected TreePaths
|
||||
*/
|
||||
int getMaxSelectionRow();
|
||||
|
||||
/**
|
||||
* Returns true if the row identified by <code>row</code> is selected.
|
||||
*
|
||||
* @param row row to check
|
||||
* @return whether the row is selected
|
||||
*/
|
||||
boolean isRowSelected(int row);
|
||||
|
||||
/**
|
||||
* Updates this object's mapping from TreePaths to rows. This should
|
||||
* be invoked when the mapping from TreePaths to integers has changed
|
||||
* (for example, a node has been expanded).
|
||||
* <p>
|
||||
* You do not normally have to call this; JTree and its associated
|
||||
* listeners will invoke this for you. If you are implementing your own
|
||||
* view class, then you will have to invoke this.
|
||||
*/
|
||||
void resetRowSelection();
|
||||
|
||||
/**
|
||||
* Returns the lead selection index. That is the last index that was
|
||||
* added.
|
||||
*
|
||||
* @return the lead selection index
|
||||
*/
|
||||
int getLeadSelectionRow();
|
||||
|
||||
/**
|
||||
* Returns the last path that was added. This may differ from the
|
||||
* leadSelectionPath property maintained by the JTree.
|
||||
*
|
||||
* @return the last path that was added
|
||||
*/
|
||||
TreePath getLeadSelectionPath();
|
||||
|
||||
/**
|
||||
* Adds a PropertyChangeListener to the listener list.
|
||||
* The listener is registered for all properties.
|
||||
* <p>
|
||||
* A PropertyChangeEvent will get fired when the selection mode
|
||||
* changes.
|
||||
*
|
||||
* @param listener the PropertyChangeListener to be added
|
||||
*/
|
||||
void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Removes a PropertyChangeListener from the listener list.
|
||||
* This removes a PropertyChangeListener that was registered
|
||||
* for all properties.
|
||||
*
|
||||
* @param listener the PropertyChangeListener to be removed
|
||||
*/
|
||||
void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Adds x to the list of listeners that are notified each time the
|
||||
* set of selected TreePaths changes.
|
||||
*
|
||||
* @param x the new listener to be added
|
||||
*/
|
||||
void addTreeSelectionListener(TreeSelectionListener x);
|
||||
|
||||
/**
|
||||
* Removes x from the list of listeners that are notified each time
|
||||
* the set of selected TreePaths changes.
|
||||
*
|
||||
* @param x the listener to remove
|
||||
*/
|
||||
void removeTreeSelectionListener(TreeSelectionListener x);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes and interfaces for dealing with {@code javax.swing.JTree}.
|
||||
* You use these classes and interfaces if you want control over how trees are
|
||||
* constructed, updated, and rendered, as well as how data associated with the
|
||||
* tree nodes are viewed and managed.
|
||||
* <p>
|
||||
* <strong>Note:</strong>
|
||||
* Most of the Swing API is <em>not</em> thread safe. For details, see
|
||||
* <a
|
||||
* href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html"
|
||||
* target="_top">Concurrency in Swing</a>,
|
||||
* a section in
|
||||
* <em><a href="http://docs.oracle.com/javase/tutorial/"
|
||||
* target="_top">The Java Tutorial</a></em>.
|
||||
*
|
||||
* <h2>Related Documentation</h2>
|
||||
* For overviews, tutorials, examples, guides, and tool documentation,
|
||||
* please see:
|
||||
* <ul>
|
||||
* <li><a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html"
|
||||
* target="_top">How to Use Trees</a>,
|
||||
* a section in <em>The Java Tutorial</em></li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.2
|
||||
* @serial exclude
|
||||
*/
|
||||
package javax.swing.tree;
|
Loading…
Add table
Add a link
Reference in a new issue