001 /* 002 * Created on Mar 13, 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.Strings.concat; 019 020 import java.awt.Point; 021 import java.awt.Rectangle; 022 023 import javax.swing.table.JTableHeader; 024 025 import org.fest.swing.annotation.RunsInCurrentThread; 026 import org.fest.swing.exception.LocationUnavailableException; 027 import org.fest.swing.util.Pair; 028 import org.fest.swing.util.TextMatcher; 029 030 /** 031 * Understands the location of a <code>{@link JTableHeader}</code> (a coordinate, column index or value.) 032 * 033 * @author Yvonne Wang 034 * @author Alex Ruiz 035 */ 036 public class JTableHeaderLocation { 037 038 /** 039 * Returns the index and the coordinates of the column which name matches the value in the given 040 * <code>{@link TextMatcher}</code>. 041 * <p> 042 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 043 * responsible for calling this method from the EDT. 044 * </p> 045 * @param tableHeader the target <code>JTableHeader</code>. 046 * @param matcher indicates which is the matching column name. 047 * @return the index and the coordinates of the column under the given index. 048 * @throws LocationUnavailableException if a column with a matching value cannot be found. 049 */ 050 @RunsInCurrentThread 051 public Pair<Integer, Point> pointAt(JTableHeader tableHeader, TextMatcher matcher) { 052 int index = indexOf(tableHeader, matcher); 053 if (isValidIndex(tableHeader, index)) return new Pair<Integer, Point>(index, point(tableHeader, index)); 054 throw new LocationUnavailableException( 055 concat("Unable to find column with name matching ", matcher.description(), " ", matcher.formattedValues())); 056 } 057 058 @RunsInCurrentThread 059 private boolean isValidIndex(JTableHeader tableHeader, int index) { 060 int itemCount = columnCount(tableHeader); 061 return (index >= 0 && index < itemCount); 062 } 063 064 /** 065 * Returns the coordinates of the column under the given index. 066 * <p> 067 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 068 * responsible for calling this method from the EDT. 069 * </p> 070 * @param tableHeader the target <code>JTableHeader</code>. 071 * @param index the given index. 072 * @return the coordinates of the column under the given index. 073 * @throws IndexOutOfBoundsException if the index is out of bounds. 074 */ 075 @RunsInCurrentThread 076 public Point pointAt(JTableHeader tableHeader, int index) { 077 return point(tableHeader, validatedIndex(tableHeader, index)); 078 } 079 080 @RunsInCurrentThread 081 private static Point point(JTableHeader tableHeader, int index) { 082 Rectangle r = tableHeader.getHeaderRect(index); 083 return new Point(r.x + r.width / 2, r.y + r.height / 2); 084 } 085 086 @RunsInCurrentThread 087 private int validatedIndex(JTableHeader tableHeader, int index) { 088 int itemCount = columnCount(tableHeader); 089 if (index >= 0 && index < itemCount) return index; 090 throw new IndexOutOfBoundsException(concat( 091 "Item index (", valueOf(index), ") should be between [", valueOf(0), "] and [", valueOf(itemCount - 1), 092 "] (inclusive)")); 093 } 094 095 /** 096 * Returns the index of the column which name matches the value in the given <code>{@link TextMatcher}</code>, or -1 097 * if a matching column was not found. 098 * <p> 099 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are 100 * responsible for calling this method from the EDT. 101 * </p> 102 * @param tableHeader the target <code>JTableHeader</code>. 103 * @param matcher indicates which is the matching column name. 104 * @return the index of a matching column or -1 if a matching column was not found. 105 */ 106 @RunsInCurrentThread 107 public int indexOf(JTableHeader tableHeader, TextMatcher matcher) { 108 int size = columnCount(tableHeader); 109 for (int i = 0; i < size; i++) 110 if (matcher.isMatching(columnName(tableHeader, i))) return i; 111 return -1; 112 } 113 114 @RunsInCurrentThread 115 private int columnCount(JTableHeader header) { 116 return header.getColumnModel().getColumnCount(); 117 } 118 119 @RunsInCurrentThread 120 private String columnName(JTableHeader tableHeader, int index) { 121 return tableHeader.getTable().getModel().getColumnName(index); 122 } 123 }