001 /* 002 * Created on Jan 12, 2008 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2008-2010 the original author or authors. 014 */ 015 package org.fest.swing.driver; 016 017 import static java.lang.String.valueOf; 018 import static org.fest.util.Arrays.format; 019 import static org.fest.util.Strings.concat; 020 021 import java.awt.Point; 022 import java.awt.Rectangle; 023 024 import javax.swing.JTree; 025 import javax.swing.tree.TreePath; 026 027 import org.fest.swing.annotation.RunsInCurrentThread; 028 import org.fest.swing.exception.LocationUnavailableException; 029 import org.fest.swing.util.Pair; 030 031 /** 032 * Understands a visible location on a <code>{@link JTree}</code>. A row index or a <code>{@link String}</code>ified 033 * <code>{@link TreePath}</code> (i.e. each <code>{@link TreePath}</code> component is a <code>String</code>) or 034 * a <code>{@link TreePath}</code> of <code>Object</code> may be used to indicate the location. Note that if a 035 * <code>{@link TreePath}</code> is used, the entire path leading up to the designated node must be viewable at the 036 * time the location is used. 037 * 038 * @author Alex Ruiz 039 */ 040 public final class JTreeLocation { 041 042 /** 043 * Returns the bounds and visible coordinates of the given row. 044 * <p> 045 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 046 * responsible for calling this method from the EDT. 047 * </p> 048 * @param tree the target <code>JTree</code>. 049 * @param row the given row. 050 * @return the the bounds and visible coordinates of the given row. 051 * @throws IndexOutOfBoundsException if the given row is less than zero or equal than or greater than the number of 052 * visible rows in the <code>JTree</code>. 053 * @throws LocationUnavailableException if a tree path for the given row cannot be found. 054 * @since 1.2 055 */ 056 @RunsInCurrentThread 057 public Pair<Rectangle, Point> rowBoundsAndCoordinates(JTree tree, int row) { 058 Rectangle rowBounds = tree.getRowBounds(validIndex(tree, row)); 059 if (rowBounds != null) return new Pair<Rectangle, Point>(rowBounds, pointAt(rowBounds)); 060 throw new LocationUnavailableException(concat("The tree row ", row, " is not visible")); 061 } 062 063 /** 064 * Returns the path for the given row. 065 * <p> 066 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 067 * responsible for calling this method from the EDT. 068 * </p> 069 * @param tree the target <code>JTree</code>. 070 * @param row the given row. 071 * @return the path for the given row. 072 * @throws IndexOutOfBoundsException if the given row is less than zero or equal than or greater than the number of 073 * visible rows in the <code>JTree</code>. 074 * @throws LocationUnavailableException if a tree path for the given row cannot be found. 075 */ 076 @RunsInCurrentThread 077 public TreePath pathFor(JTree tree, int row) { 078 TreePath path = tree.getPathForRow(validIndex(tree, row)); 079 if (path != null) return path; 080 throw new LocationUnavailableException(concat("Unable to find tree path for row [", valueOf(row), "]")); 081 } 082 083 /** 084 * Validates that the given row index is valid. 085 * <p> 086 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 087 * responsible for calling this method from the EDT. 088 * </p> 089 * @param tree the target <code>JTree</code>. 090 * @param row the row index to validate. 091 * @return the validated row index. 092 * @throws IndexOutOfBoundsException if the given row is less than zero or equal than or greater than the number of 093 * visible rows in the <code>JTree</code>. 094 */ 095 @RunsInCurrentThread 096 public int validIndex(JTree tree, int row) { 097 int rowCount = tree.getRowCount(); 098 if (row >= 0 && row < rowCount) return row; 099 throw new IndexOutOfBoundsException(concat( 100 "The given row (", valueOf(row), ") should be greater than or equal to 0 and less than ", valueOf(rowCount))); 101 } 102 103 /** 104 * Returns the bounds and visible coordinates of the given path. 105 * <p> 106 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 107 * responsible for calling this method from the EDT. 108 * </p> 109 * @param tree the target <code>JTree</code>. 110 * @param path the given path. 111 * @return the bounds and visible coordinates of the given path. 112 * @throws LocationUnavailableException if any part of the path is not visible. 113 * @since 1.2 114 */ 115 @RunsInCurrentThread 116 public Pair<Rectangle, Point> pathBoundsAndCoordinates(JTree tree, TreePath path) { 117 Rectangle pathBounds = tree.getPathBounds(path); 118 if (pathBounds != null) return new Pair<Rectangle, Point>(pathBounds, pointAt(pathBounds)); 119 throw new LocationUnavailableException(concat("The tree path ", format(path.getPath()), " is not visible")); 120 } 121 122 private Point pointAt(Rectangle cellBounds) { 123 return new Point(cellBounds.x + cellBounds.width / 2, cellBounds.y + cellBounds.height / 2); 124 } 125 }