- /*
 - * @(#)SynthTreeUI.java 1.20 04/01/13
 - *
 - * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 - * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 - */
 - package com.sun.java.swing.plaf.gtk;
 - import javax.swing.*;
 - import javax.swing.event.*;
 - import java.awt.*;
 - import java.awt.event.*;
 - import java.awt.datatransfer.*;
 - import java.awt.dnd.*;
 - import java.beans.*;
 - import java.io.*;
 - import java.util.*;
 - import javax.swing.plaf.ActionMapUIResource;
 - import javax.swing.plaf.ComponentUI;
 - import javax.swing.plaf.UIResource;
 - import javax.swing.plaf.TreeUI;
 - import javax.swing.tree.*;
 - import javax.swing.text.Position;
 - /**
 - * SynthTreeUI provides space for a control icon and the renderer
 - * portion of a node. The leading edge of the renderer is calculated
 - * by <code>Tree.indent</code> * depth - 1 + <code>Tree.controlSize</code>.
 - * The icon is centered at leading renderer edge -
 - * <code>Tree.trailingControlOffset</code>. The horizontal separators,
 - * if drawn, are drawn from the leading edge of the renderer -
 - * <code>Tree.trailingControlOffset</code> to the leading edge of
 - * renderer - <code>Tree.trailingLegBufferOffset</code>.
 - * <p>
 - *
 - * @version 1.20, 01/13/04 (based on BasicTreeUI v 1.155)
 - * @author Scott Violet
 - */
 - class SynthTreeUI extends TreeUI implements PropertyChangeListener, SynthUI,
 - LazyActionMap.Loader {
 - private static final TreeDragGestureRecognizer defaultDragRecognizer
 - = new TreeDragGestureRecognizer();
 - private static DropTargetListener defaultDropTargetListener = null;
 - private static final TransferHandler defaultTransferHandler
 - = new TreeTransferHandler();
 - /**
 - * Icon to use for nodes that are collapsed.
 - */
 - private Icon collapsedIcon;
 - /**
 - * Icon to use when a node is expanded.
 - */
 - private Icon expandedIcon;
 - /**
 - * The Tree!
 - */
 - private JTree tree;
 - /**
 - * Used during drawing to track which nodes have had their separators
 - * drawn.
 - */
 - private Map drawingCache;
 - /**
 - * Offset, from trailing margin, to center of control icon.
 - */
 - private int trailingControlOffset;
 - /**
 - * Total size to allow to expand/collapse icon. This includes the
 - * leading padding.
 - */
 - private int controlSize;
 - /**
 - * Pixels to indent children, this is not necessarily controlSize.
 - */
 - private int indent;
 - /**
 - * Amount of space to leave between node and horizontal separators as
 - * measured from trailing margin.
 - */
 - private int trailingLegBufferOffset;
 - /**
 - * Indicates if the horizontal legs should be drawn.
 - */
 - private boolean drawHorizontalLegs;
 - /**
 - * Indicates if the vertical legs should be drawn.
 - */
 - private boolean drawVerticalLegs;
 - /**
 - * Whether or not the focus border should be drawn around the renderer.
 - */
 - private boolean drawsFocusBorder;
 - /**
 - * The offset the root should be rendered at. This isn't a pixel
 - * value, rather an integer that will be offset by the getIndent.
 - * The value depends upon if the root is visible, and if the root handles
 - * are visible.
 - */
 - private int rootOffset;
 - /**
 - * If true, when TreeSelectionListener.valueChanged is invoked it will
 - * NOT invoke stopCellEditing. This is used when the selection is changed
 - * as a result of editing so that the editing session isn't canceled
 - * immediately.
 - */
 - private boolean stopEditingWhenSelectionChanges;
 - /**
 - * Used to paint the TreeCellRenderer.
 - */
 - private CellRendererPane rendererPane;
 - /**
 - * Preferred size, calculated from the AbstractLayoutCache.
 - */
 - private Dimension preferredSize;
 - /**
 - * Is the preferredSize valid?
 - */
 - protected boolean validCachedPreferredSize;
 - /**
 - * Object responsible for handling sizing and expanded issues.
 - */
 - private AbstractLayoutCache treeState;
 - /**
 - * True if doing optimizations for a largeModel. This is used
 - * to determine the type of AbstractLayoutCache to create.
 - */
 - private boolean largeModel;
 - /**
 - * Reponsible for telling the TreeState the size needed for a node.
 - */
 - private AbstractLayoutCache.NodeDimensions nodeDimensions;
 - /**
 - * Used during editing to hold editing related state.
 - */
 - private EditingState editingState;
 - /**
 - * Indicates the orientation. This is cached as used quite extensively
 - * while painting.
 - */
 - private boolean leftToRight;
 - /**
 - * Row corresponding to the lead path.
 - */
 - private int leadRow;
 - // Cached listeners
 - private MouseListener mouseListener;
 - private FocusListener focusListener;
 - private KeyListener keyListener;
 - /**
 - * Used for large models, listens for moved/resized events and
 - * updates the validCachedPreferredSize bit accordingly.
 - */
 - private ComponentListener componentListener;
 - private CellEditorListener cellEditorListener;
 - private TreeSelectionListener treeSelectionListener;
 - private TreeModelListener treeModelListener;
 - private TreeExpansionListener treeExpansionListener;
 - private SynthStyle style;
 - private SynthStyle cellStyle;
 - public static ComponentUI createUI(JComponent x) {
 - return new SynthTreeUI();
 - }
 - /**
 - * Ensures that the rows identified by beginRow through endRow are
 - * visible.
 - */
 - private static void ensureRowsAreVisible(JTree tree, int beginRow,
 - int endRow) {
 - if (beginRow >= 0 && endRow < tree.getRowCount()) {
 - // PENDING: needs to be updated.
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - SynthContext context = ui.getContext(tree);
 - boolean scrollVert = context.getStyle().getBoolean(context,
 - "Tree.scrollsHorizontallyAndVertically", false);
 - context.dispose();
 - if (beginRow == endRow) {
 - Rectangle scrollBounds = tree.getPathBounds(
 - tree.getPathForRow(beginRow));
 - if (scrollBounds != null) {
 - if (!scrollVert) {
 - scrollBounds.x = tree.getVisibleRect().x;
 - scrollBounds.width = 1;
 - }
 - tree.scrollRectToVisible(scrollBounds);
 - }
 - }
 - else {
 - Rectangle beginRect = tree.getPathBounds(tree.getPathForRow
 - (beginRow));
 - Rectangle visRect = tree.getVisibleRect();
 - Rectangle testRect = beginRect;
 - int beginY = beginRect.y;
 - int maxY = beginY + visRect.height;
 - for (int counter = beginRow + 1; counter <= endRow; counter++){
 - testRect = tree.getPathBounds(tree.getPathForRow(counter));
 - if ((testRect.y + testRect.height) > maxY) {
 - counter = endRow;
 - }
 - }
 - tree.scrollRectToVisible(new Rectangle(visRect.x, beginY, 1,
 - testRect.y + testRect.height-
 - beginY));
 - }
 - }
 - }
 - //
 - // ComponentUI methods
 - //
 - /**
 - * Returns the preferred size needed to properly renderer the tree.
 - */
 - public Dimension getPreferredSize(JComponent c) {
 - if (!validCachedPreferredSize) {
 - updateCachedPreferredSize();
 - }
 - return new Dimension(preferredSize);
 - }
 - /**
 - * Returns the minimum size for this component. Which will be
 - * the min preferred size or 0, 0.
 - */
 - public Dimension getMinimumSize(JComponent c) {
 - return new Dimension(0, 0);
 - }
 - /**
 - * Returns the maximum size for this component, which will be the
 - * preferred size if the instance is currently in a JTree, or 0, 0.
 - */
 - public Dimension getMaximumSize(JComponent c) {
 - return getPreferredSize(tree);
 - }
 - //
 - // TreeUI methods
 - //
 - /**
 - * Returns the Rectangle enclosing the label portion that the
 - * last item in path will be drawn into. Will return null if
 - * any component in path is currently valid.
 - */
 - public Rectangle getPathBounds(JTree tree, TreePath path) {
 - if (tree != null && treeState != null) {
 - Rectangle bounds = treeState.getBounds(path, null);
 - adjustCellBounds(tree, bounds, null);
 - return bounds;
 - }
 - return null;
 - }
 - /**
 - * Returns the path for passed in row. If row is not visible
 - * null is returned.
 - */
 - public TreePath getPathForRow(JTree tree, int row) {
 - return (treeState != null) ? treeState.getPathForRow(row) : null;
 - }
 - /**
 - * 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.
 - */
 - public int getRowForPath(JTree tree, TreePath path) {
 - return (treeState != null) ? treeState.getRowForPath(path) : -1;
 - }
 - /**
 - * Returns the number of rows that are being displayed.
 - */
 - public int getRowCount(JTree tree) {
 - return (treeState != null) ? treeState.getRowCount() : 0;
 - }
 - /**
 - * Returns the path to the node that is closest to x,y. If
 - * there is nothing currently visible this will return null, 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.
 - */
 - public TreePath getClosestPathForLocation(JTree tree, int x, int y) {
 - if (tree != null && treeState != null) {
 - Insets i = tree.getInsets();
 - if (leftToRight) {
 - x -= i.left;
 - }
 - else {
 - x = tree.getWidth() - x - i.right;
 - }
 - return treeState.getPathClosestTo(x, y - i.top);
 - }
 - return null;
 - }
 - /**
 - * Returns true if the tree is being edited. The item that is being
 - * edited can be returned by getEditingPath().
 - */
 - public boolean isEditing(JTree tree) {
 - return (editingState != null);
 - }
 - /**
 - * Stops the current editing session. This has no effect if the
 - * tree isn't being edited. Returns true if the editor allows the
 - * editing session to stop.
 - */
 - public boolean stopEditing(JTree tree) {
 - if (editingState != null && tree.getCellEditor().stopCellEditing()) {
 - completeEditing(false, false, true);
 - return true;
 - }
 - return false;
 - }
 - /**
 - * Cancels the current editing session.
 - */
 - public void cancelEditing(JTree tree) {
 - if (editingState != null) {
 - completeEditing(false, true, false);
 - }
 - }
 - /**
 - * Selects the last item in path and tries to edit it. Editing will
 - * fail if the CellEditor won't allow it for the selected item.
 - */
 - public void startEditingAtPath(JTree tree, TreePath path) {
 - tree.scrollPathToVisible(path);
 - if (path != null && tree.isVisible(path)) {
 - startEditing(path, null);
 - }
 - }
 - /**
 - * Returns the path to the element that is being edited.
 - */
 - public TreePath getEditingPath(JTree tree) {
 - return (editingState != null) ? editingState.path : null;
 - }
 - //
 - // Install methods
 - //
 - public SynthTreeUI() {
 - preferredSize = new Dimension();
 - }
 - public void installUI(JComponent c) {
 - if (c == null) {
 - throw new NullPointerException(
 - "null component passed to SynthTreeUI.installUI()");
 - }
 - tree = (JTree)c;
 - drawingCache = new HashMap(7);
 - leftToRight = tree.getComponentOrientation().isLeftToRight();
 - stopEditingWhenSelectionChanges = true;
 - validCachedPreferredSize = false;
 - installDefaults();
 - installKeyboardActions();
 - installComponents();
 - installListeners();
 - }
 - protected void installDefaults() {
 - // Installs the renderer, and potentially the editor
 - updateRenderer();
 - fetchStyle(tree);
 - // This has to be here so that createLayoutCache doesn't get an NPE
 - // when the renderer calls into the NodeDimensions.
 - rendererPane = createCellRendererPane();
 - tree.add(rendererPane);
 - treeState = createLayoutCache();
 - configureLayoutCache();
 - TransferHandler th = tree.getTransferHandler();
 - if (th == null || th instanceof UIResource) {
 - tree.setTransferHandler(defaultTransferHandler);
 - }
 - DropTarget dropTarget = tree.getDropTarget();
 - if (dropTarget instanceof UIResource) {
 - if (defaultDropTargetListener == null) {
 - defaultDropTargetListener = new TreeDropTargetListener();
 - }
 - try {
 - dropTarget.addDropTargetListener(defaultDropTargetListener);
 - } catch (TooManyListenersException tmle) {
 - // should not happen... swing drop target is multicast
 - }
 - }
 - }
 - private void fetchStyle(JTree tree) {
 - SynthContext context = getContext(tree, ENABLED);
 - SynthStyle oldStyle = style;
 - style = SynthLookAndFeel.updateStyle(context, this);
 - if (style != oldStyle) {
 - drawHorizontalLegs = style.getBoolean(
 - context, "Tree.drawHorizontalLegs",true);
 - drawVerticalLegs = style.getBoolean(
 - context, "Tree.drawVerticalLegs", true);
 - tree.setRowHeight(style.getInt(context, "Tree.rowHeight", -1));
 - tree.setScrollsOnExpand(style.getBoolean(
 - context, "Tree.scrollsOnExpand", true));
 - largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0);
 - expandedIcon = style.getIcon(context, "Tree.expandedIcon");
 - collapsedIcon = style.getIcon(context, "Tree.collapsedIcon");
 - trailingLegBufferOffset = style.getInt(
 - context, "Tree.trailingLegBufferOffset", 0);
 - trailingControlOffset = style.getInt(
 - context, "Tree.trailingControlOffset", 0);
 - controlSize = style.getInt(context, "Tree.controlSize", 0);
 - indent = style.getInt(context, "Tree.indent", 0);
 - updateRootOffset();
 - drawsFocusBorder = style.getBoolean(
 - context, "Tree.drawsFocusBorder", true);
 - }
 - context.dispose();
 - context = getContext(tree, Region.TREE_CELL, ENABLED);
 - cellStyle = SynthLookAndFeel.updateStyle(context, this);
 - context.dispose();
 - }
 - protected void installListeners() {
 - tree.addPropertyChangeListener(this);
 - tree.addMouseListener(defaultDragRecognizer);
 - tree.addMouseMotionListener(defaultDragRecognizer);
 - if ((mouseListener = createMouseListener()) != null) {
 - tree.addMouseListener(mouseListener);
 - if (mouseListener instanceof MouseMotionListener) {
 - tree.addMouseMotionListener(
 - (MouseMotionListener)mouseListener);
 - }
 - }
 - if ((focusListener = createFocusListener()) != null) {
 - tree.addFocusListener(focusListener);
 - }
 - if ((keyListener = createKeyListener()) != null) {
 - tree.addKeyListener(keyListener);
 - }
 - if ((treeExpansionListener = createTreeExpansionListener()) != null) {
 - tree.addTreeExpansionListener(treeExpansionListener);
 - }
 - // TreeModel can be null
 - TreeModel model = tree.getModel();
 - if ((treeModelListener = createTreeModelListener()) != null &&
 - model != null) {
 - model.addTreeModelListener(treeModelListener);
 - }
 - TreeSelectionModel treeSelectionModel = tree.getSelectionModel();
 - if ((treeSelectionListener = createTreeSelectionListener()) != null) {
 - treeSelectionModel.addTreeSelectionListener(treeSelectionListener);
 - }
 - TreeCellEditor editor = tree.getCellEditor();
 - if (editor != null) {
 - cellEditorListener = createCellEditorListener();
 - if (cellEditorListener != null) {
 - editor.addCellEditorListener(cellEditorListener);
 - }
 - }
 - }
 - protected void installKeyboardActions() {
 - InputMap km = getInputMap(JComponent.
 - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 - SwingUtilities.replaceUIInputMap(tree, JComponent.
 - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 - km);
 - km = getInputMap(JComponent.WHEN_FOCUSED);
 - SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED, km);
 - LazyActionMap.installLazyActionMap(tree, this);
 - }
 - InputMap getInputMap(int condition) {
 - SynthContext context = getContext(tree, ENABLED);
 - SynthStyle style = context.getStyle();
 - InputMap map = null;
 - if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 - map = (InputMap)style.get(context, "Tree.ancestorInputMap");
 - }
 - else if (condition == JComponent.WHEN_FOCUSED) {
 - map = (InputMap)style.get(context, "Tree.focusInputMap");
 - InputMap rtlKeyMap;
 - if (!leftToRight && ((rtlKeyMap = (InputMap)style.get(context,
 - "Tree.focusInputMap.RightToLeft")) != null)) {
 - rtlKeyMap.setParent(map);
 - map = rtlKeyMap;
 - }
 - }
 - context.dispose();
 - return map;
 - }
 - public void loadActionMap(JComponent c, ActionMap map) {
 - map.put("selectPrevious", new IncrementAction("selectPrevious", -1,
 - false, true));
 - map.put("selectPreviousChangeLead", new IncrementAction
 - ("selectPreviousLead", -1, false, false));
 - map.put("selectPreviousExtendSelection", new IncrementAction
 - ("selectPreviousExtendSelection", -1, true, true));
 - map.put("selectNext", new IncrementAction
 - ("selectNext", 1, false, true));
 - map.put("selectNextChangeLead", new IncrementAction
 - ("selectNextLead", 1, false, false));
 - map.put("selectNextExtendSelection", new IncrementAction
 - ("selectNextExtendSelection", 1, true, true));
 - map.put("selectChild", new TraverseAction
 - ("selectChild", 1, true));
 - map.put("selectChildChangeLead", new TraverseAction
 - ("selectChildLead", 1, false));
 - map.put("selectParent", new TraverseAction
 - ("selectParent", -1, true));
 - map.put("selectParentChangeLead", new TraverseAction
 - ("selectParentLead", -1, false));
 - map.put("scrollUpChangeSelection", new ScrollAndSelectAction
 - ("scrollUpChangeSelection", SwingConstants.NORTH,false, true));
 - map.put("scrollUpChangeLead", new ScrollAndSelectAction
 - ("scrollUpChangeLead", SwingConstants.NORTH, false, false));
 - map.put("scrollUpExtendSelection", new ScrollAndSelectAction
 - ("scrollUpExtendSelection", SwingConstants.NORTH, true, true));
 - map.put("scrollDownChangeSelection", new ScrollAndSelectAction
 - ("scrollDownChangeSelection", SwingConstants.SOUTH, false,
 - true));
 - map.put("scrollDownExtendSelection", new ScrollAndSelectAction
 - ("scrollDownExtendSelection", SwingConstants.SOUTH, true,
 - true));
 - map.put("scrollDownChangeLead", new ScrollAndSelectAction
 - ("scrollDownChangeLead", SwingConstants.SOUTH, false, false));
 - map.put("selectFirst", new HomeAction
 - ("selectFirst", -1, false, true));
 - map.put("selectFirstChangeLead", new HomeAction
 - ("selectFirst", -1, false, false));
 - map.put("selectFirstExtendSelection",new HomeAction
 - ("selectFirstExtendSelection", -1, true, true));
 - map.put("selectLast", new HomeAction
 - ("selectLast", 1, false, true));
 - map.put("selectLastChangeLead", new HomeAction
 - ("selectLast", 1, false, false));
 - map.put("selectLastExtendSelection", new HomeAction
 - ("selectLastExtendSelection", 1, true, true));
 - map.put("toggle", new ToggleAction("toggle"));
 - map.put("cancel", new CancelEditingAction("cancel"));
 - map.put("startEditing", new EditAction("startEditing"));
 - map.put("selectAll", new SelectAllAction("selectAll", true));
 - map.put("clearSelection", new SelectAllAction
 - ("clearSelection", false));
 - map.put("toggleSelectionPreserveAnchor",
 - new AddSelectionAction("toggleSelectionPreserveAnchor",
 - false));
 - map.put("toggleSelection",
 - new AddSelectionAction("toggleSelection", true));
 - map.put("extendSelection", new ExtendSelectionAction
 - ("extendSelection"));
 - map.put("scrollLeft", new ScrollAction
 - ("scrollLeft", SwingConstants.HORIZONTAL, -10));
 - map.put("scrollLeftExtendSelection", new ScrollAndSelectAction
 - ("scrollLeftExtendSelection", SwingConstants.WEST,true, true));
 - map.put("scrollRight", new ScrollAction
 - ("scrollRight", SwingConstants.HORIZONTAL, 10));
 - map.put("scrollRightExtendSelection", new ScrollAndSelectAction
 - ("scrollRightExtendSelection", SwingConstants.EAST,true,true));
 - map.put("scrollRightChangeLead", new ScrollAndSelectAction
 - ("scrollRightChangeLead", SwingConstants.EAST, false, false));
 - map.put("scrollLeftChangeLead", new ScrollAndSelectAction
 - ("scrollLeftChangeLead", SwingConstants.WEST, false, false));
 - map.put("expand", new TreeExpandAction());
 - map.put("collapse", new TreeCollapseAction());
 - map.put("moveSelectionToParent", new TreeMoveSelectionToParentAction());
 - map.put(TransferHandler.getCutAction().getValue(Action.NAME),
 - TransferHandler.getCutAction());
 - map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
 - TransferHandler.getCopyAction());
 - map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
 - TransferHandler.getPasteAction());
 - }
 - /**
 - * Intalls the subcomponents of the tree, which is the renderer pane.
 - */
 - protected void installComponents() {
 - }
 - public SynthContext getContext(JComponent c) {
 - return getContext(c, getComponentState(c));
 - }
 - private SynthContext getContext(JComponent c, int state) {
 - return SynthContext.getContext(SynthContext.class, c,
 - SynthLookAndFeel.getRegion(c), style, state);
 - }
 - private Region getRegion(JTree c) {
 - return SynthLookAndFeel.getRegion(c);
 - }
 - private int getComponentState(JComponent c) {
 - return SynthLookAndFeel.getComponentState(c);
 - }
 - private SynthContext getContext(JComponent c, Region region) {
 - return getContext(c, region, getComponentState(c, region));
 - }
 - private SynthContext getContext(JComponent c, Region region, int state) {
 - return SynthContext.getContext(SynthContext.class, c,
 - region, cellStyle, state);
 - }
 - private int getComponentState(JComponent c, Region region) {
 - // Always treat the cell as selected, will be adjusted appropriately
 - // when painted.
 - return ENABLED | SELECTED;
 - }
 - //
 - // Create methods.
 - //
 - /**
 - * Adjusts the bounds, as returned from the TreeState to the insets
 - * and orientation of the Tree.
 - */
 - private void adjustCellBounds(JTree tree, Rectangle bounds, Insets i){
 - if (bounds != null) {
 - if (i == null) {
 - i = tree.getInsets();
 - }
 - bounds.y += i.top;
 - if (leftToRight) {
 - bounds.x += i.left;
 - }
 - else {
 - bounds.x = tree.getWidth() - i.right - bounds.x - bounds.width;
 - }
 - }
 - }
 - /**
 - * Creates an instance of NodeDimensions that is able to determine
 - * the size of a given node in the tree.
 - */
 - protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
 - return new NodeDimensionsHandler();
 - }
 - /**
 - * Creates the listener responsible for updating the selection based on
 - * mouse events.
 - */
 - protected MouseListener createMouseListener() {
 - return new MouseHandler();
 - }
 - /**
 - * Creates a listener that is responsible for updating the display
 - * when focus is lost/gained.
 - */
 - protected FocusListener createFocusListener() {
 - return new FocusHandler();
 - }
 - /**
 - * Creates the listener reponsible for getting key events from
 - * the tree.
 - */
 - protected KeyListener createKeyListener() {
 - return new KeyHandler();
 - }
 - /**
 - * Creates the listener that updates the display based on selection change
 - * methods.
 - */
 - protected TreeSelectionListener createTreeSelectionListener() {
 - return new TreeSelectionHandler();
 - }
 - /**
 - * Creates a listener to handle events from the current editor.
 - */
 - protected CellEditorListener createCellEditorListener() {
 - return new CellEditorHandler();
 - }
 - /**
 - * Creates and returns a new ComponentHandler. This is used for
 - * the large model to mark the validCachedPreferredSize as invalid
 - * when the component moves.
 - */
 - protected ComponentListener createComponentListener() {
 - return new ComponentHandler();
 - }
 - /**
 - * Creates and returns the object responsible for updating the treestate
 - * when nodes expanded state changes.
 - */
 - protected TreeExpansionListener createTreeExpansionListener() {
 - return new TreeExpansionHandler();
 - }
 - /**
 - * Creates the object responsible for managing what is expanded, as
 - * well as the size of nodes.
 - */
 - protected AbstractLayoutCache createLayoutCache() {
 - if (largeModel && tree.getRowHeight() > 0) {
 - return new FixedHeightLayoutCache();
 - }
 - return new VariableHeightLayoutCache();
 - }
 - /**
 - * Returns the renderer pane that renderer components are placed in.
 - */
 - protected CellRendererPane createCellRendererPane() {
 - return new CellRendererPane();
 - }
 - /**
 - * Creates a default cell editor.
 - */
 - protected TreeCellEditor createCellEditor() {
 - TreeCellRenderer renderer = tree.getCellRenderer();
 - DefaultTreeCellEditor editor;
 - if(renderer != null && (renderer instanceof DefaultTreeCellRenderer)) {
 - editor = new SynthTreeCellEditor(tree, (DefaultTreeCellRenderer)
 - renderer);
 - }
 - else {
 - editor = new SynthTreeCellEditor(tree, null);
 - }
 - SynthContext context = getContext(tree, ENABLED);
 - context.setComponentState(ENABLED | SELECTED);
 - context.dispose();
 - return editor;
 - }
 - /**
 - * Returns the default cell renderer that is used to do the
 - * stamping of each node.
 - */
 - protected TreeCellRenderer createCellRenderer() {
 - return new SynthTreeCellRenderer();
 - }
 - /**
 - * Returns a listener that can update the tree when the model changes.
 - */
 - protected TreeModelListener createTreeModelListener() {
 - return new TreeModelHandler();
 - }
 - //
 - // Uninstall methods
 - //
 - public void uninstallUI(JComponent c) {
 - completeEditing();
 - uninstallListeners();
 - uninstallComponents();
 - uninstallKeyboardActions();
 - uninstallDefaults();
 - }
 - protected void uninstallDefaults() {
 - SynthContext context = getContext(tree, ENABLED);
 - style.uninstallDefaults(context);
 - context.dispose();
 - style = null;
 - context = getContext(tree, Region.TREE_CELL, ENABLED);
 - cellStyle.uninstallDefaults(context);
 - context.dispose();
 - cellStyle = null;
 - if (tree.getTransferHandler() instanceof UIResource) {
 - tree.setTransferHandler(null);
 - }
 - if (tree.getCellRenderer() instanceof UIResource) {
 - tree.setCellRenderer(null);
 - }
 - if (tree.getCellEditor() instanceof UIResource) {
 - tree.setCellEditor(null);
 - }
 - tree = null;
 - }
 - protected void uninstallListeners() {
 - if (componentListener != null) {
 - tree.removeComponentListener(componentListener);
 - }
 - tree.removePropertyChangeListener(this);
 - tree.removeMouseListener(defaultDragRecognizer);
 - tree.removeMouseMotionListener(defaultDragRecognizer);
 - if (mouseListener != null) {
 - tree.removeMouseListener(mouseListener);
 - if (mouseListener instanceof MouseMotionListener) {
 - tree.removeMouseMotionListener((MouseMotionListener)
 - mouseListener);
 - }
 - }
 - if (focusListener != null) {
 - tree.removeFocusListener(focusListener);
 - }
 - if (keyListener != null) {
 - tree.removeKeyListener(keyListener);
 - }
 - if (treeExpansionListener != null) {
 - tree.removeTreeExpansionListener(treeExpansionListener);
 - }
 - TreeModel treeModel = tree.getModel();
 - if (treeModel != null && treeModelListener != null) {
 - treeModel.removeTreeModelListener(treeModelListener);
 - }
 - TreeSelectionModel selectionModel = tree.getSelectionModel();
 - if (treeSelectionListener != null) {
 - tree.getSelectionModel().removeTreeSelectionListener
 - (treeSelectionListener);
 - }
 - TreeCellEditor editor = tree.getCellEditor();
 - if (editor != null && cellEditorListener != null) {
 - editor.removeCellEditorListener(cellEditorListener);
 - }
 - }
 - protected void uninstallKeyboardActions() {
 - SwingUtilities.replaceUIActionMap(tree, null);
 - SwingUtilities.replaceUIInputMap(tree, JComponent.
 - WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 - null);
 - SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED, null);
 - }
 - /**
 - * Uninstalls the renderer pane.
 - */
 - protected void uninstallComponents() {
 - if (rendererPane != null) {
 - tree.remove(rendererPane);
 - }
 - }
 - //
 - // Painting routines.
 - //
 - public void update(Graphics g, JComponent c) {
 - SynthContext context = getContext(c);
 - SynthLookAndFeel.update(context, g);
 - paint(context, g);
 - context.dispose();
 - }
 - public void paint(Graphics g, JComponent c) {
 - SynthContext context = getContext(c);
 - paint(context, g);
 - context.dispose();
 - }
 - protected void paint(SynthContext context, Graphics g) {
 - Rectangle paintBounds = g.getClipBounds();
 - Insets insets = tree.getInsets();
 - TreePath initialPath = getClosestPathForLocation(tree, 0,
 - paintBounds.y);
 - Enumeration paintingEnumerator = treeState.getVisiblePathsFrom
 - (initialPath);
 - int row = treeState.getRowForPath(initialPath);
 - int endY = paintBounds.y + paintBounds.height;
 - TreeModel treeModel = tree.getModel();
 - SynthContext cellContext = getContext(tree, Region.TREE_CELL);
 - drawingCache.clear();
 - if (paintingEnumerator != null) {
 - // First pass, draw the rows
 - boolean done = false;
 - boolean isExpanded;
 - boolean hasBeenExpanded;
 - boolean isLeaf;
 - Rectangle boundsBuffer = new Rectangle();
 - Rectangle rowBounds = new Rectangle(0, 0, tree.getWidth(),0);
 - Rectangle bounds;
 - TreePath path;
 - TreeCellRenderer renderer = tree.getCellRenderer();
 - DefaultTreeCellRenderer dtcr = (renderer instanceof
 - DefaultTreeCellRenderer) ? (DefaultTreeCellRenderer)
 - renderer : null;
 - configureRenderer(cellContext);
 - while (!done && paintingEnumerator.hasMoreElements()) {
 - path = (TreePath)paintingEnumerator.nextElement();
 - if (path != null) {
 - isLeaf = treeModel.isLeaf(path.getLastPathComponent());
 - if (isLeaf) {
 - isExpanded = hasBeenExpanded = false;
 - }
 - else {
 - isExpanded = treeState.getExpandedState(path);
 - hasBeenExpanded = tree.hasBeenExpanded(path);
 - }
 - bounds = treeState.getBounds(path, boundsBuffer);
 - adjustCellBounds(tree, bounds, insets);
 - rowBounds.y = bounds.y;
 - rowBounds.height = bounds.height;
 - paintRow(renderer, dtcr, context, cellContext, g,
 - paintBounds, insets, bounds, rowBounds, path,
 - row, isExpanded, hasBeenExpanded, isLeaf);
 - if ((bounds.y + bounds.height) >= endY) {
 - done = true;
 - }
 - }
 - else {
 - done = true;
 - }
 - row++;
 - }
 - // Draw the connecting lines and controls.
 - // Find each parent and have them draw a line to their last child
 - boolean rootVisible = tree.isRootVisible();
 - TreePath parentPath = initialPath;
 - parentPath = parentPath.getParentPath();
 - while (parentPath != null) {
 - paintVerticalPartOfLeg(context, g, paintBounds,
 - insets, parentPath);
 - drawingCache.put(parentPath, Boolean.TRUE);
 - parentPath = parentPath.getParentPath();
 - }
 - done = false;
 - paintingEnumerator = treeState.getVisiblePathsFrom(initialPath);
 - while (!done && paintingEnumerator.hasMoreElements()) {
 - path = (TreePath)paintingEnumerator.nextElement();
 - if (path != null) {
 - isLeaf = treeModel.isLeaf(path.getLastPathComponent());
 - if (isLeaf) {
 - isExpanded = hasBeenExpanded = false;
 - }
 - else {
 - isExpanded = treeState.getExpandedState(path);
 - hasBeenExpanded = tree.hasBeenExpanded(path);
 - }
 - bounds = treeState.getBounds(path, boundsBuffer);
 - adjustCellBounds(tree, bounds, insets);
 - // See if the vertical line to the parent has been drawn.
 - parentPath = path.getParentPath();
 - if (parentPath != null) {
 - if (drawingCache.get(parentPath) == null) {
 - paintVerticalPartOfLeg(context, g,
 - paintBounds, insets,
 - parentPath);
 - drawingCache.put(parentPath, Boolean.TRUE);
 - }
 - paintHorizontalPartOfLeg(context, g,
 - paintBounds, insets, bounds,
 - path, row, isExpanded,
 - hasBeenExpanded, isLeaf);
 - }
 - else if (rootVisible && row == 0) {
 - paintHorizontalPartOfLeg(context, g,
 - paintBounds, insets, bounds,
 - path, row, isExpanded,
 - hasBeenExpanded, isLeaf);
 - }
 - if (shouldPaintExpandControl(path, row, isExpanded,
 - hasBeenExpanded, isLeaf)) {
 - paintExpandControl(context, g, paintBounds,
 - insets, bounds, path, row,
 - isExpanded, hasBeenExpanded,isLeaf);
 - }
 - if ((bounds.y + bounds.height) >= endY) {
 - done = true;
 - }
 - }
 - else {
 - done = true;
 - }
 - row++;
 - }
 - }
 - cellContext.dispose();
 - // Empty out the renderer pane, allowing renderers to be gc'ed.
 - rendererPane.removeAll();
 - }
 - private void configureRenderer(SynthContext context) {
 - TreeCellRenderer renderer = tree.getCellRenderer();
 - if (renderer instanceof DefaultTreeCellRenderer) {
 - DefaultTreeCellRenderer r = (DefaultTreeCellRenderer)renderer;
 - SynthStyle style = context.getStyle();
 - context.setComponentState(ENABLED | SELECTED);
 - Color color = r.getTextSelectionColor();
 - if (color == null || (color instanceof UIResource)) {
 - r.setTextSelectionColor(style.getColor(
 - context, ColorType.TEXT_FOREGROUND));
 - }
 - color = r.getBackgroundSelectionColor();
 - if (color == null || (color instanceof UIResource)) {
 - r.setBackgroundSelectionColor(style.getColor(
 - context, ColorType.TEXT_BACKGROUND));
 - }
 - context.setComponentState(ENABLED);
 - color = r.getTextNonSelectionColor();
 - if (color == null || color instanceof UIResource) {
 - r.setTextNonSelectionColor(style.getColor(
 - context, ColorType.TEXT_FOREGROUND));
 - }
 - color = r.getBackgroundNonSelectionColor();
 - if (color instanceof UIResource) {
 - r.setBackgroundNonSelectionColor(style.getColor(
 - context, ColorType.TEXT_BACKGROUND));
 - }
 - }
 - }
 - /**
 - * Paints the horizontal part of the leg. The receiver should
 - * NOT modify <code>clipBounds</code>, or <code>insets</code>.<p>
 - * NOTE: <code>parentRow</code> can be -1 if the root is not visible.
 - */
 - protected void paintHorizontalPartOfLeg(SynthContext context, Graphics g,
 - Rectangle clipBounds, Insets insets,
 - Rectangle bounds, TreePath path,
 - int row, boolean isExpanded,
 - boolean hasBeenExpanded,
 - boolean isLeaf) {
 - if (!drawHorizontalLegs) {
 - return;
 - }
 - int depth = path.getPathCount() - 1;
 - if ((depth == 0 || (depth == 1 && !tree.isRootVisible())) &&
 - !tree.getShowsRootHandles()) {
 - return;
 - }
 - int clipLeft = clipBounds.x;
 - int clipRight = clipBounds.x + (clipBounds.width - 1);
 - int clipBottom = clipBounds.y + (clipBounds.height - 1);
 - int y = bounds.y + bounds.height / 2;
 - int x0;
 - int x1;
 - if (leftToRight) {
 - x0 = bounds.x - getIndent() - getTrailingControlOffset();
 - x1 = bounds.x - trailingLegBufferOffset;
 - }
 - else {
 - x0 = bounds.x + bounds.width + trailingLegBufferOffset;
 - x1 = bounds.x + bounds.width + getIndent() +
 - getTrailingControlOffset();
 - }
 - if (y >= clipBounds.y && y <= clipBottom && x1 >= clipLeft &&
 - x0 <= clipRight ) {
 - x0 = Math.max(x0, clipLeft);
 - x1 = Math.min(x1, clipRight);
 - if (x0 < x1) {
 - SynthGraphics engine = context.getStyle().
 - getSynthGraphics(context);
 - g.setColor(context.getStyle().getColor(context,
 - ColorType.FOREGROUND));
 - engine.drawLine(context, "Tree.horizontalLine", g, x0, y,
 - x1, y);
 - }
 - }
 - }
 - /**
 - * Paints the vertical part of the leg. The receiver should
 - * NOT modify <code>clipBounds</code>, <code>insets</code>.<p>
 - */
 - protected void paintVerticalPartOfLeg(SynthContext context, Graphics g,
 - Rectangle clipBounds, Insets insets,
 - TreePath path) {
 - if (!drawVerticalLegs) {
 - return;
 - }
 - int depth = path.getPathCount() - 1;
 - if (depth == 0 && !tree.getShowsRootHandles() &&
 - !tree.isRootVisible()) {
 - return;
 - }
 - int lineX;
 - int offset = getRowX(-1, depth) - getTrailingControlOffset();
 - if (leftToRight) {
 - lineX = offset + insets.left;
 - }
 - else {
 - lineX = tree.getWidth() - offset - insets.right;
 - }
 - int clipLeft = clipBounds.x;
 - int clipRight = clipBounds.x + (clipBounds.width - 1);
 - if (lineX >= clipLeft && lineX <= clipRight) {
 - int clipTop = clipBounds.y;
 - int clipBottom = clipBounds.y + clipBounds.height;
 - Rectangle parentBounds = getPathBounds(tree, path);
 - Rectangle lastChildBounds = getPathBounds(tree,
 - getLastChildPath(path));
 - int top;
 - if (parentBounds == null) {
 - top = Math.max(insets.top, clipTop);
 - }
 - else {
 - top = Math.max(parentBounds.y + parentBounds.height, clipTop);
 - }
 - if (depth == 0 && !tree.isRootVisible()) {
 - TreeModel model = tree.getModel();
 - Object root = model.getRoot();
 - if (model.getChildCount(root) > 0) {
 - parentBounds = getPathBounds(tree, path.
 - pathByAddingChild(model.getChild(root, 0)));
 - if (parentBounds != null) {
 - top = Math.max(insets.top, parentBounds.y +
 - parentBounds.height / 2);
 - }
 - }
 - }
 - int bottom = Math.min(lastChildBounds.y +
 - (lastChildBounds.height / 2), clipBottom);
 - if (top < bottom) {
 - SynthGraphics engine = context.getStyle().
 - getSynthGraphics(context);
 - g.setColor(context.getStyle().getColor(context,
 - ColorType.FOREGROUND));
 - engine.drawLine(context, "Tree.verticalLine", g, lineX, top,
 - lineX, bottom);
 - }
 - }
 - }
 - /**
 - * Paints the expand (toggle) part of a row. The receiver should
 - * NOT modify <code>clipBounds</code>, or <code>insets</code>.
 - */
 - protected void paintExpandControl(SynthContext context, Graphics g,
 - Rectangle clipBounds, Insets insets,
 - Rectangle bounds, TreePath path,
 - int row, boolean isExpanded,
 - boolean hasBeenExpanded,
 - boolean isLeaf) {
 - Object value = path.getLastPathComponent();
 - // Draw icons if not a leaf and either hasn't been loaded,
 - // or the model child count is > 0.
 - if (!isLeaf && (!hasBeenExpanded ||
 - tree.getModel().getChildCount(value) > 0)) {
 - int middleXOfKnob;
 - if (leftToRight) {
 - middleXOfKnob = bounds.x - getTrailingControlOffset() + 1;
 - }
 - else {
 - middleXOfKnob = bounds.x + bounds.width +
 - getTrailingControlOffset() - 1;
 - }
 - int middleYOfKnob = bounds.y + (bounds.height / 2);
 - if (isExpanded) {
 - Icon expandedIcon = getExpandedIcon();
 - if (expandedIcon != null) {
 - paintIconCenteredAt(context, tree, g, expandedIcon,
 - middleXOfKnob, middleYOfKnob);
 - }
 - }
 - else {
 - Icon collapsedIcon = getCollapsedIcon();
 - if (collapsedIcon != null) {
 - paintIconCenteredAt(context, tree, g, collapsedIcon,
 - middleXOfKnob, middleYOfKnob);
 - }
 - }
 - }
 - }
 - /**
 - * Paints the renderer part of a row. The receiver should
 - * NOT modify <code>clipBounds</code>, or <code>insets</code>.
 - */
 - protected void paintRow(TreeCellRenderer renderer,
 - DefaultTreeCellRenderer dtcr, SynthContext treeContext,
 - SynthContext cellContext, Graphics g, Rectangle clipBounds,
 - Insets insets, Rectangle bounds, Rectangle rowBounds,
 - TreePath path, int row, boolean isExpanded,
 - boolean hasBeenExpanded, boolean isLeaf) {
 - // Don't paint the renderer if editing this row.
 - boolean selected = tree.isRowSelected(row);
 - if (selected) {
 - cellContext.setComponentState(ENABLED | SELECTED);
 - }
 - else {
 - cellContext.setComponentState(ENABLED);
 - }
 - if (dtcr != null && (dtcr.getBorderSelectionColor() instanceof
 - UIResource)) {
 - dtcr.setBorderSelectionColor(style.getColor(
 - cellContext, ColorType.FOCUS));
 - }
 - SynthLookAndFeel.updateSubregion(cellContext, g, rowBounds);
 - if (getEditingRow() == row) {
 - return;
 - }
 - int leadIndex;
 - if (tree.hasFocus()) {
 - leadIndex = getLeadSelectionRow();
 - }
 - else {
 - leadIndex = -1;
 - }
 - Component component = renderer.getTreeCellRendererComponent(
 - tree, path.getLastPathComponent(),
 - selected, isExpanded, isLeaf, row,
 - (leadIndex == row));
 - rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y,
 - bounds.width, bounds.height, true);
 - }
 - /**
 - * Returns true if the expand (toggle) control should be drawn for
 - * the specified row.
 - */
 - private boolean shouldPaintExpandControl(TreePath path, int row,
 - boolean isExpanded,
 - boolean hasBeenExpanded,
 - boolean isLeaf) {
 - if (isLeaf) {
 - return false;
 - }
 - int depth = path.getPathCount() - 1;
 - if ((depth == 0 || (depth == 1 && !tree.isRootVisible())) &&
 - !tree.getShowsRootHandles()) {
 - return false;
 - }
 - return true;
 - }
 - //
 - // Generic painting methods
 - //
 - /**
 - * Paints the Icon centered at the specified location.
 - */
 - private void paintIconCenteredAt(SynthContext context, Component c,
 - Graphics graphics, Icon icon,
 - int x, int y) {
 - int w = SynthIcon.getIconWidth(icon, context);
 - int h = SynthIcon.getIconHeight(icon, context);
 - SynthIcon.paintIcon(icon, context, graphics, x - w2, y - h2, w, h);
 - }
 - //
 - // Various local methods
 - //
 - /**
 - * Resets the selection model. The appropriate listener are installed
 - * on the model.
 - */
 - private void selectionModelChanged(TreeSelectionModel oldModel,
 - TreeSelectionModel newModel) {
 - completeEditing();
 - if (newModel != null) {
 - if (treeSelectionListener != null) {
 - newModel.removeTreeSelectionListener
 - (treeSelectionListener);
 - }
 - }
 - if (newModel != null) {
 - if (treeSelectionListener != null) {
 - newModel.addTreeSelectionListener
 - (treeSelectionListener);
 - }
 - if (treeState != null) {
 - treeState.setSelectionModel(newModel);
 - }
 - }
 - else if (treeState != null) {
 - treeState.setSelectionModel(null);
 - }
 - if (tree != null) {
 - tree.repaint();
 - }
 - }
 - public void propertyChange(PropertyChangeEvent event) {
 - if (event.getSource() == tree) {
 - String changeName = event.getPropertyName();
 - if (SynthLookAndFeel.shouldUpdateStyle(event)) {
 - fetchStyle((JTree)event.getSource());
 - }
 - if (JTree.LEAD_SELECTION_PATH_PROPERTY.equals(changeName)) {
 - updateLeadRow();
 - repaintPath((TreePath)event.getOldValue());
 - repaintPath((TreePath)event.getNewValue());
 - }
 - else if (JTree.ANCHOR_SELECTION_PATH_PROPERTY.equals(changeName)) {
 - repaintPath((TreePath)event.getOldValue());
 - repaintPath((TreePath)event.getNewValue());
 - }
 - else if (JTree.CELL_RENDERER_PROPERTY.equals(changeName)) {
 - completeEditing();
 - updateRenderer();
 - invalidateStateAndSize();
 - }
 - else if (JTree.TREE_MODEL_PROPERTY.equals(changeName)) {
 - TreeModel oldModel = (TreeModel)event.getOldValue();
 - completeEditing();
 - if (oldModel != null && treeModelListener != null) {
 - oldModel.removeTreeModelListener(treeModelListener);
 - }
 - TreeModel newModel = (TreeModel)event.getNewValue();
 - if (newModel != null && treeModelListener != null) {
 - newModel.addTreeModelListener(treeModelListener);
 - }
 - if (treeState != null) {
 - treeState.setModel(newModel);
 - updateLayoutCacheExpandedNodes();
 - invalidateSize();
 - }
 - }
 - else if (JTree.ROOT_VISIBLE_PROPERTY.equals(changeName)) {
 - completeEditing();
 - updateRootOffset();
 - if (treeState != null) {
 - treeState.setRootVisible(((Boolean)event.getNewValue()).
 - booleanValue());
 - invalidateStateAndSize();
 - }
 - }
 - else if (JTree.SHOWS_ROOT_HANDLES_PROPERTY.equals(changeName)) {
 - completeEditing();
 - updateRootOffset();
 - invalidateStateAndSize();
 - }
 - else if (JTree.ROW_HEIGHT_PROPERTY.equals(changeName)) {
 - completeEditing();
 - if (treeState != null) {
 - updateLargeModel();
 - treeState.setRowHeight(tree.getRowHeight());
 - invalidateSize();
 - }
 - }
 - else if (JTree.CELL_EDITOR_PROPERTY.equals(changeName)) {
 - completeEditing();
 - TreeCellEditor oldEditor = (TreeCellEditor)event.getOldValue();
 - if (oldEditor != null && cellEditorListener != null) {
 - oldEditor.removeCellEditorListener(cellEditorListener);
 - }
 - TreeCellEditor newEditor = (TreeCellEditor)event.getNewValue();
 - if (newEditor != null) {
 - if (cellEditorListener == null) {
 - cellEditorListener = createCellEditorListener();
 - }
 - if (cellEditorListener != null) {
 - newEditor.addCellEditorListener(cellEditorListener);
 - }
 - }
 - }
 - else if (JTree.EDITABLE_PROPERTY.equals(changeName)) {
 - completeEditing();
 - TreeCellEditor editor = tree.getCellEditor();
 - if (tree.isEditable()) {
 - if (editor == null) {
 - editor = createCellEditor();
 - if (editor != null) {
 - tree.setCellEditor(editor);
 - }
 - }
 - else {
 - if (cellEditorListener == null) {
 - cellEditorListener = createCellEditorListener();
 - }
 - if (cellEditorListener != null) {
 - editor.addCellEditorListener(cellEditorListener);
 - }
 - }
 - }
 - else if (editor instanceof UIResource) {
 - tree.setCellEditor(null);
 - }
 - }
 - else if (JTree.LARGE_MODEL_PROPERTY.equals(changeName)) {
 - updateLargeModel();
 - }
 - else if(JTree.SELECTION_MODEL_PROPERTY.equals(changeName)) {
 - selectionModelChanged((TreeSelectionModel)event.
 - getOldValue(), tree.getSelectionModel());
 - }
 - else if("font".equals(changeName)) {
 - completeEditing();
 - invalidateStateAndSize();
 - }
 - else if ("componentOrientation".equals(changeName)) {
 - leftToRight = tree.getComponentOrientation().isLeftToRight();
 - invalidateStateAndSize();
 - InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
 - SwingUtilities.replaceUIInputMap(tree,
 - JComponent.WHEN_FOCUSED, km);
 - } else if ("transferHandler".equals(changeName)) {
 - DropTarget dropTarget = tree.getDropTarget();
 - if (dropTarget instanceof UIResource) {
 - if (defaultDropTargetListener == null) {
 - defaultDropTargetListener = new TreeDropTargetListener();
 - }
 - try {
 - dropTarget.addDropTargetListener(defaultDropTargetListener);
 - } catch (TooManyListenersException tmle) {
 - // should not happen... swing drop target is multicast
 - }
 - }
 - }
 - }
 - }
 - private int getTrailingControlOffset() {
 - return trailingControlOffset;
 - }
 - private int getIndent() {
 - return indent;
 - }
 - /**
 - * Returns the icon to draw when the node is expanded.
 - */
 - private Icon getExpandedIcon() {
 - return expandedIcon;
 - }
 - /**
 - * Returns the Icon to draw when the node is collapsed.
 - */
 - private Icon getCollapsedIcon() {
 - return collapsedIcon;
 - }
 - /**
 - * Updates the necessary state in response to the large model, or rowHeight
 - * property changing.
 - */
 - private void updateLargeModel() {
 - boolean largeModel = tree.isLargeModel();
 - if (tree.getRowHeight() < 1) {
 - largeModel = false;
 - }
 - if (this.largeModel != largeModel) {
 - completeEditing();
 - this.largeModel = largeModel;
 - treeState = createLayoutCache();
 - configureLayoutCache();
 - invalidateSize();
 - }
 - }
 - /**
 - * Returns true if operating in large model mode.
 - */
 - private boolean isLargeModel() {
 - return largeModel;
 - }
 - /**
 - * Returns the amount to indent the given row. NOTE: This does not
 - * include insets, nor should it!
 - */
 - private int getRowX(int row, int depth) {
 - return getIndent() * (depth + rootOffset - 1) + controlSize;
 - }
 - /**
 - * Makes all the nodes that are expanded in JTree expanded in LayoutCache.
 - * This invokes updateExpandedDescendants with the root path.
 - */
 - private void updateLayoutCacheExpandedNodes() {
 - TreeModel treeModel = tree.getModel();
 - if (treeModel != null && treeModel.getRoot() != null) {
 - updateExpandedDescendants(new TreePath(treeModel.getRoot()));
 - }
 - }
 - /**
 - * Updates the expanded state of all the descendants of <code>path</code>
 - * by getting the expanded descendants from the tree and forwarding
 - * to the tree state.
 - */
 - private void updateExpandedDescendants(TreePath path) {
 - completeEditing();
 - treeState.setExpandedState(path, true);
 - Enumeration descendants = tree.getExpandedDescendants(path);
 - if (descendants != null) {
 - while (descendants.hasMoreElements()) {
 - path = (TreePath)descendants.nextElement();
 - treeState.setExpandedState(path, true);
 - }
 - }
 - updateLeadRow();
 - invalidateSize();
 - }
 - /**
 - * Returns a path to the last child of <code>parent</code>.
 - */
 - private TreePath getLastChildPath(TreePath parent) {
 - TreeModel treeModel = tree.getModel();
 - if (treeModel != null) {
 - int childCount = treeModel.getChildCount
 - (parent.getLastPathComponent());
 - if(childCount > 0) {
 - return parent.pathByAddingChild(treeModel.getChild
 - (parent.getLastPathComponent(), childCount - 1));
 - }
 - }
 - return null;
 - }
 - /**
 - * Updates the offset for the root. This should be invoked as the
 - * properties the rootOffset depends upon change, eg root visibility,
 - * showing root handles...
 - */
 - private void updateRootOffset() {
 - if (tree.isRootVisible()) {
 - if (tree.getShowsRootHandles()) {
 - rootOffset = 1;
 - }
 - else {
 - rootOffset = 0;
 - }
 - }
 - else if (!tree.getShowsRootHandles()) {
 - rootOffset = -1;
 - }
 - else {
 - rootOffset = 0;
 - }
 - }
 - /**
 - * If the JTree's renderer is null, this will install a default one.
 - * Additionaly if we have installed an editor, we're reinstall it.
 - */
 - private void updateRenderer() {
 - TreeCellRenderer newCellRenderer = tree.getCellRenderer();
 - if (newCellRenderer == null) {
 - tree.setCellRenderer(createCellRenderer());
 - }
 - if (tree.isEditable() && (tree.getCellEditor() instanceof
 - UIResource)) {
 - // We do this as the editor gets state from the renderer,
 - // so that any time one changes we need to update the other.
 - tree.setCellEditor(createCellEditor());
 - }
 - }
 - /**
 - * Configures the AbstractLayoutCache based on the tree we're
 - * providing the look and feel for.
 - */
 - private void configureLayoutCache() {
 - if (nodeDimensions == null) {
 - nodeDimensions = createNodeDimensions();
 - }
 - treeState.setNodeDimensions(nodeDimensions);
 - treeState.setRootVisible(tree.isRootVisible());
 - treeState.setRowHeight(tree.getRowHeight());
 - treeState.setSelectionModel(tree.getSelectionModel());
 - // Only do this if necessary, may loss state if call with
 - // same model as it currently has.
 - if (treeState.getModel() != tree.getModel()) {
 - treeState.setModel(tree.getModel());
 - }
 - updateLayoutCacheExpandedNodes();
 - // Create a listener to update preferred size when bounds
 - // changes, if necessary.
 - if (largeModel) {
 - if (componentListener == null) {
 - componentListener = createComponentListener();
 - if (componentListener != null) {
 - tree.addComponentListener(componentListener);
 - }
 - }
 - }
 - else if(componentListener != null) {
 - tree.removeComponentListener(componentListener);
 - componentListener = null;
 - }
 - }
 - /**
 - * Invalides the size of the AbstractLayoutCache and marks the tree as
 - * needing to redisplay.
 - */
 - private void invalidateStateAndSize() {
 - treeState.invalidateSizes();
 - invalidateSize();
 - }
 - /**
 - * Marks the cached size as being invalid, and messages the
 - * tree with <code>treeDidChange</code>.
 - */
 - private void invalidateSize() {
 - validCachedPreferredSize = false;
 - tree.treeDidChange();
 - }
 - /**
 - * Recalculates the preferred size needed to display the tree.
 - */
 - private void updateCachedPreferredSize() {
 - Insets i = tree.getInsets();
 - if (largeModel) {
 - Rectangle visRect = tree.getVisibleRect();
 - visRect.x -= i.left;
 - visRect.y -= i.top;
 - preferredSize.width = treeState.getPreferredWidth(visRect);
 - }
 - else if (leftToRight) {
 - preferredSize.width = treeState.getPreferredWidth(null);
 - }
 - preferredSize.height = treeState.getPreferredHeight();
 - preferredSize.width += i.left + i.right;
 - preferredSize.height += i.top + i.bottom;
 - validCachedPreferredSize = true;
 - }
 - //
 - // Editing related methods
 - //
 - /**
 - * Returns the row being edited, -1 if not editing.
 - */
 - private int getEditingRow() {
 - return (editingState != null) ? editingState.row : -1;
 - }
 - /**
 - * Returns the Component responsible for editing, or null if not
 - * editing.
 - */
 - private Component getEditingComponent() {
 - return (editingState != null) ? editingState.component : null;
 - }
 - /**
 - * Messaged to stop the editing session. If the tree the receiver
 - * is providing the look and feel for returns true from
 - * <code>getInvokesStopCellEditing</code>, stopCellEditing will be
 - * invoked on the current editor, otherwise cancelCellEditing will be
 - * invoked
 - */
 - private void completeEditing() {
 - if (tree.getInvokesStopCellEditing() && getEditingComponent() != null){
 - tree.getCellEditor().stopCellEditing();
 - }
 - // Invoke cancelCellEditing, this will do nothing if stopCellEditing
 - // was successful.
 - completeEditing(false, true, false);
 - }
 - /**
 - * Stops the editing session. If messageStop is true the editor
 - * is messaged with stopEditing, if messageCancel is true the
 - * editor is messaged with cancelEditing. If messageTree is true
 - * the treeModel is messaged with valueForPathChanged.
 - */
 - private void completeEditing(boolean messageStop,
 - boolean messageCancel,
 - boolean messageTree) {
 - if (editingState != null) {
 - EditingState oldState = editingState;
 - Object newValue = editingState.editor.getCellEditorValue();
 - Rectangle editingBounds = tree.getPathBounds(oldState.path);
 - boolean requestFocus = (tree != null && (tree.hasFocus() ||
 - SwingUtilities.findFocusOwner(editingState.component) != null));
 - editingState = null;
 - if (messageStop) {
 - oldState.editor.stopCellEditing();
 - }
 - else if (messageCancel) {
 - oldState.editor.cancelCellEditing();
 - }
 - tree.remove(oldState.component);
 - if (oldState.editorHasDifferentSize) {
 - treeState.invalidatePathBounds(oldState.path);
 - invalidateSize();
 - }
 - else {
 - editingBounds.x = 0;
 - editingBounds.width = tree.getSize().width;
 - tree.repaint(editingBounds);
 - }
 - if (requestFocus) {
 - tree.requestFocus();
 - }
 - if (messageTree) {
 - tree.getModel().valueForPathChanged(oldState.path, newValue);
 - }
 - }
 - }
 - /**
 - * Will start editing for node if there is a cellEditor and
 - * shouldSelectCell returns true.<p>
 - * This assumes that path is valid and visible.
 - */
 - private boolean startEditing(TreePath path, MouseEvent event) {
 - if (tree.isEditing() && tree.getInvokesStopCellEditing() &&
 - !tree.stopEditing()) {
 - return false;
 - }
 - completeEditing();
 - TreeCellEditor cellEditor = tree.getCellEditor();
 - if (cellEditor != null && tree.isPathEditable(path)) {
 - int row = getRowForPath(tree, path);
 - if (cellEditor.isCellEditable(event)) {
 - EditingState state = new EditingState();
 - editingState = state;
 - state.component = cellEditor.getTreeCellEditorComponent
 - (tree, path.getLastPathComponent(),
 - tree.isPathSelected(path), tree.isExpanded(path),
 - tree.getModel().isLeaf(path.getLastPathComponent()),
 - row);
 - state.editor = cellEditor;
 - Rectangle nodeBounds = getPathBounds(tree, path);
 - state.row = row;
 - Dimension editorSize = state.component.getPreferredSize();
 - // Only allow odd heights if explicitly set.
 - if (editorSize.height != nodeBounds.height &&
 - tree.getRowHeight() > 0) {
 - editorSize.height = tree.getRowHeight();
 - }
 - if (editorSize.width != nodeBounds.width ||
 - editorSize.height != nodeBounds.height) {
 - // Editor wants different width or height, invalidate
 - // treeState and relayout.
 - state.editorHasDifferentSize = true;
 - treeState.invalidatePathBounds(path);
 - invalidateSize();
 - }
 - else {
 - state.editorHasDifferentSize = false;
 - }
 - tree.add(state.component);
 - state.component.setBounds(nodeBounds.x, nodeBounds.y,
 - editorSize.width,
 - editorSize.height);
 - state.path = path;
 - state.component.validate();
 - Rectangle visRect = tree.getVisibleRect();
 - tree.repaint(nodeBounds.x, nodeBounds.y, visRect.width +
 - visRect.x - nodeBounds.x, editorSize.height);
 - if (cellEditor.shouldSelectCell(event)) {
 - stopEditingWhenSelectionChanges = false;
 - tree.setSelectionRow(row);
 - stopEditingWhenSelectionChanges = true;
 - }
 - SynthLookAndFeel.compositeRequestFocus(state.component);
 - return true;
 - }
 - }
 - return false;
 - }
 - //
 - // Following are primarily for handling mouse events.
 - //
 - /**
 - * If the <code>mouseX</code> and <code>mouseY</code> are in the
 - * expand/collapse region of the <code>row</code>, this will toggle
 - * the row.
 - */
 - protected void expandPathIfNecessary(SynthContext context,
 - TreePath path, int mouseX,
 - int mouseY) {
 - if (isLocationInExpandControl(context, path, mouseX, mouseY)) {
 - handleExpandControlClick(path, mouseX, mouseY);
 - }
 - }
 - /**
 - * Returns true if <code>mouseX</code> and <code>mouseY</code> fall
 - * in the area of row that is used to expand/collapse the node and
 - * the node at <code>row</code> does not represent a leaf.
 - */
 - protected boolean isLocationInExpandControl(SynthContext context,
 - TreePath path, int mouseX, int mouseY) {
 - TreeModel treeModel = tree.getModel();
 - if (path != null && !treeModel.isLeaf(path.getLastPathComponent())){
 - int boxWidth;
 - if (getExpandedIcon() != null) {
 - boxWidth = SynthIcon.getIconWidth(getExpandedIcon(), context);
 - }
 - else {
 - boxWidth = 8;
 - }
 - Insets i = tree.getInsets();
 - int boxX = getRowX(tree.getRowForPath(path),
 - path.getPathCount() - 1) -
 - getTrailingControlOffset() - boxWidth / 2;
 - if (leftToRight) {
 - boxX += i.left;
 - }
 - else {
 - boxX = tree.getWidth() - getRowX(
 - tree.getRowForPath(path), path.getPathCount() - 1) +
 - getTrailingControlOffset() - boxWidth / 2;
 - }
 - return mouseX >= boxX && (mouseX <= boxX + boxWidth);
 - }
 - return false;
 - }
 - /**
 - * Messaged when the user clicks the particular row, this invokes
 - * toggleExpandState.
 - */
 - protected void handleExpandControlClick(TreePath path, int mouseX,
 - int mouseY) {
 - toggleExpandState(path);
 - }
 - /**
 - * Expands path if it is not expanded, or collapses row if it is expanded.
 - * If expanding a path and JTree scrolls on expand, ensureRowsAreVisible
 - * is invoked to scroll as many of the children to visible as possible
 - * (tries to scroll to last visible descendant of path).
 - */
 - private void toggleExpandState(TreePath path) {
 - if (!tree.isExpanded(path)) {
 - int row = tree.getRowForPath(path);
 - tree.expandPath(path);
 - invalidateSize();
 - if (row != -1) {
 - if(tree.getScrollsOnExpand()) {
 - ensureRowsAreVisible(tree, row, row + treeState.
 - getVisibleChildCount(path));
 - }
 - else {
 - ensureRowsAreVisible(tree, row, row);
 - }
 - }
 - }
 - else {
 - tree.collapsePath(path);
 - invalidateSize();
 - }
 - }
 - /**
 - * Returning true signifies a mouse event on the node should toggle
 - * the selection of only the row under mouse.
 - */
 - protected boolean isToggleSelectionEvent(MouseEvent event) {
 - return (SynthLookAndFeel.isPrimaryMouseButton(event) &&
 - event.isControlDown());
 - }
 - /**
 - * Returning true signifies a mouse event on the node should select
 - * from the anchor point.
 - */
 - protected boolean isMultiSelectEvent(MouseEvent event) {
 - return (SynthLookAndFeel.isPrimaryMouseButton(event) &&
 - event.isShiftDown());
 - }
 - /**
 - * Returning true indicates the row under the mouse should be toggled
 - * based on the event. This is invoked after checkForClickInExpandControl,
 - * implying the location is not in the expand (toggle) control
 - */
 - protected boolean isToggleEvent(MouseEvent event) {
 - if (!SynthLookAndFeel.isPrimaryMouseButton(event)) {
 - return false;
 - }
 - int clickCount = tree.getToggleClickCount();
 - if (clickCount <= 0) {
 - return false;
 - }
 - return (event.getClickCount() == clickCount);
 - }
 - /**
 - * Messaged to update the selection based on a MouseEvent over a
 - * particular row. If the event is a toggle selection event, the
 - * row is either selected, or deselected. If the event identifies
 - * a multi selection event, the selection is updated from the
 - * anchor point. Otherwise the row is selected, and if the event
 - * specified a toggle event the row is expanded/collapsed.
 - */
 - protected void selectPathForEvent(TreePath path, MouseEvent event) {
 - // Should this event toggle the selection of this row?
 - /* Control toggles just this node. */
 - if (isToggleSelectionEvent(event)) {
 - if (tree.isPathSelected(path)) {
 - tree.removeSelectionPath(path);
 - }
 - else {
 - tree.addSelectionPath(path);
 - }
 - tree.setAnchorSelectionPath(path);
 - tree.setLeadSelectionPath(path);
 - }
 - /* Adjust from the anchor point. */
 - else if (isMultiSelectEvent(event)) {
 - TreePath anchor = tree.getAnchorSelectionPath();
 - int anchorRow = (anchor == null) ? -1 : tree.getRowForPath(anchor);
 - if (anchorRow == -1 || tree.getSelectionModel().
 - getSelectionMode() == TreeSelectionModel.
 - SINGLE_TREE_SELECTION) {
 - tree.setSelectionPath(path);
 - }
 - else {
 - int row = getRowForPath(tree, path);
 - TreePath lastAnchorPath = anchor;
 - if (row < anchorRow) {
 - tree.setSelectionInterval(row, anchorRow);
 - }
 - else {
 - tree.setSelectionInterval(anchorRow, row);
 - }
 - tree.setAnchorSelectionPath(lastAnchorPath);
 - tree.setLeadSelectionPath(path);
 - }
 - }
 - /* Otherwise set the selection to just this interval. */
 - else if(SynthLookAndFeel.isPrimaryMouseButton(event)) {
 - tree.setSelectionPath(path);
 - if(isToggleEvent(event)) {
 - toggleExpandState(path);
 - }
 - }
 - }
 - /**
 - * Updates the lead row.
 - */
 - private void updateLeadRow() {
 - leadRow = tree.getLeadSelectionRow();
 - }
 - /**
 - * Returns the lead selection row. This is cached as painting makes
 - * extensive use of this.
 - */
 - private int getLeadSelectionRow() {
 - return leadRow;
 - }
 - /**
 - * Invokes <code>repaint</code> on the JTree for the passed in TreePath,
 - * <code>path</code>.
 - */
 - private void repaintPath(TreePath path) {
 - if (path != null) {
 - Rectangle bounds = tree.getPathBounds(path);
 - if (bounds != null) {
 - tree.repaint(bounds.x, bounds.y, bounds.width, bounds.height);
 - }
 - }
 - }
 - /**
 - * Updates the TreeState in response to nodes expanding/collapsing.
 - */
 - private static class TreeExpansionHandler implements
 - TreeExpansionListener {
 - /**
 - * Called whenever an item in the tree has been expanded.
 - */
 - public void treeExpanded(TreeExpansionEvent event) {
 - JTree tree = (JTree)event.getSource();
 - // PENDING: needs to be updated.
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - TreePath path = event.getPath();
 - ui.updateExpandedDescendants(path);
 - }
 - /**
 - * Called whenever an item in the tree has been collapsed.
 - */
 - public void treeCollapsed(TreeExpansionEvent event) {
 - JTree tree = (JTree)event.getSource();
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - TreePath path = event.getPath();
 - ui.completeEditing();
 - if (path != null && tree.isVisible(path)) {
 - ui.treeState.setExpandedState(path, false);
 - ui.updateLeadRow();
 - ui.invalidateSize();
 - }
 - }
 - }
 - /**
 - * Updates the preferred size when scrolling (if necessary). This class
 - * is used when FixedHeightLayoutCache is used by SynthTreeUI. Because
 - * FixedHeightLayoutCache only returns the preferred width of the visible
 - * paths, you need to revalidate on every move otherwise certain regions
 - * may not be visible. This class does this.
 - */
 - private static class ComponentHandler extends ComponentAdapter implements
 - ActionListener {
 - /**
 - * Timer used when inside a scrollpane and the scrollbar is
 - * adjusting.
 - */
 - private javax.swing.Timer timer;
 - /**
 - * ScrollBar that is being adjusted.
 - */
 - private JScrollBar scrollBar;
 - /**
 - * Last SynthTreeUI that we were in.
 - */
 - private SynthTreeUI ui;
 - public void componentMoved(ComponentEvent e) {
 - JTree tree = (JTree)e.getSource();
 - // PENDING: change me
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - if (this.ui != ui) {
 - adjust();
 - }
 - if (timer == null) {
 - JScrollPane scrollPane = (JScrollPane)SwingUtilities.
 - getAncestorOfClass(JScrollPane.class, tree);
 - if (scrollPane == null) {
 - ui.invalidateSize();
 - }
 - else {
 - JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
 - if (scrollBar == null || !scrollBar.getValueIsAdjusting()){
 - // Try the horizontal scrollbar.
 - if((scrollBar = scrollPane.getHorizontalScrollBar())
 - != null && scrollBar.getValueIsAdjusting()) {
 - queue(ui, scrollBar);
 - }
 - else {
 - ui.invalidateSize();
 - }
 - }
 - else {
 - queue(ui, scrollBar);
 - }
 - }
 - }
 - }
 - /**
 - * Creates, if necessary, and starts a Timer to check if need to
 - * resize the bounds.
 - */
 - private void queue(SynthTreeUI ui, JScrollBar bar) {
 - if (timer == null) {
 - timer = new javax.swing.Timer(200, this);
 - timer.setRepeats(true);
 - }
 - timer.start();
 - this.ui = ui;
 - this.scrollBar = bar;
 - }
 - /**
 - * Public as a result of Timer. If the scrollBar is null, or
 - * not adjusting, this stops the timer and updates the sizing.
 - */
 - public void actionPerformed(ActionEvent ae) {
 - if (!scrollBar.getValueIsAdjusting()) {
 - adjust();
 - }
 - }
 - /**
 - * Stops the timer and schedules a repaint/revalidate on the tree.
 - */
 - private void adjust() {
 - if (timer != null) {
 - timer.stop();
 - }
 - ui.invalidateSize();
 - timer = null;
 - scrollBar = null;
 - ui = null;
 - }
 - }
 - private class TreeExpandAction extends AbstractAction {
 - public void actionPerformed(ActionEvent e) {
 - int selRow = getLeadSelectionRow();
 - tree.expandRow(selRow);
 - }
 - }
 - private class TreeCollapseAction extends AbstractAction {
 - public void actionPerformed(ActionEvent e) {
 - int selRow = getLeadSelectionRow();
 - tree.collapseRow(selRow);
 - }
 - }
 - private class TreeMoveSelectionToParentAction extends AbstractAction {
 - public void actionPerformed(ActionEvent e) {
 - int selRow = getLeadSelectionRow();
 - TreePath path = getPathForRow(tree, selRow);
 - if (path != null && path.getPathCount() > 1) {
 - int newIndex = getRowForPath(tree, path.getParentPath());
 - if (newIndex != -1) {
 - tree.setSelectionInterval(newIndex, newIndex);
 - ensureRowsAreVisible(tree, newIndex, newIndex);
 - }
 - }
 - }
 - }
 - /**
 - * Forwards all TreeModel events to the TreeState.
 - */
 - private class TreeModelHandler implements TreeModelListener {
 - public void treeNodesChanged(TreeModelEvent e) {
 - if (treeState != null && e != null) {
 - treeState.treeNodesChanged(e);
 - TreePath pPath = e.getTreePath().getParentPath();
 - if (pPath == null || treeState.isExpanded(pPath)) {
 - invalidateSize();
 - }
 - }
 - }
 - public void treeNodesInserted(TreeModelEvent e) {
 - if (treeState != null && e != null) {
 - treeState.treeNodesInserted(e);
 - updateLeadRow();
 - TreePath path = e.getTreePath();
 - if (treeState.isExpanded(path)) {
 - invalidateSize();
 - }
 - else {
 - // PENDING(sky): Need a method in TreeModelEvent
 - // that can return the count, getChildIndices allocs
 - // a new array!
 - int[] indices = e.getChildIndices();
 - int childCount = tree.getModel().getChildCount
 - (path.getLastPathComponent());
 - if (indices != null && (childCount - indices.length) == 0){
 - invalidateSize();
 - }
 - }
 - }
 - }
 - public void treeNodesRemoved(TreeModelEvent e) {
 - if (treeState != null && e != null) {
 - treeState.treeNodesRemoved(e);
 - updateLeadRow();
 - TreePath path = e.getTreePath();
 - if (treeState.isExpanded(path) || tree.getModel().
 - getChildCount(path.getLastPathComponent()) == 0) {
 - invalidateSize();
 - }
 - }
 - }
 - public void treeStructureChanged(TreeModelEvent e) {
 - if (treeState != null && e != null) {
 - treeState.treeStructureChanged(e);
 - updateLeadRow();
 - TreePath pPath = e.getTreePath();
 - if (pPath != null) {
 - pPath = pPath.getParentPath();
 - }
 - if(pPath == null || treeState.isExpanded(pPath)) {
 - invalidateSize();
 - }
 - }
 - }
 - }
 - /**
 - * Listens for changes in the selection model and updates the display
 - * accordingly.
 - */
 - private class TreeSelectionHandler implements TreeSelectionListener {
 - /**
 - * Messaged when the selection changes in the tree we're displaying
 - * for. Stops editing, messages super and displays the changed paths.
 - */
 - public void valueChanged(TreeSelectionEvent event) {
 - // Stop editing
 - if (stopEditingWhenSelectionChanges) {
 - completeEditing();
 - }
 - // Make sure all the paths are visible, if necessary.
 - TreeSelectionModel model = tree.getSelectionModel();
 - TreeModel treeModel = tree.getModel();
 - if (tree.getExpandsSelectedPaths()) {
 - TreePath[] paths = model.getSelectionPaths();
 - if (paths != null) {
 - for(int counter = paths.length - 1; counter >= 0;
 - counter--) {
 - TreePath path = paths[counter].getParentPath();
 - boolean expand = true;
 - while (path != null) {
 - // Indicates this path isn't valid anymore,
 - // we shouldn't attempt to expand it then.
 - if (treeModel != null && treeModel.isLeaf(
 - path.getLastPathComponent())){
 - expand = false;
 - path = null;
 - }
 - else {
 - path = path.getParentPath();
 - }
 - }
 - if (expand) {
 - tree.makeVisible(paths[counter]);
 - }
 - }
 - }
 - }
 - TreePath oldLead = tree.getLeadSelectionPath();
 - TreePath lead = tree.getSelectionModel().getLeadSelectionPath();
 - tree.setAnchorSelectionPath(lead);
 - tree.setLeadSelectionPath(lead);
 - TreePath[] changedPaths = event.getPaths();
 - Rectangle nodeBounds;
 - Rectangle visRect = tree.getVisibleRect();
 - boolean paintPaths = true;
 - int nWidth = tree.getWidth();
 - if (changedPaths != null) {
 - int counter, maxCounter = changedPaths.length;
 - if (maxCounter > 4) {
 - tree.repaint();
 - paintPaths = false;
 - }
 - else {
 - for (counter = 0; counter < maxCounter; counter++) {
 - nodeBounds = getPathBounds(tree,
 - changedPaths[counter]);
 - if (nodeBounds != null && visRect.
 - intersects(nodeBounds)) {
 - tree.repaint(0, nodeBounds.y, nWidth,
 - nodeBounds.height);
 - }
 - }
 - }
 - }
 - if (paintPaths) {
 - nodeBounds = getPathBounds(tree, oldLead);
 - if (nodeBounds != null && visRect.intersects(nodeBounds)) {
 - tree.repaint(0, nodeBounds.y, nWidth, nodeBounds.height);
 - }
 - nodeBounds = getPathBounds(tree, lead);
 - if(nodeBounds != null && visRect.intersects(nodeBounds)) {
 - tree.repaint(0, nodeBounds.y, nWidth, nodeBounds.height);
 - }
 - }
 - }
 - }
 - /**
 - * Listener responsible for getting cell editing events and updating
 - * the tree accordingly.
 - */
 - class CellEditorHandler implements CellEditorListener {
 - /** Messaged when editing has stopped in the tree. */
 - public void editingStopped(ChangeEvent e) {
 - completeEditing(false, false, true);
 - }
 - /** Messaged when editing has been canceled in the tree. */
 - public void editingCanceled(ChangeEvent e) {
 - completeEditing(false, false, false);
 - }
 - }
 - /**
 - * This class is used to handle selecting nodes based on a typed
 - * sequence.
 - */
 - private static class KeyHandler extends KeyAdapter {
 - public void keyTyped(KeyEvent e) {
 - JTree tree = (JTree)e.getSource();
 - if (e.isAltDown() || e.isControlDown() || e.isMetaDown()) {
 - return;
 - }
 - // handle first letter navigation
 - if(tree != null && tree.getRowCount() > 0 && tree.hasFocus() &&
 - tree.isEnabled()) {
 - boolean startingFromSelection = true;
 - String prefix = Character.toString(e.getKeyChar());
 - int startingRow = tree.getMinSelectionRow() + 1;
 - if (startingRow >= tree.getRowCount()) {
 - startingFromSelection = false;
 - startingRow = 0;
 - }
 - TreePath path = tree.getNextMatch(prefix, startingRow,
 - Position.Bias.Forward);
 - if (path != null) {
 - tree.setSelectionPath(path);
 - }
 - else if (startingFromSelection) {
 - path = tree.getNextMatch(prefix, 0,
 - Position.Bias.Forward);
 - if (path != null) {
 - tree.setSelectionPath(path);
 - }
 - }
 - }
 - }
 - }
 - /**
 - * Repaints the lead selection row when focus is lost/gained.
 - */
 - private static class FocusHandler implements FocusListener {
 - /**
 - * Invoked when focus is activated on the tree we're in, redraws the
 - * lead row.
 - */
 - public void focusGained(FocusEvent e) {
 - paintLead((JTree)e.getSource());
 - }
 - /**
 - * Invoked when focus is activated on the tree we're in, redraws the
 - * lead row.
 - */
 - public void focusLost(FocusEvent e) {
 - paintLead((JTree)e.getSource());
 - }
 - /**
 - * Pains the lead selection of the tree.
 - */
 - private void paintLead(JTree tree) {
 - Rectangle bounds;
 - bounds = tree.getPathBounds(tree.getLeadSelectionPath());
 - if (bounds != null) {
 - tree.repaint(bounds);
 - }
 - }
 - }
 - /**
 - * Class responsible for getting size of node
 - */
 - // This returns locations that don't include any Insets.
 - private class NodeDimensionsHandler extends
 - AbstractLayoutCache.NodeDimensions {
 - /**
 - * Responsible for getting the size of a particular node. Returned
 - * location does not include insets, that is handled by SynthTreeUI.
 - */
 - public Rectangle getNodeDimensions(Object value, int row,
 - int depth, boolean expanded,
 - Rectangle size) {
 - // Return size of editing component, if editing and asking
 - // for editing row.
 - Component c = getEditingComponent();
 - int editingRow = getEditingRow();
 - if (c != null && editingRow == row) {
 - Dimension prefSize = c.getPreferredSize();
 - int rh = tree.getRowHeight();
 - if (rh > 0 && rh != prefSize.height) {
 - prefSize.height = rh;
 - }
 - if (size != null) {
 - size.x = getRowX(row, depth);
 - size.width = prefSize.width;
 - size.height = prefSize.height;
 - }
 - else {
 - size = new Rectangle(getRowX(row, depth), 0,
 - prefSize.width, prefSize.height);
 - }
 - return size;
 - }
 - // Not editing, use renderer.
 - TreeCellRenderer renderer = tree.getCellRenderer();
 - if (renderer != null) {
 - c = renderer.getTreeCellRendererComponent
 - (tree, value, tree.isRowSelected(row),
 - expanded, tree.getModel().isLeaf(value), row,
 - false);
 - rendererPane.add(c);
 - c.validate();
 - Dimension prefSize = c.getPreferredSize();
 - if (size != null) {
 - size.x = getRowX(row, depth);
 - size.width = prefSize.width;
 - size.height = prefSize.height;
 - }
 - else {
 - size = new Rectangle(getRowX(row, depth), 0,
 - prefSize.width, prefSize.height);
 - }
 - return size;
 - }
 - return null;
 - }
 - }
 - /**
 - * TreeMouseListener is responsible for updating the selection
 - * based on mouse events, it will also redispatch events to the editing
 - * component.
 - */
 - private static class MouseHandler extends MouseAdapter implements
 - MouseMotionListener {
 - /**
 - * Indicates if in the process of doing a drag and drop session.
 - * This affects how the selection will be changed.
 - */
 - private boolean inDND;
 - /**
 - * Destination Component that events are dispatched to.
 - */
 - private Component destination;
 - /**
 - * Invoked when a mouse button has been pressed on a component.
 - */
 - public void mousePressed(MouseEvent e) {
 - if (!e.isConsumed()) {
 - handleSelection(e);
 - redispatchEventIfNecessary(e);
 - inDND = false;
 - }
 - else {
 - inDND = true;
 - }
 - }
 - /**
 - * Updates the selection as necessary based on the MoueEvent.
 - */
 - private void handleSelection(MouseEvent e) {
 - JTree tree = (JTree)e.getSource();
 - // PENDING: Change to new getUI method
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - if (tree != null && tree.isEnabled()) {
 - if (tree.isEditing() && tree.getInvokesStopCellEditing() &&
 - !tree.stopEditing()) {
 - return;
 - }
 - if (tree.isRequestFocusEnabled()) {
 - tree.requestFocus();
 - }
 - TreePath path = tree.getClosestPathForLocation(e.getX(),
 - e.getY());
 - if (path != null) {
 - Rectangle bounds = tree.getPathBounds(path);
 - if (e.getY() > (bounds.y + bounds.height)) {
 - return;
 - }
 - if (SynthLookAndFeel.isPrimaryMouseButton(e)) {
 - SynthContext context = ui.getContext(tree);
 - ui.expandPathIfNecessary(context, path, e.getX(),
 - e.getY());
 - context.dispose();
 - }
 - int x = e.getX();
 - if (x > bounds.x && x <= (bounds.x + bounds.width) &&
 - !ui.startEditing(path, e)) {
 - ui.selectPathForEvent(path, e);
 - }
 - }
 - }
 - cacheDestination(ui.getEditingComponent(), e.getX(), e.getY());
 - }
 - public void mouseDragged(MouseEvent e) {
 - redispatchEventIfNecessary(e);
 - }
 - /**
 - * Invoked when the mouse button has been moved on a component
 - * (with no buttons no down).
 - */
 - public void mouseMoved(MouseEvent e) {
 - }
 - public void mouseReleased(MouseEvent e) {
 - if (!e.isConsumed() && inDND) {
 - handleSelection(e);
 - redispatchEventIfNecessary(e);
 - }
 - }
 - /**
 - * Caches the component used to redirect events to.
 - */
 - private void cacheDestination(Component editingComponent, int x,
 - int y) {
 - if (editingComponent != null) {
 - destination = SwingUtilities.getDeepestComponentAt(
 - editingComponent, x, y);
 - }
 - else {
 - destination = null;
 - }
 - }
 - /**
 - * Dispatches the MouseEvent to the current destination.
 - */
 - private void redispatchEventIfNecessary(MouseEvent e) {
 - if (destination != null) {
 - JTree tree = (JTree)e.getSource();
 - destination.dispatchEvent(SwingUtilities.convertMouseEvent
 - (tree, e, destination));
 - }
 - }
 - }
 - //
 - // Actions used for keyboard navigation
 - //
 - private abstract static class GenericTreeAction extends AbstractAction {
 - /**
 - * Specifies the direction to adjust the selection by, intepretation of
 - * this is left to subclasses.
 - */
 - protected int direction;
 - /**
 - * True indicates should set selection from anchor path.
 - */
 - protected boolean addToSelection;
 - /**
 - * True indicates the selection should be reset.
 - */
 - protected boolean changeSelection;
 - GenericTreeAction(String name) {
 - super(name);
 - }
 - GenericTreeAction(String name, int direction, boolean addToSelection,
 - boolean changeSelection) {
 - super(name);
 - this.direction = direction;
 - this.addToSelection = addToSelection;
 - this.changeSelection = changeSelection;
 - }
 - public void actionPerformed(ActionEvent e) {
 - JTree tree = (JTree)e.getSource();
 - int rowCount = tree.getRowCount();
 - if (rowCount > 0) {
 - actionPerformed(e, tree, rowCount);
 - }
 - }
 - protected abstract void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount);
 - protected void adjustSelection(JTree tree, TreePath path) {
 - if (addToSelection) {
 - extendSelection(tree, path);
 - }
 - else if(changeSelection) {
 - tree.setSelectionPath(path);
 - }
 - else {
 - tree.setLeadSelectionPath(path);
 - }
 - }
 - /**
 - * Extends the selection from the anchor to make <code>newLead</code>
 - * the lead of the selection. This does not scroll.
 - */
 - private void extendSelection(JTree tree, TreePath newLead) {
 - TreePath aPath = tree.getAnchorSelectionPath();
 - int aRow = (aPath == null) ? -1 : tree.getRowForPath(aPath);
 - int newIndex = tree.getRowForPath(newLead);
 - if(aRow == -1) {
 - tree.setSelectionRow(newIndex);
 - }
 - else {
 - if (aRow < newIndex) {
 - tree.setSelectionInterval(aRow, newIndex);
 - }
 - else {
 - tree.setSelectionInterval(newIndex, aRow);
 - }
 - tree.setAnchorSelectionPath(aPath);
 - tree.setLeadSelectionPath(newLead);
 - }
 - }
 - }
 - /**
 - * <code>TraverseAction</code> is the action used for left/right keys.
 - * Will toggle the expandedness of a node, as well as potentially
 - * incrementing the selection.
 - */
 - private static class TraverseAction extends GenericTreeAction {
 - TraverseAction(String name, int direction, boolean changeSelection) {
 - super(name, direction, false, changeSelection);
 - }
 - protected void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount) {
 - int minSelIndex = tree.getLeadSelectionRow();
 - int newIndex;
 - TreeModel model = tree.getModel();
 - if (minSelIndex == -1) {
 - newIndex = 0;
 - }
 - else {
 - // PENDING: needs to be updated.
 - SynthTreeUI ui = (SynthTreeUI)tree.getUI();
 - TreePath path = tree.getPathForRow(minSelIndex);
 - // Try and expand the node, otherwise go to next
 - // node.
 - if (direction == 1) {
 - if (!model.isLeaf(path.getLastPathComponent()) &&
 - !tree.isExpanded(minSelIndex)) {
 - ui.toggleExpandState(path);
 - newIndex = -1;
 - }
 - else {
 - newIndex = Math.min(minSelIndex + 1, rowCount - 1);
 - }
 - }
 - // Try to collapse node.
 - else {
 - if (!model.isLeaf(path.getLastPathComponent()) &&
 - tree.isExpanded(minSelIndex)) {
 - ui.toggleExpandState(tree.getPathForRow(minSelIndex));
 - newIndex = -1;
 - }
 - else {
 - path = tree.getPathForRow(minSelIndex);
 - if (path != null && path.getPathCount() > 1) {
 - newIndex = tree.getRowForPath(
 - path.getParentPath());
 - }
 - else {
 - newIndex = -1;
 - }
 - }
 - }
 - }
 - if (newIndex != -1) {
 - if (changeSelection) {
 - tree.setSelectionInterval(newIndex, newIndex);
 - }
 - else {
 - tree.setLeadSelectionPath(tree.getPathForRow(newIndex));
 - }
 - ensureRowsAreVisible(tree, newIndex, newIndex);
 - }
 - }
 - }
 - /**
 - * ScrollAction handles scrolling left/right/up/down and changing
 - * the selection.
 - */
 - private static class ScrollAndSelectAction extends GenericTreeAction {
 - private ScrollAndSelectAction(String name, int direction,
 - boolean
 - addToSelection, boolean changeSelection){
 - super(name, direction, addToSelection, changeSelection);
 - }
 - protected void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount) {
 - Dimension maxSize = tree.getSize();
 - TreePath lead = tree.getLeadSelectionPath();
 - TreePath newPath = null;
 - Rectangle visRect = tree.getVisibleRect();
 - Rectangle newRect;
 - switch(direction) {
 - case SwingConstants.NORTH:
 - // up.
 - newPath = tree.getClosestPathForLocation(visRect.x, visRect.y);
 - if (newPath.equals(lead)) {
 - visRect.y = Math.max(0, visRect.y - visRect.height);
 - newPath = tree.getClosestPathForLocation(visRect.x,
 - visRect.y);
 - }
 - newRect = tree.getPathBounds(newPath);
 - visRect.y = newRect.y;
 - break;
 - case SwingConstants.SOUTH:
 - // down
 - visRect.y = Math.min(maxSize.height, visRect.y +
 - visRect.height - 1);
 - newPath = tree.getClosestPathForLocation(visRect.x, visRect.y);
 - if (newPath.equals(lead)) {
 - visRect.y = Math.min(maxSize.height, visRect.y +
 - visRect.height - 1);
 - newPath = tree.getClosestPathForLocation(visRect.x,
 - visRect.y);
 - }
 - newRect = tree.getPathBounds(newPath);
 - visRect.y = newRect.y - (visRect.height - newRect.height);
 - break;
 - case SwingConstants.WEST:
 - newPath = tree.getClosestPathForLocation(visRect.x, visRect.y);
 - visRect.x = Math.max(0, visRect.x - visRect.width);
 - break;
 - case SwingConstants.EAST:
 - visRect.x = Math.min(Math.max(0, tree.getWidth() -
 - visRect.width), visRect.x + visRect.width);
 - newPath = tree.getClosestPathForLocation(visRect.x,
 - visRect.y + visRect.height);
 - break;
 - }
 - adjustSelection(tree, newPath);
 - tree.scrollRectToVisible(visRect);
 - }
 - }
 - /**
 - * Moves the selection up/down.
 - */
 - private static class IncrementAction extends GenericTreeAction {
 - IncrementAction(String name, int direction, boolean addToSelection,
 - boolean changeSelection) {
 - super(name);
 - this.direction = direction;
 - this.addToSelection = addToSelection;
 - this.changeSelection = changeSelection;
 - }
 - protected void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount) {
 - int selIndex = tree.getLeadSelectionRow();
 - int newIndex;
 - TreeSelectionModel selectionModel = tree.getSelectionModel();
 - if (selIndex == -1) {
 - if (direction == 1) {
 - newIndex = 0;
 - }
 - else {
 - newIndex = rowCount - 1;
 - }
 - }
 - else {
 - // Aparently people don't like wrapping;(
 - newIndex = Math.min(rowCount - 1, Math.max
 - (0, (selIndex + direction)));
 - }
 - adjustSelection(tree, tree.getPathForRow(newIndex));
 - ensureRowsAreVisible(tree, newIndex, newIndex);
 - }
 - }
 - /**
 - * HomeAction is used to handle end/home actions.
 - * Scrolls either the first or last cell to be visible based on
 - * direction.
 - */
 - private static class HomeAction extends GenericTreeAction {
 - HomeAction(String name, int direction, boolean addToSelection,
 - boolean changeSelection) {
 - super(name, direction, addToSelection, changeSelection);
 - }
 - protected void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount) {
 - if (direction == -1) {
 - ensureRowsAreVisible(tree, 0, 0);
 - if (addToSelection) {
 - TreePath aPath = tree.getAnchorSelectionPath();
 - int aRow = (aPath == null) ? -1 :tree.getRowForPath(aPath);
 - if (aRow == -1) {
 - tree.setSelectionInterval(0, 0);
 - }
 - else {
 - tree.setSelectionInterval(0, aRow);
 - tree.setAnchorSelectionPath(aPath);
 - tree.setLeadSelectionPath(tree.getPathForRow(0));
 - }
 - }
 - else if (changeSelection) {
 - tree.setSelectionInterval(0, 0);
 - }
 - else {
 - tree.setLeadSelectionPath(tree.getPathForRow(0));
 - }
 - }
 - else {
 - ensureRowsAreVisible(tree, rowCount - 1, rowCount - 1);
 - if (addToSelection) {
 - TreePath aPath = tree.getAnchorSelectionPath();
 - int aRow = (aPath == null) ? -1 :
 - tree.getRowForPath(aPath);
 - if (aRow == -1) {
 - tree.setSelectionInterval(rowCount - 1, rowCount -1);
 - }
 - else {
 - tree.setSelectionInterval(aRow, rowCount - 1);
 - tree.setAnchorSelectionPath(aPath);
 - tree.setLeadSelectionPath(tree.getPathForRow(
 - rowCount -1));
 - }
 - }
 - else if (changeSelection) {
 - tree.setSelectionInterval(rowCount - 1, rowCount - 1);
 - }
 - else {
 - tree.setLeadSelectionPath(tree.getPathForRow(
 - rowCount - 1));
 - }
 - }
 - }
 - }
 - /**
 - * Toggles the expanded state of the first row.
 - */
 - private static class ToggleAction extends GenericTreeAction {
 - ToggleAction(String name) {
 - super(name);
 - }
 - protected void actionPerformed(ActionEvent e, JTree tree,
 - int rowCount) {
 - int selRow = tree.getLeadSelectionRow();
 - if (selRow != -1) {
 - TreePath path = tree.getPathForRow(selRow);
 - if (!tree.getModel().isLeaf(path.getLastPathComponent())) {
 - TreePath aPath = tree.getAnchorSelectionPath();
 - TreePath lPath = tree.getLeadSelectionPath();
 - // PENDING:
 - ((SynthTreeUI)tree.getUI()).toggleExpandState(path);
 - tree.setAnchorSelectionPath(aPath);
 - tree.setLeadSelectionPath(lPath);
 - }
 - }
 - }
 - }
 - /**
 - * Scrolls the component it is created with a specified amount.
 - */
 - private static class ScrollAction extends AbstractAction {
 - /**
 - * Direction to scroll.
 - */
 - private int direction;
 - /**
 - * Amount to scroll.
 - */
 - private int amount;
 - public ScrollAction(String name, int direction, int amount) {
 - super(name);
 - this.direction = direction;
 - this.amount = amount;
 - }
 - public void actionPerformed(ActionEvent e) {
 - JComponent component = (JComponent)e.getSource();
 - Rectangle visRect = component.getVisibleRect();
 - Dimension size = component.getSize();
 - if (direction == SwingConstants.HORIZONTAL) {
 - visRect.x += amount;
 - visRect.x = Math.max(0, visRect.x);
 - visRect.x = Math.min(Math.max(0, size.width - visRect.width),
 - visRect.x);
 - }
 - else {
 - visRect.y += amount;
 - visRect.y = Math.max(0, visRect.y);
 - visRect.y = Math.min(Math.max(0, size.width - visRect.height),
 - visRect.y);
 - }
 - component.scrollRectToVisible(visRect);
 - }
 - }
 - /**
 - * ActionListener that invokes cancelEditing when action performed.
 - */
 - // PENDING: Make this static when isEnabled can be changed.
 - private class CancelEditingAction extends AbstractAction {
 - public CancelEditingAction(String name) {
 - super(name);
 - }
 - public void actionPerformed(ActionEvent e) {
 - if (tree != null) {
 - tree.cancelEditing();
 - }
 - }
 - // PENDING: Need an isEnabled that takes a Component
 - public boolean isEnabled() { return (tree != null &&
 - tree.isEnabled() &&
 - isEditing(tree)); }
 - }
 - /**
 - * ActionListener invoked to start editing on the leadPath.
 - */
 - private static class EditAction extends GenericTreeAction {
 - public EditAction(String name) {
 - super(name);
 - }
 - protected void actionPerformed(ActionEvent ae, JTree tree,
 - int rowCount) {
 - TreePath path = tree.getLeadSelectionPath();
 - if (path != null) {
 - tree.startEditingAtPath(path);
 - }
 - }
 - }
 - /**
 - * Action to select everything in tree.
 - */
 - private static class SelectAllAction extends GenericTreeAction {
 - /**
 - * If true, everything is selected, if false, the selection is cleared.
 - */
 - private boolean selectAll;
 - public SelectAllAction(String name, boolean selectAll) {
 - super(name);
 - this.selectAll = selectAll;
 - }
 - protected void actionPerformed(ActionEvent ae, JTree tree,
 - int rowCount) {
 - if (selectAll) {
 - TreePath lastPath = tree.getLeadSelectionPath();
 - TreePath aPath = tree.getAnchorSelectionPath();
 - if (lastPath != null && !tree.isVisible(lastPath)) {
 - lastPath = null;
 - }
 - tree.setSelectionInterval(0, rowCount - 1);
 - if (lastPath != null) {
 - tree.setLeadSelectionPath(lastPath);
 - }
 - if (aPath != null && tree.isVisible(aPath)) {
 - tree.setAnchorSelectionPath(aPath);
 - }
 - else if (lastPath != null) {
 - tree.setAnchorSelectionPath(lastPath);
 - }
 - }
 - else {
 - TreePath lastPath = tree.getLeadSelectionPath();
 - TreePath aPath = tree.getAnchorSelectionPath();
 - tree.clearSelection();
 - tree.setAnchorSelectionPath(aPath);
 - tree.setLeadSelectionPath(lastPath);
 - }
 - }
 - }
 - /**
 - * Toggles the selection of the lead selected row.
 - */
 - private static class AddSelectionAction extends GenericTreeAction {
 - private boolean changeAnchor;
 - AddSelectionAction(String name, boolean changeAnchor) {
 - super(name);
 - this.changeAnchor = changeAnchor;
 - }
 - protected void actionPerformed(ActionEvent ae, JTree tree,
 - int rowCount) {
 - int lead = tree.getLeadSelectionRow();
 - TreePath aPath = tree.getAnchorSelectionPath();
 - TreePath lPath = tree.getLeadSelectionPath();
 - if (lead == -1) {
 - lead = 0;
 - }
 - if (!changeAnchor) {
 - if (tree.isRowSelected(lead)) {
 - tree.removeSelectionRow(lead);
 - tree.setLeadSelectionPath(lPath);
 - }
 - else {
 - tree.addSelectionRow(lead);
 - }
 - tree.setAnchorSelectionPath(aPath);
 - }
 - else {
 - tree.setSelectionRow(lead);
 - }
 - }
 - }
 - /**
 - * Extends the selection from the anchor to the lead.
 - */
 - private static class ExtendSelectionAction extends GenericTreeAction {
 - ExtendSelectionAction(String name) {
 - super(name);
 - }
 - protected void actionPerformed(ActionEvent ae, JTree tree,
 - int rowCount) {
 - int lead = tree.getLeadSelectionRow();
 - if (lead != -1) {
 - TreePath leadP = tree.getLeadSelectionPath();
 - TreePath aPath = tree.getAnchorSelectionPath();
 - int aRow = tree.getRowForPath(aPath);
 - if (aRow == -1) {
 - aRow = 0;
 - }
 - tree.setSelectionInterval(aRow, lead);
 - tree.setLeadSelectionPath(leadP);
 - tree.setAnchorSelectionPath(aPath);
 - }
 - }
 - }
 - private static class SynthTreeCellEditor extends DefaultTreeCellEditor {
 - public SynthTreeCellEditor(JTree tree,
 - DefaultTreeCellRenderer renderer) {
 - super(tree, renderer);
 - setBorderSelectionColor(null);
 - }
 - protected TreeCellEditor createTreeCellEditor() {
 - // PENDING: should custom border be allowed from style?
 - JTextField tf = new JTextField();
 - tf.setName("Tree.cellEditor");
 - // PENDING: rethink this
 - ((SynthTextUI)tf.getUI()).forceFetchStyle(tf);
 - DefaultCellEditor editor = new DefaultCellEditor(tf);
 - // One click to edit.
 - editor.setClickCountToStart(1);
 - return editor;
 - }
 - }
 - /**
 - * Used to track the editing state.
 - */
 - private static class EditingState {
 - /**
 - * Component doing the editing.
 - */
 - public Component component;
 - /**
 - * Path being edited.
 - */
 - public TreePath path;
 - /**
 - * Row that is being edited.
 - */
 - public int row;
 - /**
 - * Indicates if the editor has a different size than the renderer.
 - */
 - public boolean editorHasDifferentSize;
 - /**
 - * The editor.
 - */
 - public CellEditor editor;
 - }
 - private class SynthTreeCellRenderer extends DefaultTreeCellRenderer
 - implements UIResource {
 - SynthTreeCellRenderer() {
 - setName("Tree.cellRenderer");
 - // PENDING: rethink this, we shouldn't have to force this.
 - ((SynthLabelUI)getUI()).forceFetchStyle(this);
 - }
 - public void paint(Graphics g) {
 - paintComponent(g);
 - if (hasFocus) {
 - SynthContext context = getContext(tree, Region.TREE_CELL);
 - if (context.getStyle() == null) {
 - assert false: "SynthTreeCellRenderer is being used " +
 - "outside of UI that created it";
 - return;
 - }
 - SynthPainter painter = (SynthPainter)context.getStyle().
 - get(context, "focus");
 - if (painter != null) {
 - int imageOffset = 0;
 - Icon currentI = getIcon();
 - if(currentI != null && getText() != null) {
 - imageOffset = currentI.getIconWidth() +
 - Math.max(0, getIconTextGap() - 1);
 - }
 - if (selected) {
 - context.setComponentState(ENABLED | SELECTED);
 - }
 - else {
 - context.setComponentState(ENABLED);
 - }
 - if(getComponentOrientation().isLeftToRight()) {
 - painter.paint(context, "focus", g, imageOffset, 0,
 - getWidth() - imageOffset, getHeight());
 - }
 - else {
 - painter.paint(context, "focus", g, 0, 0, getWidth() -
 - imageOffset, getHeight());
 - }
 - }
 - context.dispose();
 - }
 - }
 - }
 - /**
 - * Drag gesture recognizer for JTree components
 - */
 - static class TreeDragGestureRecognizer extends SynthDragGestureRecognizer {
 - /**
 - * Determines if the following are true:
 - * <ul>
 - * <li>the press event is located over a selection
 - * <li>the dragEnabled property is true
 - * <li>A TranferHandler is installed
 - * </ul>
 - * <p>
 - * This is implemented to check for a TransferHandler.
 - * Subclasses should perform the remaining conditions.
 - */
 - protected boolean isDragPossible(MouseEvent e) {
 - if (super.isDragPossible(e)) {
 - JTree tree = (JTree) this.getComponent(e);
 - if (tree.getDragEnabled()) {
 - TreeUI ui = tree.getUI();
 - TreePath path = ui.getClosestPathForLocation(tree, e.getX(),
 - e.getY());
 - if ((path != null) && tree.isPathSelected(path)) {
 - return true;
 - }
 - }
 - }
 - return false;
 - }
 - }
 - /**
 - * A DropTargetListener to extend the default Swing handling of drop operations
 - * by moving the tree selection to the nearest location to the mouse pointer.
 - * Also adds autoscroll capability.
 - */
 - static class TreeDropTargetListener extends SynthDropTargetListener {
 - /**
 - * called to save the state of a component in case it needs to
 - * be restored because a drop is not performed.
 - */
 - protected void saveComponentState(JComponent comp) {
 - JTree tree = (JTree) comp;
 - selectedIndices = tree.getSelectionRows();
 - }
 - /**
 - * called to restore the state of a component
 - * because a drop was not performed.
 - */
 - protected void restoreComponentState(JComponent comp) {
 - JTree tree = (JTree) comp;
 - tree.setSelectionRows(selectedIndices);
 - }
 - /**
 - * called to set the insertion location to match the current
 - * mouse pointer coordinates.
 - */
 - protected void updateInsertionLocation(JComponent comp, Point p) {
 - JTree tree = (JTree) comp;
 - TreeUI ui = tree.getUI();
 - TreePath path = ui.getClosestPathForLocation(tree, p.x, p.y);
 - if (path != null) {
 - tree.setSelectionPath(path);
 - }
 - }
 - private int[] selectedIndices;
 - }
 - static class TreeTransferHandler extends TransferHandler implements UIResource, Comparator {
 - private JTree tree;
 - /**
 - * Create a Transferable to use as the source for a data transfer.
 - *
 - * @param c The component holding the data to be transfered. This
 - * argument is provided to enable sharing of TransferHandlers by
 - * multiple components.
 - * @return The representation of the data to be transfered.
 - *
 - */
 - protected Transferable createTransferable(JComponent c) {
 - if (c instanceof JTree) {
 - tree = (JTree) c;
 - TreePath[] paths = tree.getSelectionPaths();
 - if (paths == null || paths.length == 0) {
 - return null;
 - }
 - StringBuffer plainBuf = new StringBuffer();
 - StringBuffer htmlBuf = new StringBuffer();
 - htmlBuf.append("<html>\n<body>\n<ul>\n");
 - TreeModel model = tree.getModel();
 - TreePath lastPath = null;
 - TreePath[] displayPaths = getDisplayOrderPaths(paths);
 - for (int i = 0; i < displayPaths.length; i++) {
 - TreePath path = displayPaths[i];
 - Object node = path.getLastPathComponent();
 - boolean leaf = model.isLeaf(node);
 - String label = getDisplayString(path, true, leaf);
 - plainBuf.append(label + "\n");
 - htmlBuf.append(" <li>" + label + "\n");
 - }
 - // remove the last newline
 - plainBuf.deleteCharAt(plainBuf.length() - 1);
 - htmlBuf.append("</ul>\n</body>\n</html>");
 - tree = null;
 - return new SynthTransferable(plainBuf.toString(), htmlBuf.toString());
 - }
 - return null;
 - }
 - public int compare(Object o1, Object o2) {
 - int row1 = tree.getRowForPath((TreePath)o1);
 - int row2 = tree.getRowForPath((TreePath)o2);
 - return row1 - row2;
 - }
 - String getDisplayString(TreePath path, boolean selected, boolean leaf) {
 - int row = tree.getRowForPath(path);
 - boolean hasFocus = tree.getLeadSelectionRow() == row;
 - Object node = path.getLastPathComponent();
 - return tree.convertValueToText(node, selected, tree.isExpanded(row),
 - leaf, row, hasFocus);
 - }
 - /**
 - * Selection paths are in selection order. The conversion to
 - * HTML requires display order. This method resorts the paths
 - * to be in the display order.
 - */
 - TreePath[] getDisplayOrderPaths(TreePath[] paths) {
 - // sort the paths to display order rather than selection order
 - ArrayList selOrder = new ArrayList();
 - for (int i = 0; i < paths.length; i++) {
 - selOrder.add(paths[i]);
 - }
 - Collections.sort(selOrder, this);
 - int n = selOrder.size();
 - TreePath[] displayPaths = new TreePath[n];
 - for (int i = 0; i < n; i++) {
 - displayPaths[i] = (TreePath) selOrder.get(i);
 - }
 - return displayPaths;
 - }
 - public int getSourceActions(JComponent c) {
 - return COPY;
 - }
 - }
 - } // End of class BasicTreeUI