/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.internal.swing; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Iterator; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import javax.swing.tree.TreePath; import abbot.finder.AWTHierarchy; import abbot.script.Condition; import abbot.tester.ActionFailedException; import abbot.tester.ComponentLocation; import abbot.tester.ComponentMissingException; import abbot.tester.ComponentTester; import abbot.tester.JComboBoxTester; import abbot.tester.JListLocation; import abbot.tester.JTabbedPaneLocation; import abbot.tester.JTabbedPaneTester; import abbot.tester.JTableLocation; import abbot.tester.JTextComponentTester; import abbot.tester.JTreeLocation; import abbot.tester.LocationUnavailableException; import abbot.util.Properties; import com.windowtester.internal.runtime.preferences.PlaybackSettings; import com.windowtester.internal.swing.util.KeyStrokeDecoder; import com.windowtester.internal.tester.swing.JListTester; import com.windowtester.internal.tester.swing.JTableTester; import com.windowtester.internal.tester.swing.JTreeTester; import com.windowtester.runtime.WidgetSearchException; /** * A service that drives UI events. * <br> * The prefered way to access these functions is through a <code>UIContextSwing</code> instance. * * @see com.windowtester.internal.swing.UIContextSwing * */ public class UIDriverSwing { /** Base delay setting. */ public static int defaultTimeout = Properties.getProperty("abbot.robot.default_delay", 30000, 0, 60000); private static final int SLEEP_INTERVAL = 10; /** A settings object that manages playback-related settings */ protected PlaybackSettings _settings; public static int getDefaultTimeout() { return defaultTimeout; } public static int getDefaultSleepInterval() { return SLEEP_INTERVAL; } private Component dragSource; private int dragSrcX; private int dragSrcY; //////////////////////////////////////////////////////////////////////////// // // Constructor // // ////////////////////////////////////////////////////////////////////////// public UIDriverSwing(){ ComponentTester.setTester(JList.class,new JListTester()); ComponentTester.setTester(JTree.class,new JTreeTester()); ComponentTester.setTester(JTable.class,new JTableTester()); } /////////////////////////////////////////////////////////////////////////// // // Click actions // /////////////////////////////////////////////////////////////////////////// public Component click(int clickCount,Component w,int x,int y,int mask){ ComponentTester tester = ComponentTester.getTester(w); dragSource = w; dragSrcX = x; dragSrcY = y; tester.actionClick(w, x, y, mask, clickCount); return w; } public Component click(Component owner, String labelOrPath) throws ComponentMissingException, ActionFailedException { // not checking for awt.MenuItem, not a subclass of Component ComponentTester tester = ComponentTester.getTester(owner); dragSource = owner; if (owner instanceof JTable){ JTableLocation location = new JTableLocation(labelOrPath); Point cellLocation = location.getPoint(owner); dragSrcX = cellLocation.x; dragSrcY = cellLocation.y; ((JTableTester)tester).actionSelectCell(owner,new JTableLocation(labelOrPath)); } if (owner instanceof JTabbedPane) ((JTabbedPaneTester)tester).actionSelectTab(owner, new JTabbedPaneLocation(labelOrPath)); return owner; } public Component clickTreeItem(int clickCount,Component owner,String path,int mask){ // convert string to TreePath String[] nodeNames = path.split("/"); TreePath treePath = new TreePath(nodeNames); dragSource = owner; JTreeLocation location = new JTreeLocation(treePath); ComponentTester tester = ComponentTester.getTester(owner); ((JTreeTester)tester).actionMakeVisible(owner,treePath); try { Point point = location.getPoint(owner); dragSrcX = point.x; dragSrcY = point.y; } catch (LocationUnavailableException e) { // do nothing System.out.println("Caught location unaviable exception"); } ((JTreeTester)tester).actionSelectPath(clickCount,owner,treePath,mask); return owner; } /** * click on table cell selection based on row and col * @param owner * @param row * @param col * @return * TODO: check with given string, if any whether we have the right cell */ public Component clickTable(int clickCount,JTable owner,int row,int col,int mask){ ComponentTester tester = ComponentTester.getTester(owner); JTableLocation location = new JTableLocation(row,col); Point cellLocation = location.getPoint(owner); dragSrcX = cellLocation.x; dragSrcY = cellLocation.y; dragSource = owner; ((JTableTester)tester).actionSelectCell(clickCount,owner,new JTableLocation(row,col),mask); return owner; } public Component clickMenuItem(JMenuItem owner){ ComponentTester tester = ComponentTester.getTester(owner); tester.actionSelectMenuItem(owner); return owner; } public Component clickListItem(int clickCount,JList owner,String labelOrPath, int mask) throws ActionFailedException { ComponentTester tester = ComponentTester.getTester(owner); dragSource = owner; JListLocation location = new JListLocation(labelOrPath); Point point = location.getPoint(owner); dragSrcX = point.x; dragSrcY = point.y; ((JListTester)tester).actionMultipleClick(owner,clickCount,labelOrPath,mask); return owner; } public Component clickComboBox(JComboBox owner,String labelOrPath,int clickCount) throws ActionFailedException { ComponentTester tester = ComponentTester.getTester(owner); if (labelOrPath != null) ((JComboBoxTester)tester).actionSelectItem(owner,labelOrPath); else tester.actionClick(owner, new ComponentLocation(), InputEvent.BUTTON1_MASK, clickCount); return owner; } /** * Click at a particular position in a text component * @param owner * @param caret * @return */ public Component clickTextComponent(JTextComponent owner,int caret){ ComponentTester tester = ComponentTester.getTester(owner); try { Rectangle rect = owner.modelToView(caret); dragSource = owner; dragSrcX = rect.x + rect.width/2; dragSrcY = rect.y + rect.height/2; } catch (BadLocationException e) { // TODO Auto-generated catch block e.printStackTrace(); } ((JTextComponentTester)tester).actionClick(owner,caret); return owner; } public Component contextClick(Component widget, String path) throws WidgetSearchException, ActionFailedException{ ComponentTester tester = ComponentTester.getTester(widget); try { tester.actionSelectPopupMenuItem(widget,path); } catch (ComponentMissingException e) { throw new WidgetSearchException("Cant find menu item"+ path); } return widget; } public Component contextClick(Component widget, int x, int y, String path) throws WidgetSearchException, ActionFailedException { ComponentTester tester = ComponentTester.getTester(widget); try { tester.actionSelectPopupMenuItem(widget,x,y,path); } catch (ComponentMissingException e) { throw new WidgetSearchException("Cant find menu item"+ path); } return widget; } /** * Context click on tree node * @param widget * @param itemPath * @param menuPath * @return * @throws ComponentMissingException * @throws ActionFailedException */ public Component contextClickTree(JTree widget,String itemPath, String menuPath) throws ComponentMissingException, ActionFailedException { String[] nodeNames = itemPath.split("/"); TreePath path = new TreePath(nodeNames); ComponentTester tester = ComponentTester.getTester(widget); ((JTreeTester)tester).actionMakeVisible(widget,path); tester.actionSelectPopupMenuItem(widget,new JTreeLocation(path),menuPath); return widget; } /** * Context click on a table * @param widget * @param itemPath * @param menuPath * @return * @throws ComponentMissingException * @throws ActionFailedException */ public Component contextClickTable(JTable widget, int row,int col, String menuPath) throws ComponentMissingException, ActionFailedException { ComponentTester tester = ComponentTester.getTester(widget); JTableLocation location = new JTableLocation(row,col); tester.actionShowPopupMenu(widget,location); tester.actionSelectPopupMenuItem(widget,location,menuPath); return widget; } /////////////////////////////////////////////////////////////////////////// // // Primitive mouse action commands // /////////////////////////////////////////////////////////////////////////// public void mouseMove(Component w) { mouseMove(w, w.getWidth() / 2, w.getHeight() / 2); } public void mouseMove(Component w, int x, int y) { ComponentTester tester = ComponentTester.getTester(w); tester.mouseMove(w,x,y); } public void mouseMove(int x,int y) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.mouseMove(x,y); } /** * Press the mouse. * @param accel - the mouse accelerator. * @since 3.8.1 */ public void mouseDown(int accel) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.mousePress(accel); } /** * Release the mouse * @param accel - the mouse accelerator. * @since 3.8.1 */ public void mouseUp(int accel) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.mouseRelease(accel); } /////////////////////////////////////////////////////////////////////////// // // Drag and drop actions // /////////////////////////////////////////////////////////////////////////// /** * @since 3.8.1 */ public void doDragTo(Component target,int x,int y){ ComponentTester tester = ComponentTester.getTester(Component.class); tester.drag(dragSource, dragSrcX, dragSrcY, InputEvent.BUTTON1_MASK); tester.mouseMove(target, x, y); tester.drop(target,x,y); waitForIdle(); } /** * @since 3.8.1 */ public Point getLocation(Component owner, String path){ if (owner instanceof JList){ JListLocation location = new JListLocation(path); return location.getPoint(owner); } if (owner instanceof JTree){ String[] nodeNames = path.split("/"); JTreeLocation location = new JTreeLocation(new TreePath(nodeNames)); return location.getPoint(owner); } ComponentLocation location = new ComponentLocation(); return location.getPoint(owner); } /** * @since 3.8.1 */ public Point getLocation(Component owner,int row,int col){ JTableLocation location = new JTableLocation(row,col); return location.getPoint(owner); } /** * @since 3.8.1 */ public Point getLocation(Component owner, int index){ JTextComponentTester tester = (JTextComponentTester) ComponentTester.getTester(JTextComponent.class); return tester.scrollToVisible(owner, index); } /** * @since 3.8.1 */ public Point getLocation(Component owner){ ComponentLocation location = new ComponentLocation(); return location.getPoint(owner); } /////////////////////////////////////////////////////////////////////////// // // Text entry actions // /////////////////////////////////////////////////////////////////////////// public void enterText(String txt) throws ActionFailedException { // get the component and the tester ComponentTester tester = ComponentTester.getTester(Component.class); Component widget = tester.findFocusOwner(); ComponentTester testerw = ComponentTester.getTester(widget); // if(widget instanceof JTextComponent){ // ((JTextComponentTester) testerw).actionEnterText(widget,txt); // } // else tester.actionKeyString(widget,txt); } // TODO: this needs to be fixed public void keyClick(int key) { ComponentTester tester = ComponentTester.getTester(Component.class); int[] keys = KeyStrokeDecoder.extractKeys(key); int modifiers = KeyStrokeDecoder.extractModifiers(key); for (int i=0;i < keys.length;i++) tester.actionKeyStroke(keys[i], modifiers); } public void keyClick(char key) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.keyStroke(key); } public void keyClick(int modifiers, char c) { ComponentTester tester = ComponentTester.getTester(Component.class); boolean shift = (modifiers & InputEvent.SHIFT_MASK) != 0 || (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0; boolean alt = (modifiers & InputEvent.ALT_MASK) != 0 || (modifiers & InputEvent.ALT_DOWN_MASK) != 0; boolean ctrl = (modifiers & InputEvent.CTRL_MASK) != 0 || (modifiers & InputEvent.CTRL_DOWN_MASK) != 0; if(shift) tester.actionKeyPress(KeyEvent.VK_SHIFT); if (alt) tester.actionKeyPress(KeyEvent.VK_ALT); if (ctrl) tester.actionKeyPress(KeyEvent.VK_CONTROL); tester.keyStroke(c); waitForIdle(); if (ctrl) tester.actionKeyRelease(KeyEvent.VK_CONTROL); if (alt) tester.actionKeyRelease(KeyEvent.VK_ALT); if (shift) tester.actionKeyRelease(KeyEvent.VK_SHIFT); } /////////////////////////////////////////////////////////////////////////// // // "Meta" actions // /////////////////////////////////////////////////////////////////////////// /** Set the focus on to the given component. */ public void setFocus(Component widget) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.actionFocus(widget); } public void close(Window window ) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.close(window); } /////////////////////////////////////////////////////////////////////////// // // Timing // /////////////////////////////////////////////////////////////////////////// public void waitForIdle() { ComponentTester tester = ComponentTester.getTester(Component.class); tester.actionWaitForIdle(); } public void waitForWindowShowing(final String windowName, final int timeout) { wait(new Condition() { public boolean test() { return assertComponentShowing(windowName); } public String toString() { return windowName + " to show"; } }, timeout); } boolean boolT; private synchronized boolean assertComponentShowing(final String title){ boolT = false; // Collection f = WindowTracker.getTracker().getRootWindows(); ArrayList componentList = new ArrayList(); AWTHierarchy h = new AWTHierarchy(); final Iterator rootIter = h.getRoots().iterator(); while (rootIter.hasNext()) { componentList.addAll(h.getComponents((Component)rootIter.next())); } componentList.addAll(h.getRoots()); // f = h.getRoots(); final Iterator compIter = componentList.iterator(); while (compIter.hasNext()) { Component c = (Component)compIter.next(); if (c instanceof Frame){ Frame w = (Frame)c; if ( w.isDisplayable() && (w.getTitle().equals(title))) { boolT = w.isVisible(); } } if (c instanceof Dialog){ Dialog d = (Dialog)c; if ( d.isDisplayable() && (d.getTitle().equals(title))) { boolT = d.isVisible(); } } } return boolT; } public void pause(int ms) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.actionDelay(ms); } public void wait(Condition condition) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.wait(condition); } public void wait(Condition condition, long timeout) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.wait(condition,timeout); } public void wait(Condition condition, long timeout, int interval) { ComponentTester tester = ComponentTester.getTester(Component.class); tester.wait(condition,timeout,interval); } }