Home » openjdk-7 » javax » swing » tree » [javadoc | source]

    1   /*
    2    * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.swing.tree;
   27   
   28   import javax.swing.event.TreeModelEvent;
   29   import java.awt.Dimension;
   30   import java.awt.Rectangle;
   31   import java.util.Enumeration;
   32   
   33   /**
   34    * <strong>Warning:</strong>
   35    * Serialized objects of this class will not be compatible with
   36    * future Swing releases. The current serialization support is
   37    * appropriate for short term storage or RMI between applications running
   38    * the same version of Swing.  As of 1.4, support for long term storage
   39    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   40    * has been added to the <code>java.beans</code> package.
   41    * Please see {@link java.beans.XMLEncoder}.
   42    *
   43    * @author Scott Violet
   44    */
   45   
   46   public abstract class AbstractLayoutCache implements RowMapper {
   47       /** Object responsible for getting the size of a node. */
   48       protected NodeDimensions     nodeDimensions;
   49   
   50       /** Model providing information. */
   51       protected TreeModel          treeModel;
   52   
   53       /** Selection model. */
   54       protected TreeSelectionModel treeSelectionModel;
   55   
   56       /**
   57        * True if the root node is displayed, false if its children are
   58        * the highest visible nodes.
   59        */
   60       protected boolean            rootVisible;
   61   
   62       /**
   63         * Height to use for each row.  If this is <= 0 the renderer will be
   64         * used to determine the height for each row.
   65         */
   66       protected int                rowHeight;
   67   
   68   
   69       /**
   70        * Sets the renderer that is responsible for drawing nodes in the tree
   71        * and which is threfore responsible for calculating the dimensions of
   72        * individual nodes.
   73        *
   74        * @param nd a <code>NodeDimensions</code> object
   75        */
   76       public void setNodeDimensions(NodeDimensions nd) {
   77           this.nodeDimensions = nd;
   78       }
   79   
   80       /**
   81        * Returns the object that renders nodes in the tree, and which is
   82        * responsible for calculating the dimensions of individual nodes.
   83        *
   84        * @return the <code>NodeDimensions</code> object
   85        */
   86       public NodeDimensions getNodeDimensions() {
   87           return nodeDimensions;
   88       }
   89   
   90       /**
   91        * Sets the <code>TreeModel</code> that will provide the data.
   92        *
   93        * @param newModel the <code>TreeModel</code> that is to
   94        *          provide the data
   95        */
   96       public void setModel(TreeModel newModel) {
   97           treeModel = newModel;
   98       }
   99   
  100       /**
  101        * Returns the <code>TreeModel</code> that is providing the data.
  102        *
  103        * @return the <code>TreeModel</code> that is providing the data
  104        */
  105       public TreeModel getModel() {
  106           return treeModel;
  107       }
  108   
  109       /**
  110        * Determines whether or not the root node from
  111        * the <code>TreeModel</code> is visible.
  112        *
  113        * @param rootVisible true if the root node of the tree is to be displayed
  114        * @see #rootVisible
  115        * @beaninfo
  116        *        bound: true
  117        *  description: Whether or not the root node
  118        *               from the TreeModel is visible.
  119        */
  120       public void setRootVisible(boolean rootVisible) {
  121           this.rootVisible = rootVisible;
  122       }
  123   
  124       /**
  125        * Returns true if the root node of the tree is displayed.
  126        *
  127        * @return true if the root node of the tree is displayed
  128        * @see #rootVisible
  129        */
  130       public boolean isRootVisible() {
  131           return rootVisible;
  132       }
  133   
  134       /**
  135        * Sets the height of each cell.  If the specified value
  136        * is less than or equal to zero the current cell renderer is
  137        * queried for each row's height.
  138        *
  139        * @param rowHeight the height of each cell, in pixels
  140        * @beaninfo
  141        *        bound: true
  142        *  description: The height of each cell.
  143        */
  144       public void setRowHeight(int rowHeight) {
  145           this.rowHeight = rowHeight;
  146       }
  147   
  148       /**
  149        * Returns the height of each row.  If the returned value is less than
  150        * or equal to 0 the height for each row is determined by the
  151        * renderer.
  152        */
  153       public int getRowHeight() {
  154           return rowHeight;
  155       }
  156   
  157       /**
  158        * Sets the <code>TreeSelectionModel</code> used to manage the
  159        * selection to new LSM.
  160        *
  161        * @param newLSM  the new <code>TreeSelectionModel</code>
  162        */
  163       public void setSelectionModel(TreeSelectionModel newLSM) {
  164           if(treeSelectionModel != null)
  165               treeSelectionModel.setRowMapper(null);
  166           treeSelectionModel = newLSM;
  167           if(treeSelectionModel != null)
  168               treeSelectionModel.setRowMapper(this);
  169       }
  170   
  171       /**
  172        * Returns the model used to maintain the selection.
  173        *
  174        * @return the <code>treeSelectionModel</code>
  175        */
  176       public TreeSelectionModel getSelectionModel() {
  177           return treeSelectionModel;
  178       }
  179   
  180       /**
  181        * Returns the preferred height.
  182        *
  183        * @return the preferred height
  184        */
  185       public int getPreferredHeight() {
  186           // Get the height
  187           int           rowCount = getRowCount();
  188   
  189           if(rowCount > 0) {
  190               Rectangle     bounds = getBounds(getPathForRow(rowCount - 1),
  191                                                null);
  192   
  193               if(bounds != null)
  194                   return bounds.y + bounds.height;
  195           }
  196           return 0;
  197       }
  198   
  199       /**
  200        * Returns the preferred width for the passed in region.
  201        * The region is defined by the path closest to
  202        * <code>(bounds.x, bounds.y)</code> and
  203        * ends at <code>bounds.height + bounds.y</code>.
  204        * If <code>bounds</code> is <code>null</code>,
  205        * the preferred width for all the nodes
  206        * will be returned (and this may be a VERY expensive
  207        * computation).
  208        *
  209        * @param bounds the region being queried
  210        * @return the preferred width for the passed in region
  211        */
  212       public int getPreferredWidth(Rectangle bounds) {
  213           int           rowCount = getRowCount();
  214   
  215           if(rowCount > 0) {
  216               // Get the width
  217               TreePath      firstPath;
  218               int           endY;
  219   
  220               if(bounds == null) {
  221                   firstPath = getPathForRow(0);
  222                   endY = Integer.MAX_VALUE;
  223               }
  224               else {
  225                   firstPath = getPathClosestTo(bounds.x, bounds.y);
  226                   endY = bounds.height + bounds.y;
  227               }
  228   
  229               Enumeration   paths = getVisiblePathsFrom(firstPath);
  230   
  231               if(paths != null && paths.hasMoreElements()) {
  232                   Rectangle   pBounds = getBounds((TreePath)paths.nextElement(),
  233                                                   null);
  234                   int         width;
  235   
  236                   if(pBounds != null) {
  237                       width = pBounds.x + pBounds.width;
  238                       if (pBounds.y >= endY) {
  239                           return width;
  240                       }
  241                   }
  242                   else
  243                       width = 0;
  244                   while (pBounds != null && paths.hasMoreElements()) {
  245                       pBounds = getBounds((TreePath)paths.nextElement(),
  246                                           pBounds);
  247                       if (pBounds != null && pBounds.y < endY) {
  248                           width = Math.max(width, pBounds.x + pBounds.width);
  249                       }
  250                       else {
  251                           pBounds = null;
  252                       }
  253                   }
  254                   return width;
  255               }
  256           }
  257           return 0;
  258       }
  259   
  260       //
  261       // Abstract methods that must be implemented to be concrete.
  262       //
  263   
  264       /**
  265         * Returns true if the value identified by row is currently expanded.
  266         */
  267       public abstract boolean isExpanded(TreePath path);
  268   
  269       /**
  270        * Returns a rectangle giving the bounds needed to draw path.
  271        *
  272        * @param path     a <code>TreePath</code> specifying a node
  273        * @param placeIn  a <code>Rectangle</code> object giving the
  274        *          available space
  275        * @return a <code>Rectangle</code> object specifying the space to be used
  276        */
  277       public abstract Rectangle getBounds(TreePath path, Rectangle placeIn);
  278   
  279       /**
  280         * Returns the path for passed in row.  If row is not visible
  281         * <code>null</code> is returned.
  282         *
  283         * @param row  the row being queried
  284         * @return the <code>TreePath</code> for the given row
  285         */
  286       public abstract TreePath getPathForRow(int row);
  287   
  288       /**
  289         * Returns the row that the last item identified in path is visible
  290         * at.  Will return -1 if any of the elements in path are not
  291         * currently visible.
  292         *
  293         * @param path the <code>TreePath</code> being queried
  294         * @return the row where the last item in path is visible or -1
  295         *         if any elements in path aren't currently visible
  296         */
  297       public abstract int getRowForPath(TreePath path);
  298   
  299       /**
  300         * Returns the path to the node that is closest to x,y.  If
  301         * there is nothing currently visible this will return <code>null</code>,
  302         * otherwise it'll always return a valid path.
  303         * If you need to test if the
  304         * returned object is exactly at x, y you should get the bounds for
  305         * the returned path and test x, y against that.
  306         *
  307         * @param x the horizontal component of the desired location
  308         * @param y the vertical component of the desired location
  309         * @return the <code>TreePath</code> closest to the specified point
  310         */
  311       public abstract TreePath getPathClosestTo(int x, int y);
  312   
  313       /**
  314        * Returns an <code>Enumerator</code> that increments over the visible
  315        * paths starting at the passed in location. The ordering of the
  316        * enumeration is based on how the paths are displayed.
  317        * The first element of the returned enumeration will be path,
  318        * unless it isn't visible,
  319        * in which case <code>null</code> will be returned.
  320        *
  321        * @param path the starting location for the enumeration
  322        * @return the <code>Enumerator</code> starting at the desired location
  323        */
  324       public abstract Enumeration<TreePath> getVisiblePathsFrom(TreePath path);
  325   
  326       /**
  327        * Returns the number of visible children for row.
  328        *
  329        * @param path  the path being queried
  330        * @return the number of visible children for the specified path
  331        */
  332       public abstract int getVisibleChildCount(TreePath path);
  333   
  334       /**
  335        * Marks the path <code>path</code> expanded state to
  336        * <code>isExpanded</code>.
  337        *
  338        * @param path  the path being expanded or collapsed
  339        * @param isExpanded true if the path should be expanded, false otherwise
  340        */
  341       public abstract void setExpandedState(TreePath path, boolean isExpanded);
  342   
  343       /**
  344        * Returns true if the path is expanded, and visible.
  345        *
  346        * @param path  the path being queried
  347        * @return true if the path is expanded and visible, false otherwise
  348        */
  349       public abstract boolean getExpandedState(TreePath path);
  350   
  351       /**
  352        * Number of rows being displayed.
  353        *
  354        * @return the number of rows being displayed
  355        */
  356       public abstract int getRowCount();
  357   
  358       /**
  359        * Informs the <code>TreeState</code> that it needs to recalculate
  360        * all the sizes it is referencing.
  361        */
  362       public abstract void invalidateSizes();
  363   
  364       /**
  365        * Instructs the <code>LayoutCache</code> that the bounds for
  366        * <code>path</code> are invalid, and need to be updated.
  367        *
  368        * @param path the path being updated
  369        */
  370       public abstract void invalidatePathBounds(TreePath path);
  371   
  372       //
  373       // TreeModelListener methods
  374       // AbstractTreeState does not directly become a TreeModelListener on
  375       // the model, it is up to some other object to forward these methods.
  376       //
  377   
  378       /**
  379        * <p>
  380        * Invoked after a node (or a set of siblings) has changed in some
  381        * way. The node(s) have not changed locations in the tree or
  382        * altered their children arrays, but other attributes have
  383        * changed and may affect presentation. Example: the name of a
  384        * file has changed, but it is in the same location in the file
  385        * system.</p>
  386        *
  387        * <p>e.path() returns the path the parent of the changed node(s).</p>
  388        *
  389        * <p>e.childIndices() returns the index(es) of the changed node(s).</p>
  390        *
  391        * @param e  the <code>TreeModelEvent</code>
  392        */
  393       public abstract void treeNodesChanged(TreeModelEvent e);
  394   
  395       /**
  396        * <p>Invoked after nodes have been inserted into the tree.</p>
  397        *
  398        * <p>e.path() returns the parent of the new nodes</p>
  399        * <p>e.childIndices() returns the indices of the new nodes in
  400        * ascending order.</p>
  401        *
  402        * @param e the <code>TreeModelEvent</code>
  403        */
  404       public abstract void treeNodesInserted(TreeModelEvent e);
  405   
  406       /**
  407        * <p>Invoked after nodes have been removed from the tree.  Note that
  408        * if a subtree is removed from the tree, this method may only be
  409        * invoked once for the root of the removed subtree, not once for
  410        * each individual set of siblings removed.</p>
  411        *
  412        * <p>e.path() returns the former parent of the deleted nodes.</p>
  413        *
  414        * <p>e.childIndices() returns the indices the nodes had before they were deleted in ascending order.</p>
  415        *
  416        * @param e the <code>TreeModelEvent</code>
  417        */
  418       public abstract void treeNodesRemoved(TreeModelEvent e);
  419   
  420       /**
  421        * <p>Invoked after the tree has drastically changed structure from a
  422        * given node down.  If the path returned by <code>e.getPath()</code>
  423        * is of length one and the first element does not identify the
  424        * current root node the first element should become the new root
  425        * of the tree.</p>
  426        *
  427        * <p>e.path() holds the path to the node.</p>
  428        * <p>e.childIndices() returns null.</p>
  429        *
  430        * @param e the <code>TreeModelEvent</code>
  431        */
  432       public abstract void treeStructureChanged(TreeModelEvent e);
  433   
  434       //
  435       // RowMapper
  436       //
  437   
  438       /**
  439        * Returns the rows that the <code>TreePath</code> instances in
  440        * <code>path</code> are being displayed at.
  441        * This method should return an array of the same length as that passed
  442        * in, and if one of the <code>TreePaths</code>
  443        * in <code>path</code> is not valid its entry in the array should
  444        * be set to -1.
  445        *
  446        * @param paths the array of <code>TreePath</code>s being queried
  447        * @return an array of the same length that is passed in containing
  448        *          the rows that each corresponding where each
  449        *          <code>TreePath</code> is displayed; if <code>paths</code>
  450        *          is <code>null</code>, <code>null</code> is returned
  451        */
  452       public int[] getRowsForPaths(TreePath[] paths) {
  453           if(paths == null)
  454               return null;
  455   
  456           int               numPaths = paths.length;
  457           int[]             rows = new int[numPaths];
  458   
  459           for(int counter = 0; counter < numPaths; counter++)
  460               rows[counter] = getRowForPath(paths[counter]);
  461           return rows;
  462       }
  463   
  464       //
  465       // Local methods that subclassers may wish to use that are primarly
  466       // convenience methods.
  467       //
  468   
  469       /**
  470        * Returns, by reference in <code>placeIn</code>,
  471        * the size needed to represent <code>value</code>.
  472        * If <code>inPlace</code> is <code>null</code>, a newly created
  473        * <code>Rectangle</code> should be returned, otherwise the value
  474        * should be placed in <code>inPlace</code> and returned. This will
  475        * return <code>null</code> if there is no renderer.
  476        *
  477        * @param value the <code>value</code> to be represented
  478        * @param row  row being queried
  479        * @param depth the depth of the row
  480        * @param expanded true if row is expanded, false otherwise
  481        * @param placeIn  a <code>Rectangle</code> containing the size needed
  482        *          to represent <code>value</code>
  483        * @return a <code>Rectangle</code> containing the node dimensions,
  484        *          or <code>null</code> if node has no dimension
  485        */
  486       protected Rectangle getNodeDimensions(Object value, int row, int depth,
  487                                             boolean expanded,
  488                                             Rectangle placeIn) {
  489           NodeDimensions            nd = getNodeDimensions();
  490   
  491           if(nd != null) {
  492               return nd.getNodeDimensions(value, row, depth, expanded, placeIn);
  493           }
  494           return null;
  495       }
  496   
  497       /**
  498         * Returns true if the height of each row is a fixed size.
  499         */
  500       protected boolean isFixedRowHeight() {
  501           return (rowHeight > 0);
  502       }
  503   
  504   
  505       /**
  506        * Used by <code>AbstractLayoutCache</code> to determine the size
  507        * and x origin of a particular node.
  508        */
  509       static public abstract class NodeDimensions {
  510           /**
  511            * Returns, by reference in bounds, the size and x origin to
  512            * place value at. The calling method is responsible for determining
  513            * the Y location. If bounds is <code>null</code>, a newly created
  514            * <code>Rectangle</code> should be returned,
  515            * otherwise the value should be placed in bounds and returned.
  516            *
  517            * @param value the <code>value</code> to be represented
  518            * @param row row being queried
  519            * @param depth the depth of the row
  520            * @param expanded true if row is expanded, false otherwise
  521            * @param bounds  a <code>Rectangle</code> containing the size needed
  522            *              to represent <code>value</code>
  523            * @return a <code>Rectangle</code> containing the node dimensions,
  524            *              or <code>null</code> if node has no dimension
  525            */
  526           public abstract Rectangle getNodeDimensions(Object value, int row,
  527                                                       int depth,
  528                                                       boolean expanded,
  529                                                       Rectangle bounds);
  530       }
  531   }

Home » openjdk-7 » javax » swing » tree » [javadoc | source]