📄 jxtree.java
字号:
/* * $Id: JXTree.java,v 1.15 2005/10/12 11:26:57 kleopatra Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */package org.jdesktop.swingx;import java.awt.Component;import java.awt.Cursor;import java.awt.Point;import java.awt.Rectangle;import java.awt.event.ActionEvent;import java.awt.event.MouseEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.lang.reflect.Method;import java.util.Hashtable;import java.util.Vector;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.swing.AbstractButton;import javax.swing.Action;import javax.swing.ActionMap;import javax.swing.Icon;import javax.swing.JComponent;import javax.swing.JTree;import javax.swing.KeyStroke;import javax.swing.ListCellRenderer;import javax.swing.event.ChangeEvent;import javax.swing.event.ChangeListener;import javax.swing.plaf.basic.BasicTreeUI;import javax.swing.tree.DefaultTreeCellRenderer;import javax.swing.tree.TreeCellRenderer;import javax.swing.tree.TreeModel;import javax.swing.tree.TreeNode;import javax.swing.tree.TreePath;import org.jdesktop.swingx.AbstractSearchable.SearchResult;import org.jdesktop.swingx.JXList.ListSearchable;import org.jdesktop.swingx.decorator.ComponentAdapter;import org.jdesktop.swingx.decorator.FilterPipeline;import org.jdesktop.swingx.decorator.HighlighterPipeline;/** * JXTree. * * PENDING: support filtering/sorting. * * @author Ramesh Gupta * @author Jeanette Winzenburg */public class JXTree extends JTree { private Method conversionMethod = null; private final static Class[] methodSignature = new Class[] {Object.class}; private final static Object[] methodArgs = new Object[] {null}; protected FilterPipeline filters; protected HighlighterPipeline highlighters; private ChangeListener highlighterChangeListener; private DelegatingRenderer delegatingRenderer; /** * Mouse/Motion/Listener keeping track of mouse moved in * cell coordinates. */ private RolloverProducer rolloverProducer; /** * RolloverController: listens to cell over events and * repaints entered/exited rows. */ private LinkController linkController; private boolean overwriteIcons; private Searchable searchable; /** * Constructs a <code>JXTree</code> with a sample model. The default model * used by this tree defines a leaf node as any node without children. */ public JXTree() { initActions(); } /** * Constructs a <code>JXTree</code> with each element of the specified array * as the child of a new root node which is not displayed. By default, this * tree defines a leaf node as any node without children. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param value an array of objects that are children of the root. */ public JXTree(Object[] value) { super(value); initActions(); } /** * Constructs a <code>JXTree</code> with each element of the specified * Vector as the child of a new root node which is not displayed. * By default, this tree defines a leaf node as any node without children. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param value an Vector of objects that are children of the root. */ public JXTree(Vector value) { super(value); initActions(); } /** * Constructs a <code>JXTree</code> created from a Hashtable which does not * display with root. Each value-half of the key/value pairs in the HashTable * becomes a child of the new root node. By default, the tree defines a leaf * node as any node without children. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param value a Hashtable containing objects that are children of the root. */ public JXTree(Hashtable value) { super(value); initActions(); } /** * Constructs a <code>JXTree</code> with the specified TreeNode as its root, * which displays the root node. By default, the tree defines a leaf node as * any node without children. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param root root node of this tree */ public JXTree(TreeNode root) { super(root, false); } /** * Constructs a <code>JXTree</code> with the specified TreeNode as its root, * which displays the root node and which decides whether a node is a leaf * node in the specified manner. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param root root node of this tree * @param asksAllowsChildren if true, only nodes that do not allow children * are leaf nodes; otherwise, any node without children is a leaf node; * @see javax.swing.tree.DefaultTreeModel#asksAllowsChildren */ public JXTree(TreeNode root, boolean asksAllowsChildren) { super(root, asksAllowsChildren); initActions(); } /** * Constructs an instance of <code>JXTree</code> which displays the root * node -- the tree is created using the specified data model. * * This version of the constructor simply invokes the super class version * with the same arguments. * * @param newModel * the <code>TreeModel</code> to use as the data model */ public JXTree(TreeModel newModel) { super(newModel); initActions(); // To support delegation of convertValueToText() to the model... conversionMethod = getValueConversionMethod(newModel); } public void setModel(TreeModel newModel) { super.setModel(newModel); // To support delegation of convertValueToText() to the model... conversionMethod = getValueConversionMethod(newModel); } private Method getValueConversionMethod(TreeModel model) { try { return model == null ? null : model.getClass().getMethod( "convertValueToText", methodSignature); } catch (NoSuchMethodException ex) { // not an error } return null; } public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { // Delegate to model, if possible. Otherwise fall back to superclass... if (value != null) { if (conversionMethod == null) { return value.toString(); } else { try { methodArgs[0] = value; return (String) conversionMethod.invoke(getModel(), methodArgs); } catch (Exception ex) { // fall through } } } return ""; } private void initActions() { // Register the actions that this class can handle. ActionMap map = getActionMap(); map.put("expand-all", new Actions("expand-all")); map.put("collapse-all", new Actions("collapse-all")); map.put("find", createFindAction()); // JW: this should be handled by the LF! KeyStroke findStroke = KeyStroke.getKeyStroke("control F"); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(findStroke, "find"); } /** * A small class which dispatches actions. * TODO: Is there a way that we can make this static? */ private class Actions extends UIAction { Actions(String name) { super(name); } public void actionPerformed(ActionEvent evt) { if ("expand-all".equals(getName())) { expandAll(); } else if ("collapse-all".equals(getName())) { collapseAll(); } } }//-------------------- search support private Action createFindAction() { Action findAction = new UIAction("find") { public void actionPerformed(ActionEvent e) { doFind(); } }; return findAction; } protected void doFind() { SearchFactory.getInstance().showFindInput(this, getSearchable()); } /** * * @returns a not-null Searchable for this editor. */ public Searchable getSearchable() { if (searchable == null) { searchable = new TreeSearchable(); } return searchable; } /** * sets the Searchable for this editor. If null, a default * searchable will be used. * * @param searchable */ public void setSearchable(Searchable searchable) { this.searchable = searchable; } /** * A searchable targetting the visible rows of a JXTree. * * PENDING: value to string conversion should behave as nextMatch (?) which * uses the convertValueToString(). * */ public class TreeSearchable extends AbstractSearchable { @Override protected void findMatchAndUpdateState(Pattern pattern, int startRow, boolean backwards) { SearchResult searchResult = null; if (backwards) { for (int index = startRow; index >= 0 && searchResult == null; index--) { searchResult = findMatchAt(pattern, index); } } else { for (int index = startRow; index < getSize() && searchResult == null; index++) { searchResult = findMatchAt(pattern, index); } } updateState(searchResult); } @Override protected SearchResult findExtendedMatch(Pattern pattern, int row) { return findMatchAt(pattern, row); } /** * Matches the cell content at row/col against the given Pattern. * Returns an appropriate SearchResult if matching or null if no * matching * * @param pattern * @param row * a valid row index in view coordinates * @param column * a valid column index in view coordinates * @return */ protected SearchResult findMatchAt(Pattern pattern, int row) { TreePath path = getPathForRow(row); Object value = null; if (path != null) { value = path.getLastPathComponent(); } if (value != null) { Matcher matcher = pattern.matcher(value.toString()); if (matcher.find()) { return createSearchResult(matcher, row, -1); } } return null; } @Override protected int getSize() { return getRowCount(); } @Override protected void moveMatchMarker() { int row = lastSearchResult.foundRow; setSelectionRow(row); if (row >= 0) { scrollRowToVisible(row); } } } /** * Collapses all nodes in the tree table. */ public void collapseAll() { for (int i = getRowCount() - 1; i >= 0 ; i--) { collapseRow(i); } } /** * Expands all nodes in the tree table. */ public void expandAll() { for (int i = 0; i < getRowCount(); i++) { expandRow(i); } } public HighlighterPipeline getHighlighters() { return highlighters; } /** Assigns a HighlighterPipeline to the table. */ public void setHighlighters(HighlighterPipeline pipeline) { HighlighterPipeline old = getHighlighters(); if (old != null) { old.removeChangeListener(getHighlighterChangeListener()); } highlighters = pipeline; if (highlighters != null) { highlighters.addChangeListener(getHighlighterChangeListener()); } firePropertyChange("highlighters", old, getHighlighters()); } private ChangeListener getHighlighterChangeListener() { if (highlighterChangeListener == null) { highlighterChangeListener = new ChangeListener() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -