package abbot.tester; import java.awt.*; import java.util.StringTokenizer; import javax.swing.JTabbedPane; import javax.swing.plaf.TabbedPaneUI; import com.windowtester.runtime.util.StringComparator; import abbot.Log; import abbot.Platform; import abbot.i18n.Strings; import abbot.util.ExtendedComparator; /** Provides encapsulation of a location on a JTabbedPane (notably a tab). Use the JTabbedPaneLocation#JTabbedPaneLocation(Point) ctor to indicate a specific coordinate. */ public class JTabbedPaneLocation extends ComponentLocation { private String tabName = null; private int index = -1; public JTabbedPaneLocation() { } public JTabbedPaneLocation(String tabName) { this.tabName = tabName; } public JTabbedPaneLocation(int index) { if (index < 0) { String msg = Strings.get("tester.JTabbedPane.invalid_index", new Object[] { new Integer(index) }); throw new LocationUnavailableException(msg); } this.index = index; } public JTabbedPaneLocation(Point p) { super(p); } protected String badFormat(String encoded) { return Strings.get("location.tab.bad_format", new Object[] { encoded }); } /** Convert the given row, col into a coordinate pair. */ private Point indexToPoint(JTabbedPane tabs, int index) { if (index < 0 || index >= tabs.getTabCount()) { String msg = Strings.get("tester.JTabbedPane.invalid_index", new Object[] { new Integer(index) }); throw new LocationUnavailableException(msg); } Log.debug("converting index " + index); TabbedPaneUI ui = tabs.getUI(); Rectangle rect = ui.getTabBounds(tabs, index); // TODO: figure out the effects of tab layout policy if (rect == null || rect.x < 0) { throw new TabNotVisibleException(index); } return new Point(rect.x + rect.width/2, rect.y + rect.height/2); } /** Return the row, col of the first object matching the given String. */ private int tabNameToIndex(JTabbedPane tabs, String name) { for (int i=0;i < tabs.getTabCount();i++) { String value = tabs.getTitleAt(i); if (StringComparator.matches(value, name)) return i; } return -1; } public Point getPoint(Component c) { JTabbedPane tabs = (JTabbedPane)c; int idx = index; if (tabName != null) { if ((idx = tabNameToIndex(tabs, tabName)) == -1) { String msg = Strings.get("tester.JTabbedPane.invalid_name", new Object[] { tabName }); throw new LocationUnavailableException(msg); } } if (idx != -1) { return indexToPoint(tabs, idx); } return super.getPoint(tabs); } public Rectangle getBounds(Component c) { JTabbedPane tabs = (JTabbedPane)c; TabbedPaneUI ui = tabs.getUI(); Point p = getPoint(tabs); int idx = ui.tabForCoordinate(tabs, p.x, p.y); return idx == -1 ? null : ui.getTabBounds(tabs, idx); } // FIXME if they correspond to the same tab, are they equal? public boolean equals(Object o) { if (o instanceof JTabbedPaneLocation) { JTabbedPaneLocation loc = (JTabbedPaneLocation)o; if (tabName != null) return tabName.equals(loc.tabName); if (index != -1) return index == loc.index; } return super.equals(o); } public String toString() { if (tabName != null) return encodeValue(tabName); if (index != -1) return encodeIndex(index); return super.toString(); } public ComponentLocation parse(String encoded) { encoded = encoded.trim(); if (isValue(encoded)) { tabName = parseValue(encoded); return this; } if (isIndex(encoded)) { index = parseIndex(encoded); return this; } return super.parse(encoded); } /** This exception is thrown if a given tab is not currently visible. Some LAFs may not display all tabs concurrently. OSX, for example, puts tabs that don't fit into a popup menu. */ class TabNotVisibleException extends LocationUnavailableException { public int index; public TabNotVisibleException(int index) { super("Tab " + index + " not visible"); this.index = index; } } }