diff options
author | Jana Fabrikova <[email protected]> | 2013-04-26 20:24:55 +0200 |
---|---|---|
committer | Jana Fabrikova <[email protected]> | 2013-04-26 20:24:55 +0200 |
commit | 45751bceb7c3402d27402b24131dcebddac762cb (patch) | |
tree | fce1ffc527f40fdca54ff8e93d726287bb2f34f3 /tests | |
parent | 559dfa4f372f950bd6469e8647bad6798f0993cc (diff) |
adding awtframework (without reproducers)
Diffstat (limited to 'tests')
8 files changed, 1465 insertions, 0 deletions
diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java new file mode 100644 index 0000000..13c0d45 --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTFrameworkException.java @@ -0,0 +1,66 @@ +/* AWTFrameworkException.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package net.sourceforge.jnlp.awt; + +/** + * Class AWTFrameworkException is thrown in the AWTFramework + * whenever the framework encounters not enough data specified + * to perform an action (for example it is impossible to ascertain + * the position of an applet in the screenshot if the width or height + * of the applet is not known. + * + */ + +public class AWTFrameworkException extends Exception { + + public AWTFrameworkException() { + super(); + } + + public AWTFrameworkException(String s) { + super(s); + } + + public AWTFrameworkException(String s, Throwable throwable) { + super(s, throwable); + } + + public AWTFrameworkException(Throwable throwable) { + super(throwable); + } +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java new file mode 100644 index 0000000..fb53057 --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/AWTHelper.java @@ -0,0 +1,559 @@ +/* AWTHelper.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ +package net.sourceforge.jnlp.awt; + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import net.sourceforge.jnlp.awt.awtactions.KeyboardActions; +import net.sourceforge.jnlp.awt.awtactions.MouseActions; +import net.sourceforge.jnlp.awt.imagesearch.ComponentFinder; +import net.sourceforge.jnlp.awt.imagesearch.ComponentNotFoundException; +import net.sourceforge.jnlp.awt.imagesearch.ImageSeeker; +import net.sourceforge.jnlp.closinglisteners.Rule; +import net.sourceforge.jnlp.closinglisteners.RulesFolowingClosingListener; + +public abstract class AWTHelper extends RulesFolowingClosingListener implements Runnable{ + + //attributes possibly set by user + private String initStr = ""; + private Color appletColor; + private BufferedImage marker; + private Rectangle markerPosition; + private int appletHeight; + private int appletWidth; + private int tryKTimes = DEFAULT_K; + + //other + protected StringBuilder sb = new StringBuilder(); + private boolean actionStarted = false; + private Rectangle actionArea; + private BufferedImage screenshot; + private Robot robot; + private boolean appletFound = false; + private boolean initStrGiven = false; //impossible to find in the output if not given + private boolean appletColorGiven = false; //impossible to search for color difference if not given + private boolean markerGiven = false; //impossible to find the applet if marker not given + private boolean appletDimensionGiven = false; + private boolean screenshotTaken = false; + private int defaultWaitForApplet = 1000; + + //default number of times the screen is captured and the applet is searched for + //in the screenshot + public static final int DEFAULT_K = 3; + + + //several constructors + /** + * the minimal constructor - use: + * - if we do not want to find the bounds of applet area first + * - searching for buttons and other components is then done in the whole + * screen, confusion with other icons on display is then possible + * - less effective, deprecated (better bound the area first) + */ + @Deprecated + public AWTHelper() { + try { + this.robot = new Robot(); + } catch (AWTException e) { + throw new RuntimeException("AWTHelper could not create its Robot instance.",e); + } + } + + /** + * the minimal constructor with initStr - use: + * - we want to know from stdout that the applet (or sth else) is ready + * - if we do not want to find the bounds of applet area first + * - searching for buttons and other components is then done in the whole + * screen, confusion with other icons on display is then possible + * - less effective, deprecated (better bound the area first) + */ + @Deprecated + public AWTHelper(String initStr){ + this(); + + this.initStr = initStr; + this.initStrGiven = true; + } + + /** + * the constructor with icon and its position in applet of given dimension + * use: + * - we want to find and activate the applet first + * - the search for applet will be done via searching for icon + * of given position(x,y,w,h) inside applet of given width and height + * + * @param icon marker by which the applet will be found + * @param iconPosition relatively to applet (including icon width and height) + * @param appletWidth + * @param appletHeight + */ + + public AWTHelper(BufferedImage icon, Rectangle iconPosition, int appletWidth, int appletHeight){ + this(); + this.marker = icon; + this.markerPosition = iconPosition; + this.markerGiven = true; + + this.appletWidth = appletWidth; + this.appletHeight = appletHeight; + this.appletDimensionGiven = true; + } + + public AWTHelper(String initString, BufferedImage icon, Rectangle iconPosition, int appletWidth, int appletHeight) throws AWTException{ + this(icon, iconPosition, appletWidth, appletHeight); + + this.initStr = initString; + this.initStrGiven = true; + } + + /** + * the constructor with applet width and height only - use: + * - we want to find the applet by finding the default icon + * that is located in the upper left corner of applet + * + * @param appletWidth + * @param appletHeight + */ + public AWTHelper(int appletWidth, int appletHeight){ + this(); + String test_server_dir_path = System.getProperty("test.server.dir"); + + try { + this.marker = ImageIO.read(new File(test_server_dir_path + "/marker.png")); + this.markerPosition = new Rectangle(0,0,marker.getWidth(),marker.getHeight()); + this.markerGiven = true; + } catch (IOException e) { + throw new RuntimeException("AWTHelper could not read marker.png.",e); + } + + this.appletWidth = appletWidth; + this.appletHeight = appletHeight; + this.appletDimensionGiven = true; + } + + public AWTHelper(String initString, int appletWidth, int appletHeight){ + this(appletWidth, appletHeight); + this.initStr = initString; + this.initStrGiven = true; + } + + /** + * refers to AWTHelper functioning as RulesFolowingClosingListener + * + * @param strs array of strings to be added as contains rules + */ + public void addClosingRulesFromStringArray(String [] strs){ + for(String s : strs){ + this.addContainsRule(s); + } + } + + /** + * override of method charReaded (from RulesFolowingClosingListener) + * + * waiting for the applet, when applet is ready run action thread + * when all the wanted strings are in the stdout, applet can be closed + * + * @param ch + */ + @Override + public void charReaded(char ch) { + sb.append(ch); + //is applet ready to start clicking? + if (initStrGiven && !actionStarted && appletIsReady(sb.toString())) { + try{ + actionStarted = true; + this.findAndActivateApplet(); + this.run(); + } catch (ComponentNotFoundException e1) { + throw new RuntimeException("AWTHelper problems finding applet.",e1); + } catch (AWTFrameworkException e2){ + throw new RuntimeException("AWTHelper problems with unset attributes.",e2); + } + } + //is all the wanted output in stdout? + super.charReaded(ch); + } + + /** + * method runAWTHelper - we can call run and declared the action as started + * without finding out if initStr is in the output, if this method is + * called + * + */ + public void runAWTHelper(){ + actionStarted = true; + this.run(); + } + + /** + * implementation of AWTHelper should implement the run method + */ + public abstract void run(); + + + /** + * method getInitStrAsRule returns the initStr in the form + * of Contains rule that can be evaluated on a string + * + * @return + */ + public Rule getInitStrAsRule(){ + return new ContainsRule(this.initStr); + } + + //boolean controls getters + protected boolean appletIsReady(String content) { + return (content.contains(initStr)); + } + + public boolean isActionStarted() { + return actionStarted; + } + + public boolean isInitStrGiven(){ + return initStrGiven; + } + + public boolean isAppletColorGiven(){ + return appletColorGiven; + } + + public boolean isAppletDimensionGiven(){ + return appletDimensionGiven; + } + + public boolean isMarkerGiven(){ + return markerGiven; + } + + //setters + /** + * method setDefaultWaitForApplet sets the time (in ms) for which the method + * captureScreenAndFindApplet will wait (for the applet to load) before it + * gets the screenshot the default time is 1000ms + * + * @param defaultWaitForApplet + */ + public void setDefaultWaitForApplet(int defaultWaitForApplet) { + this.defaultWaitForApplet = defaultWaitForApplet; + } + + public void setTryKTimes(int tryKTimes) { + this.tryKTimes = tryKTimes; + } + + public void setAppletColor(Color appletColor) { + this.appletColor = appletColor; + this.appletColorGiven = true; + } + + public void setInitStr(String initStr) { + this.initStr = initStr; + this.initStrGiven = true; + } + + public void setMarker(BufferedImage marker, Rectangle markerPosition) { + this.marker = marker; + this.markerPosition = markerPosition; + this.markerGiven = true; + } + + public void setAppletDimension(int width, int height){ + this.appletWidth = width; + this.appletHeight = height; + this.appletDimensionGiven = true; + } + + + //creating screenshots, searching for applet + /** + * method captureScreenAndFindAppletByIcon + * 1. checks that all needed attributes of AWTHelper are given + * (marker, its position and applet width and height) + * 2. captures screen, + * 3. finds the rectangle where applet is and saves it to the attribute + * actionArea + * 4. sets screenCapture indicator to true (after tryKTimes unsuccessfull + * tries an exception "ComponentNotFound" will be raised) + * + * @throws AWTException + * @throws ComponentNotFoundException + * @throws AWTFrameworkException + */ + public void captureScreenAndFindAppletByIcon() throws ComponentNotFoundException, AWTFrameworkException { + if(!appletDimensionGiven || !markerGiven){ + throw new AWTFrameworkException("AWTFramework cannot find applet without dimension or marker!"); + } + captureScreenAndFindAppletByIconTryKTimes(marker, markerPosition, appletWidth, appletHeight, tryKTimes); + } + + /** + ** method captureScreenAndFindAppletByIcon + * 1. captures screen, + * 2. finds the rectangle where applet is and saves it to the attribute + * actionArea + * 3. sets screenCapture indicator to true (after tryKTimes unsuccessfull + * tries an exception "ComponentNotFound" will be raised) + * + * @param icon + * @param iconPosition + * @param width + * @param height + * @param K + * @throws ComponentNotFoundException + * @throws AWTFrameworkException + */ + public void captureScreenAndFindAppletByIconTryKTimes(BufferedImage icon, Rectangle iconPosition, int width, int height, int K) throws ComponentNotFoundException, AWTFrameworkException { + + if(!markerGiven){ + throw new AWTFrameworkException("AWTFramework cannot find applet without marker!"); + } + + int count = 0; + appletFound = false; + while ((count < K) && !appletFound) { + robot.delay(defaultWaitForApplet); + screenshot = robot.createScreenCapture( new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() ) ); + screenshotTaken = true; + actionArea = ComponentFinder.findWindowByIcon(icon, iconPosition, width, height, screenshot); + if (ImageSeeker.isRectangleValid(actionArea)) { + appletFound = true; + } + count++; + } + + if (ImageSeeker.isRectangleValid(actionArea)) { + appletFound = true; + } else { + throw new ComponentNotFoundException("Applet not found in the screenshot!"); + } + + } + + /** + * auxiliary method writeAppletScreen for writing Buffered image into png + * + * @param appletScreen + * @param filename + * @throws IOException + */ + private void writeAppletScreen(BufferedImage appletScreen, String filename) throws IOException {// into png file + ImageIO.write(appletScreen, "png", new File(filename+".png")); + } + + + /** + * method findAndActivateApplet finds the applet by icon + * and clicks in the middle of applet area + * + * @throws ComponentNotFoundException (applet not found) + * @throws AWTFrameworkException + */ + public void findAndActivateApplet() throws ComponentNotFoundException, AWTFrameworkException + { + captureScreenAndFindAppletByIcon(); + clickInTheMiddleOfApplet(); + } + + + //methods for clicking and typing + /** + * method clickInTheMiddleOfApplet focuses the applet by clicking in the + * middle of its location rectangle + */ + public void clickInTheMiddleOfApplet() { + MouseActions.clickInside(this.actionArea, this.robot); + } + + /** + * Method clickOnIconExact - click in the middle of a rectangle with + * given pattern (icon) using specified mouse key. + * If the applet has not been found yet, the search includes whole screen. + * + * @param icon + * @param mouseKey + * @throws ComponentNotFoundException + */ + public void clickOnIconExact(BufferedImage icon, int mouseKey) throws ComponentNotFoundException{ + Rectangle areaOfSearch; + if(!appletFound){//searching whole screen, less effective + areaOfSearch = new Rectangle(0, 0, this.screenshot.getWidth(), this.screenshot.getHeight()); + }else{ + areaOfSearch = this.actionArea; + } + Rectangle iconRectangle = ImageSeeker.findExactImage(icon, this.screenshot, areaOfSearch); + + if (ImageSeeker.isRectangleValid(iconRectangle)) { + MouseActions.clickInside(mouseKey, iconRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Exact icon not found!"); + } + } + + /** + * Method clickOnIconBlurred - click in the middle of a rectangle with + * given pattern (icon) using specified mouse key. + * If the applet has not been found yet, the search includes whole screen. + * + * @param icon + * @param mouseKey + * @param precision tolerated minimal correlation (see ImageSeeker methods) + * @throws ComponentNotFoundException + */ + public void clickOnIconBlurred(BufferedImage icon, int mouseKey, double precision) throws ComponentNotFoundException{ + Rectangle areaOfSearch; + if(!appletFound){//searching whole screen, less effective + areaOfSearch = new Rectangle(0, 0, this.screenshot.getWidth(), this.screenshot.getHeight()); + }else{ + areaOfSearch = this.actionArea; + } + Rectangle iconRectangle = ImageSeeker.findBlurredImage(icon, this.screenshot, precision, areaOfSearch); + + if (ImageSeeker.isRectangleValid(iconRectangle)) { + MouseActions.clickInside(mouseKey, iconRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Blurred icon not found!"); + } + } + + /** + * Method clickOnColoredRectangle - click in the middle of a rectangle with + * given color (appletColor must be specified as the background) using + * specified mouse key. + * + * @param c + * @param mouseKey + * @throws ComponentNotFoundException + * @throws AWTFrameworkException + * + */ + public void clickOnColoredRectangle(Color c, int mouseKey) throws ComponentNotFoundException, AWTFrameworkException { + Rectangle buttonRectangle = findColoredRectangle(c); + + if (ImageSeeker.isRectangleValid(buttonRectangle)) { + MouseActions.clickInside(mouseKey, buttonRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Colored rectangle not found!"); + } + } + + public void moveToMiddleOfColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException { + + Rectangle buttonRectangle = findColoredRectangle(c); + + if (ImageSeeker.isRectangleValid(buttonRectangle)) { + MouseActions.moveMouseToMiddle(buttonRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Colored rectangle not found!"); + } + } + + public void moveOutsideColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException { + Rectangle buttonRectangle = findColoredRectangle(c); + + if (ImageSeeker.isRectangleValid(buttonRectangle)) { + MouseActions.moveMouseOutside(buttonRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Colored rectangle not found!"); + } + } + + public void moveInsideColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException { + Rectangle buttonRectangle = findColoredRectangle(c); + + if (ImageSeeker.isRectangleValid(buttonRectangle)) { + MouseActions.moveInsideRectangle(buttonRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Colored rectangle not found!"); + } + } + + public void dragFromColoredRectangle(Color c) throws ComponentNotFoundException, AWTFrameworkException { + Rectangle buttonRectangle = findColoredRectangle(c); + + if (ImageSeeker.isRectangleValid(buttonRectangle)) { + MouseActions.dragFromRectangle(buttonRectangle, this.robot); + }else{ + throw new ComponentNotFoundException("Colored rectangle not found!"); + } + } + + public Rectangle findColoredRectangle(Color c) throws AWTFrameworkException { + if(!appletColorGiven || !appletFound){ + throw new AWTFrameworkException("AWTHelper could not search for colored rectangle, needs appletColor and applet position."); + } + + Rectangle result; + + int gap = 5; + result = ImageSeeker.findColoredAreaGap(this.screenshot, c, appletColor, this.actionArea.y, this.actionArea.y + this.actionArea.height, gap); + + return result; + } + + /** + * method writeText writes string containing small letters and numbers and + * spaces like the keyboard input (using KeyboardActions so delays are + * inserted) + * + * @param text + */ + public void writeText(String text) { + KeyboardActions.writeText(this.robot, text); + } + + /** + * method typeKey writes one key on the keyboard (again using + * KeyboardActions) + * + * @param key + */ + public void typeKey(int key) { + KeyboardActions.typeKey(this.robot, key); + } +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java new file mode 100644 index 0000000..1841476 --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/KeyboardActions.java @@ -0,0 +1,111 @@ +/* KeyboardActions.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + + +package net.sourceforge.jnlp.awt.awtactions; + +import java.awt.Robot; +import java.awt.event.KeyEvent; + +public class KeyboardActions { + + private static final int defaultDelay = 250; + + /** + * method writeText for simulating typing the + * given String text by a user with delays + * allowed characters in the text: 0-9, a-z, the space + * between the keystrokes + * + * @param robot + * @param text + * @param delayMs + */ + public static void writeText(Robot robot, String text, int delayMs){ + for (int i = 0; i < text.length(); i++){ + char c = text.charAt(i); + typeKey(robot, keyFromChar(c), delayMs); + } + } + + public static void writeText(Robot robot, String text){ + writeText(robot,text, defaultDelay); + } + + /** + * method typeKey for pressing and releasing given key + * with a reasonable delay + * + * @param robot + * @param key + * @param delayMs + */ + + public static void typeKey(Robot robot, int key, int delayMs){ + robot.delay(delayMs); + robot.keyPress(key); + robot.delay(delayMs); + robot.keyRelease(key); + } + + public static void typeKey(Robot robot, int key){ + typeKey(robot, key, defaultDelay); + } + + /** + * method returning the KeyInput event int + * if the character is not from a-b, 0-9, the returned value is + * KeyEvent.VK_SPACE + * + * @param ch + * @return + */ + public static int keyFromChar(char ch){ + int key; + + if( ('0' <= ch) && ('9' >= ch) ){ + key = (int)(ch - '0') + KeyEvent.VK_0; + }else if( ( 'a' <= ch) && ('z' >= ch) ){ + key = (int)(ch - 'a') + KeyEvent.VK_A; + }else{ + key = KeyEvent.VK_SPACE; + } + + return key; + } + +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java new file mode 100644 index 0000000..dd68bb4 --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/awtactions/MouseActions.java @@ -0,0 +1,228 @@ +/* MouseActions.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + + +package net.sourceforge.jnlp.awt.awtactions; + +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; + +/** + * class MouseActions + * + * static methods for manipulating the mouse via AWT robot + */ +public class MouseActions { + private static final int defaultDelay = 250; + + /** + * method click presses and releases given mouse keys + * with reasonable delay before the event + * + * @param mouseKeyMask + * @param robot + * @param delayMs + */ + public static void click(int mouseKeyMask, Robot robot, int delayMs){ + robot.delay(delayMs); + robot.mousePress(mouseKeyMask); + robot.delay(delayMs); + robot.mouseRelease(mouseKeyMask); + } + + public static void click(int mouseKeyMask, Robot robot){ + robot.delay(defaultDelay); + robot.mousePress(mouseKeyMask); + robot.delay(defaultDelay); + robot.mouseRelease(mouseKeyMask); + } + + /** + * method doubleClick presses and releases given mouse keys + * two times with reasonable delays + * + * @param mouseKeyMask + * @param robot + * @param delayMs + */ + + public static void doubleClick(int mouseKeyMask, Robot robot, int delayMs){ + click(mouseKeyMask, robot, delayMs); + click(mouseKeyMask, robot, delayMs); + } + + public static void doubleClick(int mouseKeyMask, Robot robot){ + click(mouseKeyMask, robot, defaultDelay); + click(mouseKeyMask, robot, defaultDelay); + } + + /** + * method drag presses the right mouse key, + * drags the mouse to a point, and releases the mouse key + * with reasonable delays + * + * @param xTo + * @param yTo + * @param robot + * @param delayMs + */ + public static void drag(int xTo, int yTo, Robot robot, int delayMs){ + robot.delay(delayMs); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(delayMs); + robot.mouseMove(xTo, yTo); + } + + public static void drag(int xTo, int yTo, Robot robot){ + robot.delay(defaultDelay); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(defaultDelay); + robot.mouseMove(xTo, yTo); + } + + /** + * method dragFromRectangle clicks in the middle + * of the given rectangle and drags the mouse from the rectangle + * with reasonable delays + * + * @param rectangle + * @param robot + * @param delayMs + */ + + public static void dragFromRectangle(Rectangle rectangle, Robot robot, int delayMs){ + int x1 = rectangle.x + rectangle.width/2; + int y1 = rectangle.y + rectangle.height/2; + int x2 = x1 + 2*rectangle.width; + int y2 = y1 + 2*rectangle.height; + robot.delay(delayMs); + robot.mouseMove(x1, y1); + drag(x2,y2, robot); + } + + public static void dragFromRectangle(Rectangle rectangle, Robot robot){ + dragFromRectangle(rectangle, robot, defaultDelay); + } + + /** + * method moveInsideRectangle places the mouse in the middle + * of the given rectangle and moves the mouse inside the rectangle + * with reasonable delays + * + * @param rectangle + * @param robot + * @param delayMs + */ + + public static void moveInsideRectangle(Rectangle rectangle, Robot robot, int delayMs){ + int x1 = rectangle.x + rectangle.width/2; + int y1 = rectangle.y + rectangle.height/2; + int x2 = x1 + rectangle.width/4; + int y2 = y1 + rectangle.height/4; + robot.delay(delayMs); + robot.mouseMove(x1, y1); + robot.delay(delayMs); + robot.mouseMove(x2, y2); + } + + public static void moveInsideRectangle(Rectangle rectangle, Robot robot){ + moveInsideRectangle(rectangle, robot, defaultDelay); + } + + /** + * + * @param rectangle + * @param robot + * @param delayMs + */ + public static void moveMouseToMiddle(Rectangle rectangle, Robot robot, int delayMs){ + robot.delay(delayMs); + int x = rectangle.x + (rectangle.width/2); + int y = rectangle.y + (rectangle.height/2); + robot.mouseMove(x,y); + } + + public static void moveMouseToMiddle(Rectangle rectangle, Robot robot){ + moveMouseToMiddle(rectangle, robot, defaultDelay); + } + + /** + * + * @param rectangle + * @param robot + * @param delayMs + */ + public static void moveMouseOutside(Rectangle rectangle, Robot robot, int delayMs){ + robot.delay(delayMs); + int x = rectangle.x + 2*rectangle.width; + int y = rectangle.y + 2*rectangle.height; + robot.mouseMove(x,y); + } + + public static void moveMouseOutside(Rectangle rectangle, Robot robot){ + moveMouseOutside(rectangle, robot, defaultDelay); + } + + + /** + * method clickInside moves the mouse in the middle point + * of a given rectangle and clicks with reasonable delay + + * + * @param rectangle + * @param robot + * @param delayMs + */ + public static void clickInside(int mouseKey, Rectangle rectangle, Robot robot, int delayMs){ + moveMouseToMiddle(rectangle, robot, delayMs); + robot.delay(delayMs); + click(mouseKey, robot, delayMs); + } + + public static void clickInside(int mouseKey, Rectangle rectangle, Robot robot){ + clickInside(mouseKey, rectangle, robot, defaultDelay); + } + + public static void clickInside(Rectangle rectangle, Robot robot, int delayMs){ + clickInside(InputEvent.BUTTON1_MASK, rectangle, robot, delayMs); + } + + public static void clickInside(Rectangle rectangle, Robot robot){ + clickInside(rectangle, robot, defaultDelay); + } +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java new file mode 100644 index 0000000..e28e877 --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentFinder.java @@ -0,0 +1,107 @@ +/* ComponentFinder.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + + +package net.sourceforge.jnlp.awt.imagesearch; + +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; + +public class ComponentFinder { + + /** + * method findColoredRectangle determines coordinates of a rectangle colored + * by rectangleColor surrounded by a neighbourhood of surroundingColor + * + * @param rectangleColor + * @param surroundingColor + * @param screenshot + * @return + */ + public static Rectangle findColoredRectangle(Color rectangleColor, Color surroundingColor, BufferedImage screenshot) { + + Rectangle r = ImageSeeker.findColoredAreaGap(screenshot, rectangleColor, surroundingColor, 0, screenshot.getHeight(), 0); + return r; + } + + /** + * method findColoredRectangle determines coordinates of a rectangle colored + * by rectangleColor surrounded by a neighbourhood of surroundingColor with + * possible gap of several pixels + * + * @param rectangleColor + * @param surroundingColor + * @param screenshot + * @param gap + * @return + */ + public static Rectangle findColoredRectangle(Color rectangleColor, Color surroundingColor, BufferedImage screenshot, int gap) { + + Rectangle r = ImageSeeker.findColoredAreaGap(screenshot, rectangleColor, surroundingColor, 0, screenshot.getHeight(), gap); + return r; + } + + + /** + * method findWindowByIcon finds the application area assuming there is a + * given icon in given position on the application window + * (the left upper corner by default) the dimension of the window has to + * be given + * + * @param icon + * @param iconPosition + * @param appletWidth + * @param appletHeight + * @param screenshot + * @return Rectangle rectangle where the applet resides + */ + public static Rectangle findWindowByIcon(BufferedImage icon, Rectangle iconPosition, int windowWidth, int windowHeight, BufferedImage screenshot) { + Rectangle r = ImageSeeker.findExactImage(icon, screenshot); + return windowPositionFromIconPosition(r, iconPosition, windowWidth, windowHeight); + } + + public static Rectangle findWindowByIconBlurred(BufferedImage icon, Rectangle iconPosition, int windowWidth, int windowHeight, BufferedImage screenshot, double minCorrelation) { + Rectangle r = ImageSeeker.findBlurredImage(icon, screenshot, minCorrelation); + return windowPositionFromIconPosition(r, iconPosition, windowWidth, windowHeight); + } + + public static Rectangle windowPositionFromIconPosition(Rectangle iconAbsolute, Rectangle iconRelative, int windowWidth, int windowHeight){ + return new Rectangle( iconAbsolute.x - iconRelative.x, iconAbsolute.y - iconRelative.y, + windowWidth, windowHeight); + } +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java new file mode 100644 index 0000000..9187d6a --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ComponentNotFoundException.java @@ -0,0 +1,65 @@ +/* ComponentNotFoundException.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ +package net.sourceforge.jnlp.awt.imagesearch; + +/** + * Class ComponentNotFoundException is thrown in the AWTFramework + * in such cases when a position of a component is needed for further + * action and the component is not found in the screenshot (for example + * a method should click on a button of given colour and the button + * is not found, then the method cannot perform its action and + * throws ComponentNotFoundException). + * + */ +public class ComponentNotFoundException extends Exception { + + public ComponentNotFoundException() { + super(); + } + + public ComponentNotFoundException(String s) { + super(s); + } + + public ComponentNotFoundException(String s, Throwable throwable) { + super(s, throwable); + } + + public ComponentNotFoundException(Throwable throwable) { + super(throwable); + } +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java new file mode 100644 index 0000000..89e8c9c --- /dev/null +++ b/tests/test-extensions/net/sourceforge/jnlp/awt/imagesearch/ImageSeeker.java @@ -0,0 +1,325 @@ +/* ImageSeeker.java +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + + +package net.sourceforge.jnlp.awt.imagesearch; + +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; + + + +public class ImageSeeker +{ + public static Rectangle findExactImage(BufferedImage marker, BufferedImage screen){ + return findExactImage(marker, screen, new Rectangle(0,0,screen.getWidth(), screen.getHeight())); + } + + public static Rectangle findExactImage(BufferedImage marker, BufferedImage screen, Rectangle actionArea){ + Rectangle result = new Rectangle(0,0,0,0); + boolean found = false; + boolean ok = true; + + for(int x = actionArea.x; (x < (actionArea.x + actionArea.width - marker.getWidth()) ) && !found; x++){ + for(int y= actionArea.y; (y < (actionArea.y + actionArea.height - marker.getHeight()) ) && !found; y++){ + + for(int mx = 0; (mx < marker.getWidth()) && ok; mx++){ + for(int my = 0; (my < marker.getHeight()) && ok; my++){ + if(marker.getRGB(mx, my) != screen.getRGB(x+mx,y+my)){ + ok = false; + } + } + } + if( ok ){ + found = true; + result.x = x; + result.y = y; + result.height = marker.getHeight(); + result.width = marker.getWidth(); + }else{ + ok = true; + } + + } + } + + return result; + } + + public static Rectangle findBlurredImage(BufferedImage marker, BufferedImage testImage, double minCorrelation){ + return findBlurredImage(marker, testImage, minCorrelation, new Rectangle(0,0,testImage.getWidth(), testImage.getHeight())); + } + + public static Rectangle findBlurredImage(BufferedImage marker, BufferedImage testImage, double minCorrelation, Rectangle actionArea) + { + int maxX = actionArea.width - marker.getWidth() - 1; + int maxY = actionArea.height - marker.getHeight() - 1; + int markerMaxX = marker.getWidth(); + int markerMaxY = marker.getHeight(); + + // it is much faster to work directly with color components stored as float values + float[][][] testImageArray = createArrayForOneColorComponent(actionArea); + float[][][] markerImageArray = createArrayForOneColorComponent(marker); + + convertImageToFloatArray(testImage, testImageArray, actionArea); + convertImageToFloatArray(marker, markerImageArray); + + int bestX = -1; + int bestY = -1; + double bestCorrelation = -1; + + for (int yoffset = 0; yoffset < maxY; yoffset++ ) + { + for (int xoffset = 0; xoffset < maxX; xoffset++) + { + double correlation = computeCorrelation(markerMaxX, markerMaxY, testImageArray, markerImageArray, yoffset, xoffset); + if (correlation > bestCorrelation) + { + bestCorrelation = correlation; + bestX = xoffset + actionArea.x; + bestY = yoffset + actionArea.y; + } + } + } + if(bestCorrelation > minCorrelation){ + return new Rectangle(bestX, bestY, marker.getWidth(), marker.getHeight()); + }else{ + return new Rectangle(0,0,0,0); + } + + } + + /** + * Create three-dimensional array with the same size as tested image + * dimensions (last dimension is used for storing RGB components). + * + * @param testImage tested image + * @return newly created three-dimensional array + */ + private static float[][][] createArrayForOneColorComponent(BufferedImage testImage) + { + return new float[testImage.getHeight()][testImage.getWidth()][3]; + } + + /** + * Create three-dimensional array with the same size as the given area + * dimensions (last dimension is used for storing RGB components). + * + * @param actionArea + * @return newly created three-dimensional array + */ + private static float[][][] createArrayForOneColorComponent(Rectangle actionArea) + { + return new float[actionArea.height][actionArea.width][3]; + } + + /** + * Conversion from BufferedImage into three dimensional float arrays. + * It's much faster to work with float arrays even if it's memory ineficient. + * + * @param testImage tested image + * @param array array to fill + */ + private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array) + { + for (int y = 0; y < testImage.getHeight(); y++) + { + for (int x = 0; x < testImage.getWidth(); x++) + { + int c = testImage.getRGB(x, y); + // filter out alpha channel + c = c & 0xffffff; + array[y][x][0] = ((c >> 16) & 0xff) - 128f; + array[y][x][1] = ((c >> 8) & 0xff) - 128f; + array[y][x][2] = (c & 0xff) - 128f; + } + } + } + + /** + * Conversion from BufferedImage into three dimensional float arrays. + * It's much faster to work with float arrays even if it's memory ineficient. + * This method converts only a given part of the image (actionArea) + * + * @param testImage tested image + * @param array array to fill + * @param actionArea rectangle part of the image to convert + */ + private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array, Rectangle actionArea) + { + for (int y = actionArea.y; y < (actionArea.height + actionArea.y); y++) + { + for (int x = actionArea.x; x < (actionArea.width + actionArea.x); x++) + { + int c = testImage.getRGB(x, y); + // filter out alpha channel + c = c & 0xffffff; + array[y - actionArea.y][x - actionArea.x][0] = ((c >> 16) & 0xff) - 128f; + array[y - actionArea.y][x - actionArea.x][1] = ((c >> 8) & 0xff) - 128f; + array[y - actionArea.y][x - actionArea.x][2] = (c & 0xff) - 128f; + } + } + } + + /** + * Compute correlation for given two images and 2D offset. + * + * @param maxX + * @param maxY + * @param testImageArray + * @param markerImageArray + * @param yoffset + * @param xoffset + * @return + */ + private static double computeCorrelation(int maxX, int maxY, float[][][] testImageArray, + float[][][] markerImageArray, int yoffset, int xoffset) + { + double correlation = 0; + for (int y = 0; y < maxY; y++) + { + for (int x = 0; x < maxX; x++) + { + for (int rgbIndex = 0; rgbIndex < 3; rgbIndex++) + { + float colorComponent1 = markerImageArray[y][x][rgbIndex]; + float colorComponent2 = testImageArray[yoffset + y][xoffset + x][rgbIndex]; + correlation += colorComponent1 * colorComponent2; + } + } + } + return correlation; + } + + public static int findHorizontalRule(BufferedImage screen, + Color ruleColor, Color bgColor, boolean fromTop) { + final int height = screen.getHeight(); + int gap = 0; + + if (!fromTop) { + return findHorizontalEdgeGap(screen, ruleColor, + bgColor, 1, height - 1, gap); + } else { + return findHorizontalEdgeGap(screen, bgColor, + ruleColor, 1, height - 1, gap); + } + } + + public static int findHorizontalEdgeGap(BufferedImage screen, + Color area1Color, Color area2Color, int y1, int y2, int gap) { + final int width = screen.getWidth(); + final int area1RGB = area1Color.getRGB(); + final int area2RGB = area2Color.getRGB(); + int edgePosition = Integer.MIN_VALUE; + int lastFound = Integer.MIN_VALUE; + + for (int y = y1+1; y < y2 - gap; y++) { + int found = 0; + for (int x = 0; x < width; x++) { + int c1 = screen.getRGB(x, y - 1); + int c2 = screen.getRGB(x, y + gap); + if (c1 == area1RGB && c2 == area2RGB) { + found++; + } + } + if (found > lastFound) { + lastFound = found; + edgePosition = y; + } + + } + + return edgePosition; + } + + public static int findVerticalEdgeGap(BufferedImage screen, + Color area1Color, Color area2Color, int y1, int y2, int gap) { + final int width = screen.getWidth(); + final int area1RGB = area1Color.getRGB(); + final int area2RGB = area2Color.getRGB(); + int edgePosition = Integer.MIN_VALUE; + int lastFound = Integer.MIN_VALUE; + + for (int x = 1; x < width - 1 - gap; x++) { + int found = 0; + for (int y = y1; y < y2; y++) { + int c1 = screen.getRGB(x - 1, y); + int c2 = screen.getRGB(x + gap, y); + if (c1 == area1RGB && c2 == area2RGB) { + found++; + } + } + if (found > lastFound) { + lastFound = found; + edgePosition = x; + } + } + + return edgePosition; + } + + /** + * method findColoredAreaGap finds a rectangle of given color surrounded by + * area of the second color with a possible gap at the border + * + * @param screen + * @param searchForColor + * @param surroundWithColor + * @param y1 + * @param y2 + * @param gap + * @return + */ + public static Rectangle findColoredAreaGap(BufferedImage screen, Color searchForColor, Color surroundWithColor, int y1, int y2, int gap) { + + int ymin = findHorizontalEdgeGap(screen, surroundWithColor, searchForColor, y1, y2, gap); + int ymax = findHorizontalEdgeGap(screen, searchForColor, surroundWithColor, y1, y2, gap); + int xmin = findVerticalEdgeGap(screen, surroundWithColor, searchForColor, ymin, ymax, gap); + int xmax = findVerticalEdgeGap(screen, searchForColor, surroundWithColor, ymin, ymax, gap); + + return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin); + } + + public static boolean isRectangleValid(Rectangle r){ + + if (r == null) return false; + + return (r.width != 0)&&(r.height != 0)&&(r.x != Integer.MIN_VALUE)&&(r.y != Integer.MIN_VALUE); + } + +} diff --git a/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java b/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java index 9eb491c..3e88f06 100644 --- a/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java +++ b/tests/test-extensions/net/sourceforge/jnlp/closinglisteners/RulesFolowingClosingListener.java @@ -184,6 +184,10 @@ public class RulesFolowingClosingListener extends CountingClosingListener { addRules(l); } + public List<Rule> getRules() { + return rules; + } + public void setRules(List<Rule> rules) { if (rules == null) { throw new NullPointerException("rules cant be null"); |