0N/A/*
2362N/A * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.tree;
0N/A
0N/Aimport javax.swing.event.TreeModelEvent;
0N/Aimport java.awt.Dimension;
0N/Aimport java.awt.Rectangle;
0N/Aimport java.util.Enumeration;
0N/A
0N/A/**
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Scott Violet
0N/A */
0N/A
0N/Apublic abstract class AbstractLayoutCache implements RowMapper {
0N/A /** Object responsible for getting the size of a node. */
0N/A protected NodeDimensions nodeDimensions;
0N/A
0N/A /** Model providing information. */
0N/A protected TreeModel treeModel;
0N/A
0N/A /** Selection model. */
0N/A protected TreeSelectionModel treeSelectionModel;
0N/A
0N/A /**
0N/A * True if the root node is displayed, false if its children are
0N/A * the highest visible nodes.
0N/A */
0N/A protected boolean rootVisible;
0N/A
0N/A /**
0N/A * Height to use for each row. If this is <= 0 the renderer will be
0N/A * used to determine the height for each row.
0N/A */
0N/A protected int rowHeight;
0N/A
0N/A
0N/A /**
0N/A * Sets the renderer that is responsible for drawing nodes in the tree
0N/A * and which is threfore responsible for calculating the dimensions of
0N/A * individual nodes.
0N/A *
0N/A * @param nd a <code>NodeDimensions</code> object
0N/A */
0N/A public void setNodeDimensions(NodeDimensions nd) {
0N/A this.nodeDimensions = nd;
0N/A }
0N/A
0N/A /**
0N/A * Returns the object that renders nodes in the tree, and which is
0N/A * responsible for calculating the dimensions of individual nodes.
0N/A *
0N/A * @return the <code>NodeDimensions</code> object
0N/A */
0N/A public NodeDimensions getNodeDimensions() {
0N/A return nodeDimensions;
0N/A }
0N/A
0N/A /**
0N/A * Sets the <code>TreeModel</code> that will provide the data.
0N/A *
0N/A * @param newModel the <code>TreeModel</code> that is to
0N/A * provide the data
0N/A */
0N/A public void setModel(TreeModel newModel) {
0N/A treeModel = newModel;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>TreeModel</code> that is providing the data.
0N/A *
0N/A * @return the <code>TreeModel</code> that is providing the data
0N/A */
0N/A public TreeModel getModel() {
0N/A return treeModel;
0N/A }
0N/A
0N/A /**
0N/A * Determines whether or not the root node from
0N/A * the <code>TreeModel</code> is visible.
0N/A *
0N/A * @param rootVisible true if the root node of the tree is to be displayed
0N/A * @see #rootVisible
0N/A * @beaninfo
0N/A * bound: true
0N/A * description: Whether or not the root node
0N/A * from the TreeModel is visible.
0N/A */
0N/A public void setRootVisible(boolean rootVisible) {
0N/A this.rootVisible = rootVisible;
0N/A }
0N/A
0N/A /**
0N/A * Returns true if the root node of the tree is displayed.
0N/A *
0N/A * @return true if the root node of the tree is displayed
0N/A * @see #rootVisible
0N/A */
0N/A public boolean isRootVisible() {
0N/A return rootVisible;
0N/A }
0N/A
0N/A /**
0N/A * Sets the height of each cell. If the specified value
0N/A * is less than or equal to zero the current cell renderer is
0N/A * queried for each row's height.
0N/A *
0N/A * @param rowHeight the height of each cell, in pixels
0N/A * @beaninfo
0N/A * bound: true
0N/A * description: The height of each cell.
0N/A */
0N/A public void setRowHeight(int rowHeight) {
0N/A this.rowHeight = rowHeight;
0N/A }
0N/A
0N/A /**
0N/A * Returns the height of each row. If the returned value is less than
0N/A * or equal to 0 the height for each row is determined by the
0N/A * renderer.
0N/A */
0N/A public int getRowHeight() {
0N/A return rowHeight;
0N/A }
0N/A
0N/A /**
0N/A * Sets the <code>TreeSelectionModel</code> used to manage the
0N/A * selection to new LSM.
0N/A *
0N/A * @param newLSM the new <code>TreeSelectionModel</code>
0N/A */
0N/A public void setSelectionModel(TreeSelectionModel newLSM) {
0N/A if(treeSelectionModel != null)
0N/A treeSelectionModel.setRowMapper(null);
0N/A treeSelectionModel = newLSM;
0N/A if(treeSelectionModel != null)
0N/A treeSelectionModel.setRowMapper(this);
0N/A }
0N/A
0N/A /**
0N/A * Returns the model used to maintain the selection.
0N/A *
0N/A * @return the <code>treeSelectionModel</code>
0N/A */
0N/A public TreeSelectionModel getSelectionModel() {
0N/A return treeSelectionModel;
0N/A }
0N/A
0N/A /**
0N/A * Returns the preferred height.
0N/A *
0N/A * @return the preferred height
0N/A */
0N/A public int getPreferredHeight() {
0N/A // Get the height
0N/A int rowCount = getRowCount();
0N/A
0N/A if(rowCount > 0) {
0N/A Rectangle bounds = getBounds(getPathForRow(rowCount - 1),
0N/A null);
0N/A
0N/A if(bounds != null)
0N/A return bounds.y + bounds.height;
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A /**
0N/A * Returns the preferred width for the passed in region.
0N/A * The region is defined by the path closest to
0N/A * <code>(bounds.x, bounds.y)</code> and
0N/A * ends at <code>bounds.height + bounds.y</code>.
0N/A * If <code>bounds</code> is <code>null</code>,
0N/A * the preferred width for all the nodes
0N/A * will be returned (and this may be a VERY expensive
0N/A * computation).
0N/A *
0N/A * @param bounds the region being queried
0N/A * @return the preferred width for the passed in region
0N/A */
0N/A public int getPreferredWidth(Rectangle bounds) {
0N/A int rowCount = getRowCount();
0N/A
0N/A if(rowCount > 0) {
0N/A // Get the width
0N/A TreePath firstPath;
0N/A int endY;
0N/A
0N/A if(bounds == null) {
0N/A firstPath = getPathForRow(0);
0N/A endY = Integer.MAX_VALUE;
0N/A }
0N/A else {
0N/A firstPath = getPathClosestTo(bounds.x, bounds.y);
0N/A endY = bounds.height + bounds.y;
0N/A }
0N/A
0N/A Enumeration paths = getVisiblePathsFrom(firstPath);
0N/A
0N/A if(paths != null && paths.hasMoreElements()) {
0N/A Rectangle pBounds = getBounds((TreePath)paths.nextElement(),
0N/A null);
0N/A int width;
0N/A
0N/A if(pBounds != null) {
0N/A width = pBounds.x + pBounds.width;
0N/A if (pBounds.y >= endY) {
0N/A return width;
0N/A }
0N/A }
0N/A else
0N/A width = 0;
0N/A while (pBounds != null && paths.hasMoreElements()) {
0N/A pBounds = getBounds((TreePath)paths.nextElement(),
0N/A pBounds);
0N/A if (pBounds != null && pBounds.y < endY) {
0N/A width = Math.max(width, pBounds.x + pBounds.width);
0N/A }
0N/A else {
0N/A pBounds = null;
0N/A }
0N/A }
0N/A return width;
0N/A }
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A //
0N/A // Abstract methods that must be implemented to be concrete.
0N/A //
0N/A
0N/A /**
0N/A * Returns true if the value identified by row is currently expanded.
0N/A */
0N/A public abstract boolean isExpanded(TreePath path);
0N/A
0N/A /**
0N/A * Returns a rectangle giving the bounds needed to draw path.
0N/A *
0N/A * @param path a <code>TreePath</code> specifying a node
0N/A * @param placeIn a <code>Rectangle</code> object giving the
0N/A * available space
0N/A * @return a <code>Rectangle</code> object specifying the space to be used
0N/A */
0N/A public abstract Rectangle getBounds(TreePath path, Rectangle placeIn);
0N/A
0N/A /**
0N/A * Returns the path for passed in row. If row is not visible
0N/A * <code>null</code> is returned.
0N/A *
0N/A * @param row the row being queried
0N/A * @return the <code>TreePath</code> for the given row
0N/A */
0N/A public abstract TreePath getPathForRow(int row);
0N/A
0N/A /**
0N/A * Returns the row that the last item identified in path is visible
0N/A * at. Will return -1 if any of the elements in path are not
0N/A * currently visible.
0N/A *
0N/A * @param path the <code>TreePath</code> being queried
0N/A * @return the row where the last item in path is visible or -1
0N/A * if any elements in path aren't currently visible
0N/A */
0N/A public abstract int getRowForPath(TreePath path);
0N/A
0N/A /**
0N/A * Returns the path to the node that is closest to x,y. If
0N/A * there is nothing currently visible this will return <code>null</code>,
0N/A * otherwise it'll always return a valid path.
0N/A * If you need to test if the
0N/A * returned object is exactly at x, y you should get the bounds for
0N/A * the returned path and test x, y against that.
0N/A *
0N/A * @param x the horizontal component of the desired location
0N/A * @param y the vertical component of the desired location
0N/A * @return the <code>TreePath</code> closest to the specified point
0N/A */
0N/A public abstract TreePath getPathClosestTo(int x, int y);
0N/A
0N/A /**
0N/A * Returns an <code>Enumerator</code> that increments over the visible
0N/A * paths starting at the passed in location. The ordering of the
0N/A * enumeration is based on how the paths are displayed.
0N/A * The first element of the returned enumeration will be path,
0N/A * unless it isn't visible,
0N/A * in which case <code>null</code> will be returned.
0N/A *
0N/A * @param path the starting location for the enumeration
0N/A * @return the <code>Enumerator</code> starting at the desired location
0N/A */
0N/A public abstract Enumeration<TreePath> getVisiblePathsFrom(TreePath path);
0N/A
0N/A /**
0N/A * Returns the number of visible children for row.
0N/A *
0N/A * @param path the path being queried
0N/A * @return the number of visible children for the specified path
0N/A */
0N/A public abstract int getVisibleChildCount(TreePath path);
0N/A
0N/A /**
0N/A * Marks the path <code>path</code> expanded state to
0N/A * <code>isExpanded</code>.
0N/A *
0N/A * @param path the path being expanded or collapsed
0N/A * @param isExpanded true if the path should be expanded, false otherwise
0N/A */
0N/A public abstract void setExpandedState(TreePath path, boolean isExpanded);
0N/A
0N/A /**
0N/A * Returns true if the path is expanded, and visible.
0N/A *
0N/A * @param path the path being queried
0N/A * @return true if the path is expanded and visible, false otherwise
0N/A */
0N/A public abstract boolean getExpandedState(TreePath path);
0N/A
0N/A /**
0N/A * Number of rows being displayed.
0N/A *
0N/A * @return the number of rows being displayed
0N/A */
0N/A public abstract int getRowCount();
0N/A
0N/A /**
0N/A * Informs the <code>TreeState</code> that it needs to recalculate
0N/A * all the sizes it is referencing.
0N/A */
0N/A public abstract void invalidateSizes();
0N/A
0N/A /**
0N/A * Instructs the <code>LayoutCache</code> that the bounds for
0N/A * <code>path</code> are invalid, and need to be updated.
0N/A *
0N/A * @param path the path being updated
0N/A */
0N/A public abstract void invalidatePathBounds(TreePath path);
0N/A
0N/A //
0N/A // TreeModelListener methods
0N/A // AbstractTreeState does not directly become a TreeModelListener on
0N/A // the model, it is up to some other object to forward these methods.
0N/A //
0N/A
0N/A /**
0N/A * <p>
0N/A * Invoked after a node (or a set of siblings) has changed in some
0N/A * way. The node(s) have not changed locations in the tree or
0N/A * altered their children arrays, but other attributes have
0N/A * changed and may affect presentation. Example: the name of a
0N/A * file has changed, but it is in the same location in the file
0N/A * system.</p>
0N/A *
0N/A * <p>e.path() returns the path the parent of the changed node(s).</p>
0N/A *
0N/A * <p>e.childIndices() returns the index(es) of the changed node(s).</p>
0N/A *
0N/A * @param e the <code>TreeModelEvent</code>
0N/A */
0N/A public abstract void treeNodesChanged(TreeModelEvent e);
0N/A
0N/A /**
0N/A * <p>Invoked after nodes have been inserted into the tree.</p>
0N/A *
0N/A * <p>e.path() returns the parent of the new nodes</p>
0N/A * <p>e.childIndices() returns the indices of the new nodes in
0N/A * ascending order.</p>
0N/A *
0N/A * @param e the <code>TreeModelEvent</code>
0N/A */
0N/A public abstract void treeNodesInserted(TreeModelEvent e);
0N/A
0N/A /**
0N/A * <p>Invoked after nodes have been removed from the tree. Note that
0N/A * if a subtree is removed from the tree, this method may only be
0N/A * invoked once for the root of the removed subtree, not once for
0N/A * each individual set of siblings removed.</p>
0N/A *
0N/A * <p>e.path() returns the former parent of the deleted nodes.</p>
0N/A *
0N/A * <p>e.childIndices() returns the indices the nodes had before they were deleted in ascending order.</p>
0N/A *
0N/A * @param e the <code>TreeModelEvent</code>
0N/A */
0N/A public abstract void treeNodesRemoved(TreeModelEvent e);
0N/A
0N/A /**
0N/A * <p>Invoked after the tree has drastically changed structure from a
0N/A * given node down. If the path returned by <code>e.getPath()</code>
0N/A * is of length one and the first element does not identify the
0N/A * current root node the first element should become the new root
0N/A * of the tree.</p>
0N/A *
0N/A * <p>e.path() holds the path to the node.</p>
0N/A * <p>e.childIndices() returns null.</p>
0N/A *
0N/A * @param e the <code>TreeModelEvent</code>
0N/A */
0N/A public abstract void treeStructureChanged(TreeModelEvent e);
0N/A
0N/A //
0N/A // RowMapper
0N/A //
0N/A
0N/A /**
0N/A * Returns the rows that the <code>TreePath</code> instances in
0N/A * <code>path</code> are being displayed at.
0N/A * This method should return an array of the same length as that passed
0N/A * in, and if one of the <code>TreePaths</code>
0N/A * in <code>path</code> is not valid its entry in the array should
0N/A * be set to -1.
0N/A *
0N/A * @param paths the array of <code>TreePath</code>s being queried
0N/A * @return an array of the same length that is passed in containing
0N/A * the rows that each corresponding where each
0N/A * <code>TreePath</code> is displayed; if <code>paths</code>
0N/A * is <code>null</code>, <code>null</code> is returned
0N/A */
0N/A public int[] getRowsForPaths(TreePath[] paths) {
0N/A if(paths == null)
0N/A return null;
0N/A
0N/A int numPaths = paths.length;
0N/A int[] rows = new int[numPaths];
0N/A
0N/A for(int counter = 0; counter < numPaths; counter++)
0N/A rows[counter] = getRowForPath(paths[counter]);
0N/A return rows;
0N/A }
0N/A
0N/A //
0N/A // Local methods that subclassers may wish to use that are primarly
0N/A // convenience methods.
0N/A //
0N/A
0N/A /**
0N/A * Returns, by reference in <code>placeIn</code>,
0N/A * the size needed to represent <code>value</code>.
0N/A * If <code>inPlace</code> is <code>null</code>, a newly created
0N/A * <code>Rectangle</code> should be returned, otherwise the value
0N/A * should be placed in <code>inPlace</code> and returned. This will
0N/A * return <code>null</code> if there is no renderer.
0N/A *
0N/A * @param value the <code>value</code> to be represented
0N/A * @param row row being queried
0N/A * @param depth the depth of the row
0N/A * @param expanded true if row is expanded, false otherwise
0N/A * @param placeIn a <code>Rectangle</code> containing the size needed
0N/A * to represent <code>value</code>
0N/A * @return a <code>Rectangle</code> containing the node dimensions,
0N/A * or <code>null</code> if node has no dimension
0N/A */
0N/A protected Rectangle getNodeDimensions(Object value, int row, int depth,
0N/A boolean expanded,
0N/A Rectangle placeIn) {
0N/A NodeDimensions nd = getNodeDimensions();
0N/A
0N/A if(nd != null) {
0N/A return nd.getNodeDimensions(value, row, depth, expanded, placeIn);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns true if the height of each row is a fixed size.
0N/A */
0N/A protected boolean isFixedRowHeight() {
0N/A return (rowHeight > 0);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Used by <code>AbstractLayoutCache</code> to determine the size
0N/A * and x origin of a particular node.
0N/A */
0N/A static public abstract class NodeDimensions {
0N/A /**
0N/A * Returns, by reference in bounds, the size and x origin to
0N/A * place value at. The calling method is responsible for determining
0N/A * the Y location. If bounds is <code>null</code>, a newly created
0N/A * <code>Rectangle</code> should be returned,
0N/A * otherwise the value should be placed in bounds and returned.
0N/A *
0N/A * @param value the <code>value</code> to be represented
0N/A * @param row row being queried
0N/A * @param depth the depth of the row
0N/A * @param expanded true if row is expanded, false otherwise
0N/A * @param bounds a <code>Rectangle</code> containing the size needed
0N/A * to represent <code>value</code>
0N/A * @return a <code>Rectangle</code> containing the node dimensions,
0N/A * or <code>null</code> if node has no dimension
0N/A */
0N/A public abstract Rectangle getNodeDimensions(Object value, int row,
0N/A int depth,
0N/A boolean expanded,
0N/A Rectangle bounds);
0N/A }
0N/A}