| /* |
| * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package javax.swing.plaf.metal; |
| |
| import javax.swing.*; |
| import javax.swing.event.*; |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.beans.*; |
| import java.io.*; |
| import java.util.*; |
| import javax.swing.plaf.*; |
| import javax.swing.tree.*; |
| |
| import javax.swing.plaf.basic.*; |
| |
| /** |
| * The metal look and feel implementation of <code>TreeUI</code>. |
| * <p> |
| * <code>MetalTreeUI</code> allows for configuring how to |
| * visually render the spacing and delineation between nodes. The following |
| * hints are supported: |
| * |
| * <table summary="Descriptions of supported hints: Angled, Horizontal, and None"> |
| * <tr> |
| * <th><p style="text-align:left">Angled</p></th> |
| * <td>A line is drawn connecting the child to the parent. For handling |
| * of the root node refer to |
| * {@link javax.swing.JTree#setRootVisible} and |
| * {@link javax.swing.JTree#setShowsRootHandles}. |
| * </td> |
| * </tr> |
| * <tr> |
| * <th><p style="text-align:left">Horizontal</p></th> |
| * <td>A horizontal line is drawn dividing the children of the root node.</td> |
| * </tr> |
| * <tr> |
| * <th><p style="text-align:left">None</p></th> |
| * <td>Do not draw any visual indication between nodes.</td> |
| * </tr> |
| * </table> |
| * |
| * <p> |
| * As it is typically impractical to obtain the <code>TreeUI</code> from |
| * the <code>JTree</code> and cast to an instance of <code>MetalTreeUI</code> |
| * you enable this property via the client property |
| * <code>JTree.lineStyle</code>. For example, to switch to |
| * <code>Horizontal</code> style you would do: |
| * <code>tree.putClientProperty("JTree.lineStyle", "Horizontal");</code> |
| * <p> |
| * The default is <code>Angled</code>. |
| * |
| * @author Tom Santos |
| * @author Steve Wilson (value add stuff) |
| */ |
| public class MetalTreeUI extends BasicTreeUI { |
| |
| private static Color lineColor; |
| |
| private static final String LINE_STYLE = "JTree.lineStyle"; |
| |
| private static final String LEG_LINE_STYLE_STRING = "Angled"; |
| private static final String HORIZ_STYLE_STRING = "Horizontal"; |
| private static final String NO_STYLE_STRING = "None"; |
| |
| private static final int LEG_LINE_STYLE = 2; |
| private static final int HORIZ_LINE_STYLE = 1; |
| private static final int NO_LINE_STYLE = 0; |
| |
| private int lineStyle = LEG_LINE_STYLE; |
| private PropertyChangeListener lineStyleListener = new LineListener(); |
| |
| /** |
| * Constructs the {@code MetalTreeUI}. |
| * |
| * @param x a component |
| * @return the instance of the {@code MetalTreeUI} |
| */ |
| public static ComponentUI createUI(JComponent x) { |
| return new MetalTreeUI(); |
| } |
| |
| /** |
| * Constructs the {@code MetalTreeUI}. |
| */ |
| public MetalTreeUI() { |
| super(); |
| } |
| |
| protected int getHorizontalLegBuffer() { |
| return 3; |
| } |
| |
| public void installUI( JComponent c ) { |
| super.installUI( c ); |
| lineColor = UIManager.getColor( "Tree.line" ); |
| |
| Object lineStyleFlag = c.getClientProperty( LINE_STYLE ); |
| decodeLineStyle(lineStyleFlag); |
| c.addPropertyChangeListener(lineStyleListener); |
| |
| } |
| |
| public void uninstallUI( JComponent c) { |
| c.removePropertyChangeListener(lineStyleListener); |
| super.uninstallUI(c); |
| } |
| |
| /** |
| * Converts between the string passed into the client property |
| * and the internal representation (currently and int) |
| * |
| * @param lineStyleFlag a flag |
| */ |
| protected void decodeLineStyle(Object lineStyleFlag) { |
| if ( lineStyleFlag == null || |
| lineStyleFlag.equals(LEG_LINE_STYLE_STRING)) { |
| lineStyle = LEG_LINE_STYLE; // default case |
| } else { |
| if ( lineStyleFlag.equals(NO_STYLE_STRING) ) { |
| lineStyle = NO_LINE_STYLE; |
| } else if ( lineStyleFlag.equals(HORIZ_STYLE_STRING) ) { |
| lineStyle = HORIZ_LINE_STYLE; |
| } |
| } |
| } |
| |
| /** |
| * Returns {@code true} if a point with X coordinate {@code mouseX} |
| * and Y coordinate {@code mouseY} is in expanded control. |
| * |
| * @param row a row |
| * @param rowLevel a row level |
| * @param mouseX X coordinate |
| * @param mouseY Y coordinate |
| * @return {@code true} if a point with X coordinate {@code mouseX} |
| * and Y coordinate {@code mouseY} is in expanded control. |
| */ |
| protected boolean isLocationInExpandControl(int row, int rowLevel, |
| int mouseX, int mouseY) { |
| if(tree != null && !isLeaf(row)) { |
| int boxWidth; |
| |
| if(getExpandedIcon() != null) |
| boxWidth = getExpandedIcon().getIconWidth() + 6; |
| else |
| boxWidth = 8; |
| |
| Insets i = tree.getInsets(); |
| int boxLeftX = (i != null) ? i.left : 0; |
| |
| |
| boxLeftX += (((rowLevel + depthOffset - 1) * totalChildIndent) + |
| getLeftChildIndent()) - boxWidth/2; |
| |
| int boxRightX = boxLeftX + boxWidth; |
| |
| return mouseX >= boxLeftX && mouseX <= boxRightX; |
| } |
| return false; |
| } |
| |
| public void paint(Graphics g, JComponent c) { |
| super.paint( g, c ); |
| |
| |
| // Paint the lines |
| if (lineStyle == HORIZ_LINE_STYLE && !largeModel) { |
| paintHorizontalSeparators(g,c); |
| } |
| } |
| |
| /** |
| * Paints the horizontal separators. |
| * |
| * @param g an instance of {@code Graphics} |
| * @param c a component |
| */ |
| protected void paintHorizontalSeparators(Graphics g, JComponent c) { |
| g.setColor( lineColor ); |
| |
| Rectangle clipBounds = g.getClipBounds(); |
| |
| int beginRow = getRowForPath(tree, getClosestPathForLocation |
| (tree, 0, clipBounds.y)); |
| int endRow = getRowForPath(tree, getClosestPathForLocation |
| (tree, 0, clipBounds.y + clipBounds.height - 1)); |
| |
| if ( beginRow <= -1 || endRow <= -1 ) { |
| return; |
| } |
| |
| for ( int i = beginRow; i <= endRow; ++i ) { |
| TreePath path = getPathForRow(tree, i); |
| |
| if(path != null && path.getPathCount() == 2) { |
| Rectangle rowBounds = getPathBounds(tree,getPathForRow |
| (tree, i)); |
| |
| // Draw a line at the top |
| if(rowBounds != null) |
| g.drawLine(clipBounds.x, rowBounds.y, |
| clipBounds.x + clipBounds.width, rowBounds.y); |
| } |
| } |
| |
| } |
| |
| protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, |
| Insets insets, TreePath path) { |
| if (lineStyle == LEG_LINE_STYLE) { |
| super.paintVerticalPartOfLeg(g, clipBounds, insets, path); |
| } |
| } |
| |
| protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, |
| Insets insets, Rectangle bounds, |
| TreePath path, int row, |
| boolean isExpanded, |
| boolean hasBeenExpanded, boolean |
| isLeaf) { |
| if (lineStyle == LEG_LINE_STYLE) { |
| super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, |
| path, row, isExpanded, |
| hasBeenExpanded, isLeaf); |
| } |
| } |
| |
| /** This class listens for changes in line style */ |
| class LineListener implements PropertyChangeListener { |
| public void propertyChange(PropertyChangeEvent e) { |
| String name = e.getPropertyName(); |
| if ( name.equals( LINE_STYLE ) ) { |
| decodeLineStyle(e.getNewValue()); |
| } |
| } |
| } // end class PaletteListener |
| |
| } |