8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -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&trade;
* 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 &lt;= 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

View file

@ -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&trade;
* 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 &gt; 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 &lt;= 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);
}
}
}

View file

@ -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&trade;
* 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) {}
}

View file

@ -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&trade;
* 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> &gt;= 0 &amp;&amp;
* <i>index</i> &lt; 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

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
* &amp;&amp; dropLocation.getChildIndex() == -1
* &amp;&amp; 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);
}

View 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 &gt;= 0 &amp;&amp;
* index &lt; 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);
}

View 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();
}

View 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&trade;
* 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();
}
}

View file

@ -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

View file

@ -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;