001 /*
002 * Created on Jan 27, 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.swing.driver.JTabbedPaneTabIndexQuery.indexOfTab;
019 import static org.fest.util.Strings.concat;
020
021 import java.awt.Point;
022 import java.awt.Rectangle;
023
024 import javax.swing.JTabbedPane;
025
026 import org.fest.swing.annotation.RunsInCurrentThread;
027 import org.fest.swing.exception.LocationUnavailableException;
028 import org.fest.swing.util.StringTextMatcher;
029 import org.fest.swing.util.TextMatcher;
030 import org.fest.util.VisibleForTesting;
031
032 /**
033 * Understands a location on a <code>{@link JTabbedPane}</code> (notably a tab).
034 *
035 * @author Alex Ruiz
036 * @author Yvonne Wang
037 */
038 public class JTabbedPaneLocation {
039
040 /**
041 * Returns the index of the first tab that matches the given <code>String</code>.
042 * <p>
043 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
044 * responsible for calling this method from the EDT.
045 * </p>
046 * @param tabbedPane the target <code>JTabbedPane</code>.
047 * @param title the title to match.
048 * @return the index of the first tab that matches the given <code>String</code>.
049 * @throws LocationUnavailableException if a tab matching the given title could not be found.
050 */
051 @RunsInCurrentThread
052 public int indexOf(JTabbedPane tabbedPane, String title) {
053 return indexOf(tabbedPane, new StringTextMatcher(title));
054 }
055
056 /**
057 * Returns the index of the first tab whose title matches the value in the given <code>{@link TextMatcher}</code>.
058 * <p>
059 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
060 * responsible for calling this method from the EDT.
061 * </p>
062 * @param tabbedPane the target <code>JTabbedPane</code>.
063 * @param matcher indicates if the text of the <code>JTabbedPane</code> matches the value we are looking for.
064 * @return the index of the first tab that matches the given <code>String</code>.
065 * @throws LocationUnavailableException if a tab matching the given title could not be found.
066 */
067 @RunsInCurrentThread
068 public int indexOf(final JTabbedPane tabbedPane, final TextMatcher matcher) {
069 int index = indexOfTab(tabbedPane, matcher);
070 if (index >= 0) return index;
071 throw new LocationUnavailableException(concat(
072 "Unable to find a tab with title matching ", matcher.description(), " ", matcher.formattedValues()));
073 }
074
075 /**
076 * Returns the coordinates of the tab under the given index.
077 * <p>
078 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
079 * responsible for calling this method from the EDT.
080 * </p>
081 * @param tabbedPane the target <code>JTabbedPane</code>.
082 * @param index the given index.
083 * @return the coordinates of the tab under the given index.
084 * @throws IndexOutOfBoundsException if the given index is negative or out of bounds.
085 * @throws LocationUnavailableException if the tab under the given index is not visible.
086 */
087 @RunsInCurrentThread
088 public Point pointAt(final JTabbedPane tabbedPane, final int index) {
089 validateIndex(tabbedPane, index);
090 Rectangle rect = tabbedPane.getUI().getTabBounds(tabbedPane, index);
091 // From Abbot: TODO figure out the effects of tab layout policy sometimes tabs are not directly visible
092 if (rect == null || rect.x < 0)
093 throw new LocationUnavailableException(concat("The tab '", valueOf(index), "' is not visible"));
094 return new Point(rect.x + rect.width / 2, rect.y + rect.height / 2);
095 }
096
097 @VisibleForTesting
098 @RunsInCurrentThread
099 void validateIndex(JTabbedPane tabbedPane, int index) {
100 int max = tabbedPane.getTabCount() - 1;
101 if (index >= 0 && index <= max) return;
102 throw new IndexOutOfBoundsException(concat(
103 "Index <", valueOf(index), "> is not within the JTabbedPane bounds of <0> and <", valueOf(max), "> (inclusive)"));
104 }
105 }