/* * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. * * Copyright 2013 - 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakuli.actions.screenbased; import org.sakuli.actions.Action; import org.sakuli.datamodel.TestCase; import org.sakuli.datamodel.actions.ImageLibObject; import org.sakuli.exceptions.SakuliException; import org.sakuli.loader.BaseActionLoader; import org.sakuli.loader.ScreenActionLoader; import org.sikuli.basics.Settings; import org.sikuli.script.FindFailed; import org.sikuli.script.Location; import org.sikuli.script.Match; import org.sikuli.script.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * @author Tobias Schneck */ public class RegionImpl extends org.sikuli.script.Region implements Action { protected static final Logger LOGGER = LoggerFactory.getLogger(RegionImpl.class); private final boolean resumeOnException; private ScreenActionLoader loader; /** * Creates a new Region from the hole Screen */ public RegionImpl(boolean resumeOnException, ScreenActionLoader loader) { this(0, 0, loader.getScreen().getW(), loader.getScreen().getH(), resumeOnException, loader); } /** * Creates a new Region from the position paramters */ public RegionImpl(int x, int y, int w, int h, boolean resumeOnException, ScreenActionLoader loader) { super(x, y, w, h, loader.getScreen()); this.loader = loader; this.resumeOnException = resumeOnException; } /** * Wrapper for the {@link org.sikuli.script.Region} objects. */ public RegionImpl(org.sikuli.script.Region region, boolean resumeOnException, ScreenActionLoader loader) { super(region); this.resumeOnException = resumeOnException; this.loader = loader; } public static RegionImpl toRegion(org.sikuli.script.Region region, boolean resumeOnException, ScreenActionLoader loader) { if (region != null) { return new RegionImpl(region, resumeOnException, loader); } return null; } static Path resolveTakeScreenshotFolder(String filename, BaseActionLoader loader) { Path path = Paths.get(filename); if (path.isAbsolute()) { return path; } TestCase currentTestCase = loader.getCurrentTestCase(); Path folderPath = currentTestCase != null ? currentTestCase.getTcFile() : null; if (folderPath == null || !Files.exists(folderPath)) { LOGGER.warn("The test case folder could be found => Fallback: Use test suite folder!"); folderPath = loader.getTestSuite().getTestSuiteFolder(); } return folderPath.resolve(filename); } /** * {@link Region#find(String)}. */ public RegionImpl find(String imageName) { Match match; Pattern imagePattern = loadPattern(imageName); try { match = this.find(imagePattern); } catch (FindFailed findFailed) { match = null; } if (match != null) { return toRegion(match); } loader.getExceptionHandler().handleException("Can't find \"" + imagePattern + "\" in " + this.toString(), this, resumeOnException); return null; } /** * {@link Region#findRegion(Region)} */ public RegionImpl findRegion(RegionImpl region) { Match match; try { match = this.find(region); } catch (FindFailed findFailed) { match = null; } if (match != null) { return toRegion(match); } loader.getExceptionHandler().handleException("Can't find \"" + region + "\" in this region!", this, resumeOnException); return null; } /** * {@link Region#exists(String)} */ public RegionImpl exists(String imageName) { return toRegion(this.exists(loadPattern(imageName))); } /** * Check whether the give imageName is visible in the Region for x Seconds. * * @return this {@link Region} or null */ public RegionImpl exists(String imageName, int seconds) { return toRegion(this.exists(loadPattern(imageName), seconds)); } /** * {@link org.sakuli.actions.screenbased.Region#click()} */ public RegionImpl clickMe() { int ret; try { Location center = this.getCenter(); ret = this.click(center); } catch (FindFailed findFailed) { ret = 0; } loader.loadSettingDefaults(); if (ret != 1) { loader.getExceptionHandler().handleException("Couldn't click on region " + this, this, resumeOnException); return null; } return this; } /** * {@link Region#doubleClick()} ()} */ public RegionImpl doubleClickMe() { int ret; try { Location center = this.getCenter(); ret = this.doubleClick(center); } catch (FindFailed findFailed) { ret = 0; } loader.loadSettingDefaults(); if (ret != 1) { loader.getExceptionHandler().handleException("Couldn't double click on region " + this, this, resumeOnException); return null; } return this; } /** * {@link Region#rightClick()} ()} */ public RegionImpl rightClickMe() { int ret; try { Location center = this.getCenter(); ret = this.rightClick(center); } catch (FindFailed findFailed) { ret = 0; } loader.loadSettingDefaults(); if (ret != 1) { loader.getExceptionHandler().handleException("Couldn't right click on region " + this, this, resumeOnException); return null; } return this; } /** * wrapper implementation for {@link #mouseMove(Object)} ()} */ public RegionImpl mouseMoveMe() { int ret; try { Location center = this.getCenter(); ret = this.mouseMove(center); } catch (FindFailed findFailed) { ret = 0; } loader.loadSettingDefaults(); if (ret != 1) { loader.getExceptionHandler().handleException("Could not move the mouse on region " + this, this, resumeOnException); return null; } return this; } /** * wrapper implementation for {@link #mouseDown(int)} */ public RegionImpl mouseDown(MouseButton mouseButton) { try { this.mouseDown(mouseButton.getValue()); } catch (Throwable e) { loader.getExceptionHandler().handleException("Could execute mouseDown action for " + this, this, resumeOnException); } return this; } /** * wrapper implementation for {@link #mouseUp(int)} */ public RegionImpl mouseUp(MouseButton mouseButton) { try { this.mouseUp(mouseButton.getValue()); } catch (Throwable e) { loader.getExceptionHandler().handleException("Could execute mouseUp action for " + this, this, resumeOnException); } return this; } /** * wrapper for {@link #drag(Object)} and {@link #dropAt(Object)}). */ public RegionImpl dragAndDropTo(org.sikuli.script.Region targetRegion) { try { int ret = this.drag(targetRegion); int ret2 = this.dropAt(targetRegion); if (ret == 1 && ret2 == 1) { return toRegion(targetRegion); } } catch (FindFailed e) { LOGGER.error("Find on 'drag and drop' faild", e); } loader.getExceptionHandler().handleException("Could not execute 'drag and drop' sucessfully' from " + this + "to " + targetRegion, resumeOnException); return null; } /** * {@link Region#waitForImage(String, int)} ()} */ public RegionImpl waitForImage(String imageName, int seconds) { Match match; ImageLibObject imageObj = loadImage(imageName); try { match = this.wait(imageObj.getPattern(), seconds); } catch (FindFailed findFailed) { match = null; } if (match != null) { return toRegion(match); } loader.getExceptionHandler().handleException("Can't find \"" + imageObj + "\" in" + this + "waitFor function in " + seconds + " sec.", this, resumeOnException); return null; } /** * {@link Region#deleteChars(int)} */ public RegionImpl deleteChars(int amountOfChars) { String deleteString = ""; for (int i = 0; i < amountOfChars; i++) { deleteString += Key.DELETE; } int ret; try { ret = this.type(this, deleteString); } catch (FindFailed findFailed) { ret = 0; } if (ret != 1) { loader.getExceptionHandler().handleException("Can't delete " + amountOfChars + " chars in the field '\" + imageName + \"'\"", this, resumeOnException); return null; } return this; } /** * {@link Region#move(int, int)}. */ public RegionImpl move(int offsetX, int offsetY) { RegionImpl result = toRegion(this.offset(offsetX, offsetY)); if (result != null) { return result; } loader.getExceptionHandler().handleException("Cant't set offset for region " + this, this, resumeOnException); return null; } /** * {@link org.sakuli.actions.screenbased.Region#extractText()} */ public String extractText() { assert Settings.OcrTextRead; assert Settings.OcrTextSearch; String erg = this.text(); if (erg.equals("--- no text ---")) { loader.getExceptionHandler().handleException("text recognition is currently switched off", this, resumeOnException); return null; } LOGGER.info("Extracted text from region " + this + " is: " + erg); return erg; } /** * loads the picture from the imageLib, if it is available. Else the exception will be forwarded to the * ExceptionHandler. * * @param imageName name of the image with or without .png * @return a {@link org.sikuli.script.Pattern} object or null if pic is not available. */ protected ImageLibObject loadImage(String imageName) { try { return loader.getImageLib().getImage(imageName); } catch (SakuliException e) { loader.getExceptionHandler().handleException(e, resumeOnException); } return null; } protected Pattern loadPattern(String imageName) { ImageLibObject imageLibObject = loadImage(imageName); return imageLibObject != null ? imageLibObject.getPattern() : null; } private RegionImpl toRegion(Match match) { if (match != null) { return new RegionImpl(match, resumeOnException, loader); } return null; } private RegionImpl toRegion(org.sikuli.script.Region region) { if (region != null) { return new RegionImpl(region, resumeOnException, loader); } return null; } @Override public String toString() { if (getLastMatch() != null) { return getLastMatch().toString(); } return super.toStringShort(); } @Override public boolean getResumeOnException() { return resumeOnException; } @Override public ScreenActionLoader getLoader() { return loader; } @Override public RegionImpl getActionRegion() { return this; } }