package abbot.tester;
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.JTextComponent;
import abbot.Log;
import abbot.i18n.Strings;
/** Provides actions and assertions {@link JTextComponent}-based
* components.
*/
public class JTextComponentTester extends JComponentTester {
/**
* Type the given text into the given component, replacing any existing
* text already there. If the empty string or <code>null</code> is given,
* simply removes all existing text.
*/
public void actionEnterText(Component c, String text) {
scrollToVisible(c, 0);
actionActionMap(c, DefaultEditorKit.selectAllAction);
if (text == null || "".equals(text)) {
actionActionMap(c, DefaultEditorKit.deletePrevCharAction);
}
else {
actionKeyString(c, text);
}
}
/** Click at the given index position. */
public void actionClick(Component tc, int index) {
Point where = scrollToVisible(tc, index);
actionClick(tc, where.x, where.y);
}
public void actionSetCaretPosition(Component tc, int index) {
actionClick(tc, index);
}
/** Move the pointer to the given index location. Takes care of
* auto-scrolling through text.
* @since 3.8.1
*/
// TODO move this to a JTextComponentLocation and rely on existing
// mechanisms to do the scrolling.
public Point scrollToVisible(Component c, int index) {
JTextComponent tc = (JTextComponent)c;
try {
Rectangle visible = tc.getVisibleRect();
Rectangle rect = tc.modelToView(index);
Log.debug("visible=" + visible + ", index="
+ index + " is at " + rect);
if (rect == null) {
String msg = Strings.get("tester.zero_size");
throw new ActionFailedException(msg);
}
// Autoscroll on JTextComponent is a bit flakey
if (!visible.contains(rect.x, rect.y)) {
scrollRectToVisible(tc, rect);
visible = tc.getVisibleRect();
rect = tc.modelToView(index);
Log.debug("visible=" + visible + " caret=" + rect);
if (!visible.contains(rect.x, rect.y)) {
String msg = Strings.get("tester.JComponent.not_visible",
new Object[] {
new Integer(rect.x),
new Integer(rect.y),
tc,
});
throw new ActionFailedException(msg);
}
}
return new Point(rect.x + rect.width/2,
rect.y + rect.height/2);
}
catch(BadLocationException ble) {
String msg = Strings.get("tester.JTextComponent.bad_location",
new Object[] {
ble.getMessage(),
new Integer(index),
tc.getText()
});
throw new ActionFailedException(msg);
}
}
/** Account for differences in scrolling {@link javax.swing.JTextField}.
@see JComponentTester#scrollRectToVisible
@see JComponent#scrollRectToVisible
*/
protected void scrollRectToVisible(JComponent c, Rectangle rect) {
super.scrollRectToVisible(c, rect);
// Taken from JComponent
if (!isVisible(c, rect) && c instanceof JTextField) {
int dx = c.getX();
int dy = c.getY();
Container parent;
for (parent = c.getParent();
!(parent == null)
&& !(parent instanceof JComponent)
&& !(parent instanceof CellRendererPane);
parent = parent.getParent()) {
Rectangle bounds = parent.getBounds();
dx += bounds.x;
dy += bounds.y;
}
if (!(parent == null) && !(parent instanceof CellRendererPane)) {
rect.x += dx;
rect.y += dy;
super.scrollRectToVisible((JComponent)parent, rect);
rect.x -= dx;
rect.y -= dy;
}
}
}
/** Equivalent to JTextComponent.setCaretPosition(int), but operates
* through the UI.
*/
protected void startSelection(Component comp, int index) {
final JTextComponent tc = (JTextComponent)comp;
// Avoid automatic drag/drop if the selection start is already
// part of a selection (OSX has setDragEnabled true by default).
if (tc.getSelectionStart() != tc.getSelectionEnd()) {
invokeAndWait(new Runnable() {
public void run() {
tc.setCaretPosition(0);
tc.moveCaretPosition(0);
}
});
}
Point where = scrollToVisible(comp, index);
mousePress(comp, where.x, where.y);
}
/** Equivalent to JTextComponent.moveCaretPosition(int), but operates
* through the UI.
*/
protected void endSelection(Component comp, int index) {
Point where = scrollToVisible(comp, index);
mouseMove(comp, where.x, where.y);
mouseRelease();
}
/** Start a selection at the given index. */
public void actionStartSelection(Component comp, int index) {
startSelection(comp, index);
waitForIdle();
}
/** Terminate a selection on the given index. */
public void actionEndSelection(Component comp, int index) {
endSelection(comp, index);
waitForIdle();
}
/** Select the given text range.
@deprecated Use actionSelectText instead.
*/
public void actionSelect(Component comp, int start, int end) {
actionSelectText(comp, start, end);
}
/** Select the given text range. */
public void actionSelectText(Component comp, int start, int end) {
// An idle wait is sometimes required, otherwise the mouse press is
// never registered (w32, 1.4)
actionStartSelection(comp, start);
actionEndSelection(comp, end);
// Verify the selection was properly made
JTextComponent tc = (JTextComponent)comp;
if (!(tc.getSelectionStart() == Math.min(start, end)
&& tc.getSelectionEnd() == Math.max(start, end))) {
String msg = Strings.get("tester.JTextComponent.selection_failed",
new Object[] {
new Integer(start), new Integer(end),
new Integer(tc.getSelectionStart()),
new Integer(tc.getSelectionEnd()),
});
throw new ActionFailedException(msg);
}
}
}