Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 239604 Details for
Bug 421595
JavaFX toolkit support
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
New Patch for the JavaFX-Toolkit-Bug427351fixed
JavaFX-ToolkitSupport427351fixed.patch (text/plain), 324.08 KB, created by
Marcel Hein
on 2014-02-04 05:49:01 EST
(
hide
)
Description:
New Patch for the JavaFX-Toolkit-Bug427351fixed
Filename:
MIME Type:
Creator:
Marcel Hein
Created:
2014-02-04 05:49:01 EST
Size:
324.08 KB
patch
obsolete
>diff --git a/org.eclipse.jubula.feature.rc/feature.xml b/org.eclipse.jubula.feature.rc/feature.xml >index 4ff8323..0278c18 100644 >--- a/org.eclipse.jubula.feature.rc/feature.xml >+++ b/org.eclipse.jubula.feature.rc/feature.xml >@@ -36,6 +36,8 @@ BREDEX GmbH - initial API and implementation and/or initial documentation > <plugin id="org.eclipse.jubula.rc.common.source" download-size="0" install-size="0" version="0.0.0" unpack="false"/> > <plugin id="org.eclipse.jubula.rc.swing" download-size="0" install-size="0" version="0.0.0" unpack="false"/> > <plugin id="org.eclipse.jubula.rc.swing.source" download-size="0" install-size="0" version="0.0.0" unpack="false"/> >+ <plugin id="org.eclipse.jubula.rc.javafx" download-size="0" install-size="0" version="0.0.0" unpack="false"/> >+ <plugin id="org.eclipse.jubula.rc.javafx.source" download-size="0" install-size="0" version="0.0.0" unpack="false"/> > <plugin id="org.eclipse.jubula.rc.swt" download-size="0" install-size="0" version="0.0.0" unpack="false"/> > <plugin id="org.eclipse.jubula.rc.swt.source" download-size="0" install-size="0" version="0.0.0" unpack="false"/> > <plugin id="org.eclipse.jubula.tools" download-size="0" install-size="0" version="0.0.0" unpack="false"/> >diff --git a/org.eclipse.jubula.feature/feature.xml b/org.eclipse.jubula.feature/feature.xml >index a5d57d5..9492dbc 100644 >--- a/org.eclipse.jubula.feature/feature.xml >+++ b/org.eclipse.jubula.feature/feature.xml >@@ -111,7 +111,7 @@ BREDEX GmbH - initial API and implementation and/or initial documentation > install-size="0" > version="0.0.0" > unpack="false"/> >- >+ > <plugin > id="org.eclipse.jubula.toolkit.provider.win.apps" > download-size="0" >@@ -448,4 +448,18 @@ BREDEX GmbH - initial API and implementation and/or initial documentation > version="0.0.0" > unpack="false"/> > >+ <plugin >+ id="org.eclipse.jubula.toolkit.provider.javafx" >+ download-size="0" >+ install-size="0" >+ version="0.0.0" >+ unpack="false"/> >+ >+ <plugin >+ id="org.eclipse.jubula.rc.javafx" >+ download-size="0" >+ install-size="0" >+ version="0.0.0" >+ unpack="false"/> >+ > </feature> >diff --git a/org.eclipse.jubula.rc.javafx/.checkstyle b/org.eclipse.jubula.rc.javafx/.checkstyle >new file mode 100644 >index 0000000..f69a865 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/.checkstyle >@@ -0,0 +1,7 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+ >+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false"> >+ <fileset name="all" enabled="true" check-config-name="Jubula" local="false"> >+ <file-match-pattern match-pattern="." include-pattern="true"/> >+ </fileset> >+</fileset-config> >diff --git a/org.eclipse.jubula.rc.javafx/.classpath b/org.eclipse.jubula.rc.javafx/.classpath >new file mode 100644 >index 0000000..13136fb >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/.classpath >@@ -0,0 +1,7 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<classpath> >+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> >+ <classpathentry kind="src" output="target/classes" path="src"/> >+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0x"/> >+ <classpathentry kind="output" path="target/classes"/> >+</classpath> >diff --git a/org.eclipse.jubula.rc.javafx/.gitignore b/org.eclipse.jubula.rc.javafx/.gitignore >new file mode 100644 >index 0000000..4dc0091 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/.gitignore >@@ -0,0 +1,2 @@ >+/target >+/bin >diff --git a/org.eclipse.jubula.rc.javafx/.project b/org.eclipse.jubula.rc.javafx/.project >new file mode 100644 >index 0000000..a120a21 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/.project >@@ -0,0 +1,41 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<projectDescription> >+ <name>org.eclipse.jubula.rc.javafx</name> >+ <comment></comment> >+ <projects> >+ </projects> >+ <buildSpec> >+ <buildCommand> >+ <name>org.eclipse.jdt.core.javabuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>org.eclipse.pde.ManifestBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>org.eclipse.pde.SchemaBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ </buildSpec> >+ <natures> >+ <nature>org.eclipse.jdt.core.javanature</nature> >+ <nature>org.eclipse.pde.PluginNature</nature> >+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature> >+ </natures> >+ <linkedResources> >+ <link> >+ <name>.settings</name> >+ <type>2</type> >+ <locationURI>PARENT-1-PROJECT_LOC/org.eclipse.jubula.project.configuration/settings/1.4</locationURI> >+ </link> >+ </linkedResources> >+</projectDescription> >diff --git a/org.eclipse.jubula.rc.javafx/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jubula.rc.javafx/.settings/org.eclipse.jdt.core.prefs >new file mode 100644 >index 0000000..4378554 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/.settings/org.eclipse.jdt.core.prefs >@@ -0,0 +1,11 @@ >+eclipse.preferences.version=1 >+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled >+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 >+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve >+org.eclipse.jdt.core.compiler.compliance=1.4 >+org.eclipse.jdt.core.compiler.debug.lineNumber=generate >+org.eclipse.jdt.core.compiler.debug.localVariable=generate >+org.eclipse.jdt.core.compiler.debug.sourceFile=generate >+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning >+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning >+org.eclipse.jdt.core.compiler.source=1.3 >diff --git a/org.eclipse.jubula.rc.javafx/META-INF/MANIFEST.MF b/org.eclipse.jubula.rc.javafx/META-INF/MANIFEST.MF >new file mode 100644 >index 0000000..436a692 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/META-INF/MANIFEST.MF >@@ -0,0 +1,16 @@ >+Manifest-Version: 1.0 >+Bundle-ManifestVersion: 2 >+Bundle-Name: Jubula Remote Control - JavaFX >+Bundle-SymbolicName: org.eclipse.jubula.rc.javafx;singleton:=true >+Bundle-Version: 2.3.0.qualifier >+Bundle-Vendor: Eclipse Jubula >+Require-Bundle: org.apache.commons.beanutils;bundle-version="[1.7.0,2.0.0)", >+ org.apache.commons.lang;bundle-version="[2.4.0,3.0.0)", >+ ch.qos.logback.classic;bundle-version="[1.0.0,2.0.0)", >+ ch.qos.logback.core;bundle-version="[1.0.0,2.0.0)", >+ org.slf4j.api;bundle-version="[1.7.2,2.0.0)", >+ org.eclipse.jubula.tools;bundle-version="[2.3.0,2.4.0)", >+ org.eclipse.jubula.communication;bundle-version="[2.3.0,2.4.0)", >+ org.eclipse.jubula.rc.common;bundle-version="[2.3.0,2.4.0)" >+Export-Package: org.eclipse.jubula.rc.javafx >+Bundle-RequiredExecutionEnvironment: JavaSE-1.7 >diff --git a/org.eclipse.jubula.rc.javafx/about.html b/org.eclipse.jubula.rc.javafx/about.html >new file mode 100644 >index 0000000..23f53f0 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/about.html >@@ -0,0 +1,28 @@ >+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" >+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> >+<html xmlns="http://www.w3.org/1999/xhtml"> >+<head> >+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> >+<title>About</title> >+</head> >+<body lang="EN-US"> >+<h2>About This Content</h2> >+ >+<p>September 23, 2013</p> >+<h3>License</h3> >+ >+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise >+indicated below, the Content is provided to you under the terms and conditions of the >+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available >+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. >+For purposes of the EPL, "Program" will mean the Content.</p> >+ >+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is >+being redistributed by another party ("Redistributor") and different terms and conditions may >+apply to your use of any object code in the Content. Check the Redistributor's license that was >+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise >+indicated below, the terms and conditions of the EPL still apply to any source code in the Content >+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> >+ >+</body> >+</html> >diff --git a/org.eclipse.jubula.rc.javafx/build.properties b/org.eclipse.jubula.rc.javafx/build.properties >new file mode 100644 >index 0000000..b341bbd >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/build.properties >@@ -0,0 +1,17 @@ >+############################################################################### >+# Copyright (c) 2013 BREDEX GmbH. >+# 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 >+############################################################################### >+bin.includes = about.html,\ >+ META-INF/,\ >+ .,\ >+ logback.xml >+jars.compile.order = . >+source.. = src/ >+output.. = target/classes/ >+javacSource = 1.7 >+javacTarget = 1.7 >+javacErrors.. = -assertIdentifier >diff --git a/org.eclipse.jubula.rc.javafx/logback.xml b/org.eclipse.jubula.rc.javafx/logback.xml >new file mode 100644 >index 0000000..39bc9e7 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/logback.xml >@@ -0,0 +1,20 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<configuration scan="false"> >+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> >+ <!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> >+ <encoder> >+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n >+ </pattern> >+ </encoder> >+ </appender> >+ <appender name="FILE" class="ch.qos.logback.core.FileAppender"> >+ <file>${user.home}/.jubula/logs/rc_javafx.log</file> >+ <encoder> >+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n >+ </pattern> >+ </encoder> >+ </appender> >+ <root level="warn"> >+ <appender-ref ref="FILE" /> >+ </root> >+</configuration> >diff --git a/org.eclipse.jubula.rc.javafx/pom.xml b/org.eclipse.jubula.rc.javafx/pom.xml >new file mode 100644 >index 0000000..a1402d4 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/pom.xml >@@ -0,0 +1,33 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!-- Copyright (c) 2013 BREDEX GmbH. 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 --> >+<project >+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> >+ <modelVersion>4.0.0</modelVersion> >+ <parent> >+ <artifactId>org.eclipse.jubula.releng.client</artifactId> >+ <groupId>org.eclipse.jubula</groupId> >+ <version>2.3.0-SNAPSHOT</version> >+ <relativePath>../org.eclipse.jubula.releng.client</relativePath> >+ </parent> >+ >+ <artifactId>org.eclipse.jubula.rc.javafx</artifactId> >+ <build> >+ <plugins> >+ <plugin> >+ <groupId>org.eclipse.tycho</groupId> >+ <artifactId>tycho-compiler-plugin</artifactId> >+ <version>0.18.0</version> >+ <configuration> >+ <useJDK>BREE</useJDK> >+ <compilerArgument>-err:-forbidden</compilerArgument> >+ </configuration> >+ </plugin> >+ </plugins> >+ </build> >+ <packaging>eclipse-plugin</packaging> >+ >+</project> >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/common/adapter/JavaFXAdapterFactory.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/common/adapter/JavaFXAdapterFactory.java >new file mode 100644 >index 0000000..82df99a >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/common/adapter/JavaFXAdapterFactory.java >@@ -0,0 +1,76 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.common.adapter; >+ >+import javafx.scene.control.ButtonBase; >+import javafx.scene.control.Label; >+import javafx.scene.control.MenuItem; >+import javafx.scene.control.TableView; >+import javafx.scene.control.TextInputControl; >+import javafx.scene.control.TreeView; >+ >+import org.eclipse.jubula.rc.common.adaptable.IAdapterFactory; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent; >+import org.eclipse.jubula.rc.javafx.tester.adapter.ButtonBaseAdapter; >+import org.eclipse.jubula.rc.javafx.tester.adapter.LabelAdapter; >+import org.eclipse.jubula.rc.javafx.tester.adapter.TableAdapter; >+import org.eclipse.jubula.rc.javafx.tester.adapter.TextComponentAdapter; >+import org.eclipse.jubula.rc.javafx.tester.adapter.TreeViewAdapter; >+ >+/** >+ * This is the adapter factory for all JavaFX components. It is creating the >+ * specific adapter for a JavaFX component. >+ * >+ * Since we are using adapter here, it is a adapter factory. But this must not >+ * be the case. It is only relevant that the object is implementing the specific >+ * interface. >+ * >+ * @author BREDEX GmbH >+ * @created 28.10.2013 >+ * >+ */ >+public class JavaFXAdapterFactory implements IAdapterFactory { >+ >+ /** >+ * the supported classes >+ */ >+ private static final Class[] SUPPORTEDCLASSES = new Class[] { >+ ButtonBase.class, MenuItem.class, Label.class, >+ TextInputControl.class, TreeView.class, TableView.class >+ }; >+ >+ @Override >+ public Class[] getSupportedClasses() { >+ return SUPPORTEDCLASSES; >+ } >+ >+ @Override >+ public Object getAdapter(Class targetAdapterClass, Object objectToAdapt) { >+ IComponent returnvalue = null; >+ if (targetAdapterClass.isAssignableFrom(IComponent.class)) { >+ >+ if (objectToAdapt instanceof ButtonBase) { >+ returnvalue = new ButtonBaseAdapter((ButtonBase) objectToAdapt); >+ } else if (objectToAdapt instanceof Label) { >+ returnvalue = new LabelAdapter((Label) objectToAdapt); >+ } else if (objectToAdapt instanceof TextInputControl) { >+ returnvalue = new TextComponentAdapter( >+ (TextInputControl) objectToAdapt); >+ } else if (objectToAdapt instanceof TreeView) { >+ returnvalue = new TreeViewAdapter((TreeView) objectToAdapt); >+ } else if (objectToAdapt instanceof TableView) { >+ returnvalue = new TableAdapter((TableView) objectToAdapt); >+ } >+ } >+ return returnvalue; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/JavaFXAUTServer.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/JavaFXAUTServer.java >new file mode 100644 >index 0000000..33ec93e >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/JavaFXAUTServer.java >@@ -0,0 +1,128 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx; >+ >+import java.lang.reflect.InvocationTargetException; >+import java.util.List; >+ >+import javafx.stage.Stage; >+ >+import org.eclipse.jubula.rc.common.AUTServer; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.driver.IRobotFactory; >+import org.eclipse.jubula.rc.common.listener.BaseAUTListener; >+import org.eclipse.jubula.rc.javafx.driver.RobotFactoryConfig; >+import org.eclipse.jubula.rc.javafx.listener.AbstractFXAUTEventHandler; >+import org.eclipse.jubula.rc.javafx.listener.CheckListener; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.listener.MappingListener; >+import org.eclipse.jubula.rc.javafx.listener.RecordListener; >+import org.slf4j.Logger; >+import org.slf4j.LoggerFactory; >+ >+/** >+ * The AutServer controlling the AUT. <br> >+ * A quasi singleton: the instance is created from main(). <br> >+ * Expected arguments to main are, see also >+ * StartAUTServerCommand.createCmdArray(): >+ * <ul> >+ * <li>The name of host the client is running on, must be InetAddress conform.</li> >+ * <li>The port the JubulaClient is listening to.</li> >+ * <li>The main class of the AUT.</li> >+ * <li>Any further arguments are interpreted as arguments to the AUT.</li> >+ * <ul> >+ * When a connection to the JubulaClient could made, any errors will send as a >+ * message to the JubulaClient. >+ * >+ * Changing the mode to OBJECT_MAPPING results in installing an >+ * JavaFXEventFilter on the assumed primary stage, which listens to the mouse- >+ * and key.events relevant for OBJECT_MAPPING. >+ * >+ * Changing the mode removes the installed MappingListener. >+ * >+ * @author BREDEX GmbH >+ * @created 24.09.2013 >+ */ >+public class JavaFXAUTServer extends AUTServer { >+ >+ /** the logger */ >+ private static final Logger LOG = LoggerFactory >+ .getLogger(JavaFXAUTServer.class); >+ >+ /** >+ * constructor instantiates the listeners >+ */ >+ public JavaFXAUTServer() { >+ super(new MappingListener(), new RecordListener(), new CheckListener()); >+ } >+ >+ @Override >+ protected void addToolkitEventListener(BaseAUTListener listener) { >+ if (listener instanceof AbstractFXAUTEventHandler) { >+ addToolkitEventListener((AbstractFXAUTEventHandler) listener); >+ } >+ >+ } >+ >+ /** >+ * Adds a handler to the stage >+ * >+ * @param handler >+ * the handler >+ */ >+ private void addToolkitEventListener(AbstractFXAUTEventHandler handler) { >+ List<Object> stages = ComponentHandler >+ .getAssignableFromType(Stage.class); >+ for (final Object object : stages) { >+ handler.addHandler((Stage) object); >+ } >+ } >+ >+ @Override >+ protected void addToolkitEventListeners() { >+ addToolkitEventListener(new ComponentHandler()); >+ } >+ >+ @Override >+ protected void removeToolkitEventListener(BaseAUTListener listener) { >+ if (listener instanceof AbstractFXAUTEventHandler) { >+ removeToolkitEventListener((AbstractFXAUTEventHandler) listener); >+ } >+ } >+ >+ /** >+ * removes a handler from the stage >+ * >+ * @param handler >+ * the handler >+ */ >+ private void removeToolkitEventListener(AbstractFXAUTEventHandler handler) { >+ List<Object> stages = ComponentHandler >+ .getAssignableFromType(Stage.class); >+ for (Object object : stages) { >+ handler.removeHandler((Stage) object); >+ } >+ } >+ >+ @Override >+ protected void startTasks() throws ExceptionInInitializerError, >+ InvocationTargetException, NoSuchMethodException { >+ addToolKitEventListenerToAUT(); >+ invokeAUT(); >+ } >+ >+ @Override >+ public IRobot getRobot() { >+ IRobotFactory robotFactory = new RobotFactoryConfig().getRobotFactory(); >+ return robotFactory.getRobot(); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/ActivateApplicationCommand.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/ActivateApplicationCommand.java >new file mode 100644 >index 0000000..3675cd0 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/ActivateApplicationCommand.java >@@ -0,0 +1,31 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.commands; >+ >+import org.eclipse.jubula.rc.common.commands.AbstractActivateApplicationCommand; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.javafx.driver.RobotFactoryConfig; >+ >+/** >+ * @author BREDEX GmbH >+ * @created 4.11.2013 >+ * >+ */ >+public class ActivateApplicationCommand extends >+ AbstractActivateApplicationCommand { >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected IRobot getRobot() { >+ return new RobotFactoryConfig().getRobotFactory().getRobot(); >+ } >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/CAPTestCommand.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/CAPTestCommand.java >new file mode 100644 >index 0000000..af632ed >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/commands/CAPTestCommand.java >@@ -0,0 +1,41 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.commands; >+ >+import org.eclipse.jubula.rc.common.commands.AbstractCapTestCommand; >+import org.eclipse.jubula.rc.common.exception.ComponentNotFoundException; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * This class gets an message with ICommand action parameter triples. It invokes >+ * the implementation class and executes the method. Then it creates a >+ * <code>CAPTestResponseMessage</code> and sends it back to the client. The >+ * <code>CAPTestResponseMessage</code> contains an error event only if the test >+ * step fails, due to a problem prior to or during the execution of the >+ * implementation class action method. >+ * >+ * @author BREDEX GmbH >+ * @created 4.11.2013 >+ * >+ */ >+public class CAPTestCommand extends AbstractCapTestCommand { >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Object findComponent(IComponentIdentifier ci, int timeout) >+ throws ComponentNotFoundException, IllegalArgumentException { >+ >+ return ComponentHandler.findComponent(ci, true, timeout); >+ } >+ >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTJavaFXHierarchy.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTJavaFXHierarchy.java >new file mode 100644 >index 0000000..4b35ffd >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTJavaFXHierarchy.java >@@ -0,0 +1,505 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.Iterator; >+import java.util.List; >+import java.util.Map; >+import java.util.Set; >+import java.util.Vector; >+import java.util.concurrent.locks.ReentrantLock; >+ >+import javafx.scene.Node; >+import javafx.scene.control.MenuItem; >+ >+import org.apache.commons.lang.Validate; >+import org.eclipse.jubula.rc.common.AUTServerConfiguration; >+import org.eclipse.jubula.rc.common.components.AUTHierarchy; >+import org.eclipse.jubula.rc.common.exception.ComponentNotManagedException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.tools.exception.InvalidDataException; >+import org.eclipse.jubula.tools.messagehandling.MessageIDs; >+import org.eclipse.jubula.tools.objects.ComponentIdentifier; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * This class holds a hierarchy of the components of the AUT. <br> >+ * >+ * The hierarchy is composed with <code>JavaFXHierarchyContainer</code>s. For >+ * every component from the AUT a hierarchy container is created. The names for >+ * the components are stored in the appropriate hierarchy containers.<br> >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ * >+ */ >+public class AUTJavaFXHierarchy extends AUTHierarchy { >+ >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ AUTJavaFXHierarchy.class); >+ >+ /** Businessprocess for getting components */ >+ private static FindJavaFXComponentBP findBP = new FindJavaFXComponentBP(); >+ >+ /** The lock for accessing the Hierarchy **/ >+ private ReentrantLock m_lock = new ReentrantLock(); >+ >+ /** >+ * Default constructor >+ */ >+ public AUTJavaFXHierarchy() { >+ } >+ >+ /** >+ * Creates the Hierarchy from a given Object >+ * >+ * @param o >+ * the Object >+ */ >+ public void createHierarchyFrom(Object o) { >+ m_lock.lock(); >+ try { >+ Map realMap = getRealMap(); >+ Object parent = ParentGetter.get(o); >+ >+ Object lastParent = parent; >+ while (parent != null) { >+ if (realMap.containsKey(parent)) { >+ lastParent = parent; >+ break; >+ } >+ lastParent = parent; >+ parent = ParentGetter.get(parent); >+ } >+ >+ createHierarchy(lastParent == null ? o : lastParent); >+ } finally { >+ m_lock.unlock(); >+ } >+ } >+ >+ /** >+ * Recursively adds Object to the hierarchy from the given Parent. >+ * >+ * @param parent >+ * the Parent of the Children >+ */ >+ private void createHierarchy(Object parent) { >+ JavaFXHierarchyContainer parentCont; >+ >+ if (getRealMap().containsKey(parent)) { >+ parentCont = getHierarchyContainer(parent); >+ } else { >+ parentCont = initContainer(parent); >+ name(parentCont); >+ addToHierachyMap(parentCont); >+ } >+ List<Object> children = ChildrenGetter.getAsList(parent); >+ for (Object child : children) { >+ createHierarchy(child); >+ JavaFXHierarchyContainer childCont = getHierarchyContainer(child); >+ if (!(parentCont.contains(childCont))) { >+ parentCont.add(childCont); >+ childCont.setPrnt(parentCont); >+ } else if (childCont.getPrnt() == null) { >+ childCont.setPrnt(parentCont); >+ } >+ name(childCont); >+ } >+ } >+ >+ /** >+ * Convenience Method for creating Container. >+ * >+ * @param o >+ * the Object to create the Container for. >+ * @return the Container >+ */ >+ private JavaFXHierarchyContainer initContainer(Object o) { >+ JavaFXComponent comp = new JavaFXComponent(o); >+ JavaFXHierarchyContainer cont = new JavaFXHierarchyContainer(comp); >+ return cont; >+ } >+ >+ /** >+ * Removes a component from the hierarchy. This means that the following >+ * references will be removed: <br> >+ * -Container of the component from the hierarchy Map <br> >+ * -The given component from the real map <br> >+ * -The reference from the parent container to the container of this >+ * component <br> >+ * -The actions mentioned above for all children of this component >+ * >+ * @param component >+ * the component that will be deleted >+ */ >+ public void removeComponentFromHierarchy(Object component) { >+ if (component != null) { >+ JavaFXHierarchyContainer cont = getHierarchyContainer(component); >+ if (cont != null) { >+ removeContainer(cont); >+ } >+ } >+ } >+ >+ /** >+ * Removes a container from the hierarchy. This means that the following >+ * references will be removed: <br> >+ * -Container from the hierarchy Map <br> >+ * -The component of the given container from the real map <br> >+ * -The reference from the parent container to the given container <br> >+ * -The actions mentioned above for all children of this container >+ * >+ * @param ctner >+ * the container that will be deleted >+ */ >+ public void removeContainer(JavaFXHierarchyContainer ctner) { >+ m_lock.lock(); >+ try { >+ Map<JavaFXComponent, JavaFXHierarchyContainer> >+ contMap = getHierarchyMap(); >+ >+ Map<Object, JavaFXComponent> realMap = getRealMap(); >+ JavaFXComponent fxComp = ctner.getComponent(); >+ >+ fxComp.removeChangeListener(); >+ contMap.remove(ctner.getComponent()); >+ realMap.remove(fxComp.getRealComponent()); >+ JavaFXHierarchyContainer parent = (JavaFXHierarchyContainer) ctner >+ .getPrnt(); >+ if (parent != null) { >+ JavaFXHierarchyContainer[] parentComp = parent.getChildren(); >+ int i = 0; >+ for (JavaFXHierarchyContainer comp : parentComp) { >+ if (comp == ctner) { >+ parentComp[i] = null; >+ break; >+ } >+ i++; >+ } >+ } >+ ArrayList<JavaFXHierarchyContainer> children = >+ new ArrayList<JavaFXHierarchyContainer>( >+ Arrays.asList(ctner.getChildren())); >+ >+ for (JavaFXHierarchyContainer child : children) { >+ removeContainer(child); >+ } >+ } finally { >+ m_lock.unlock(); >+ } >+ } >+ >+ @Override >+ public IComponentIdentifier[] getAllComponentId() { >+ List<IComponentIdentifier> result = new Vector<IComponentIdentifier>(); >+ Set<JavaFXComponent> keys = getHierarchyMap().keySet(); >+ for (Iterator<JavaFXComponent> itr = keys.iterator(); itr.hasNext();) { >+ JavaFXComponent wrapComp = itr.next(); >+ Object comp = wrapComp.getRealComponent(); >+ try { >+ if (AUTServerConfiguration.getInstance().isSupported(comp)) { >+ >+ result.add(getComponentIdentifier(comp)); >+ } >+ } catch (IllegalArgumentException iae) { >+ // from isSupported -> log >+ log.error("hierarchy map contains null values", iae); //$NON-NLS-1$ >+ // and continue >+ } catch (ComponentNotManagedException e) { >+ // from isSupported -> log >+ log.error( >+ "component '" + wrapComp.getRealComponentType().getName() + "' not found!", e); //$NON-NLS-1$ //$NON-NLS-2$ >+ // and continue >+ } >+ } >+ return result.toArray(new IComponentIdentifier[result.size()]); >+ } >+ >+ /** >+ * Investigates the given <code>component</code> for an identifier. To >+ * obtain this identifier the name of the component and the container >+ * hierarchy is used. >+ * >+ * @param component >+ * the component to create an identifier for, must not be null. >+ * @throws ComponentNotManagedException >+ * if component is null or <br> >+ * (one of the) component(s) in the hierarchy is not managed >+ * @return the identifier for <code>component</code> >+ */ >+ public IComponentIdentifier getComponentIdentifier(Object component) >+ throws ComponentNotManagedException { >+ >+ IComponentIdentifier result = new ComponentIdentifier(); >+ try { >+ // fill the componentIdentifier >+ result.setComponentClassName(component.getClass().getName()); >+ result.setSupportedClassName(AUTServerConfiguration.getInstance() >+ .getTestableClass(component.getClass()).getName()); >+ List<String> hierarchy = getPathToRoot(component); >+ result.setHierarchyNames(hierarchy); >+ result.setNeighbours(getComponentContext(component)); >+ JavaFXHierarchyContainer cont = getHierarchyContainer(component); >+ setAlternativeDisplayName(cont, component, result); >+ if (component.equals(findBP.findComponent(result, >+ ComponentHandler.getAutHierarchy()))) { >+ result.setEqualOriginalFound(true); >+ } >+ return result; >+ } catch (IllegalArgumentException iae) { >+ // from getPathToRoot() >+ log.error(iae); >+ throw new ComponentNotManagedException( >+ "getComponentIdentifier() called for an unmanaged component: " //$NON-NLS-1$ >+ + component, MessageIDs.E_COMPONENT_NOT_MANAGED); >+ // let pass the ComponentNotManagedException from getPathToRoot() >+ } >+ } >+ >+ /** >+ * Searchs for the component in the AUT with the given >+ * <code>componentIdentifier</code>. >+ * >+ * @param componentIdentifier >+ * the identifier created in object mapping mode >+ * @throws IllegalArgumentException >+ * if the given identifer is null or <br> >+ * the hierarchy is not valid: empty or containing null elements >+ * @throws InvalidDataException >+ * if the hierarchy in the componentIdentifier does not consist >+ * of strings >+ * @throws ComponentNotManagedException >+ * if no component could be found for the identifier >+ * @return the instance of the component of the AUT >+ */ >+ public Object findComponent(IComponentIdentifier componentIdentifier) >+ throws IllegalArgumentException, ComponentNotManagedException, >+ InvalidDataException { >+ Object comp = findBP.findComponent(componentIdentifier, >+ ComponentHandler.getAutHierarchy()); >+ >+ if (comp != null) { >+ return comp; >+ } >+ throw new ComponentNotManagedException( >+ "unmanaged component with identifier: '" //$NON-NLS-1$ >+ + componentIdentifier.toString() + "'.", //$NON-NLS-1$ >+ MessageIDs.E_COMPONENT_NOT_MANAGED); >+ } >+ >+ /** >+ * Returns the path from the given component to root. The List contains >+ * Strings (the name of the containers). >+ * >+ * @param component >+ * the component to start, it's an instance from the AUT, must >+ * not be null >+ * @throws IllegalArgumentException >+ * if component is null >+ * @throws ComponentNotManagedException >+ * if no hierarchy conatiner exists for the component >+ * @return the path to root, the first elements contains the root, the last >+ * element contains the component itself. >+ */ >+ public List<String> getPathToRoot(Object component) >+ throws IllegalArgumentException, ComponentNotManagedException { >+ >+ if (log.isInfoEnabled()) { >+ log.info("pathToRoot called for " + component); //$NON-NLS-1$ >+ } >+ Validate.notNull(component, "The component must not be null"); //$NON-NLS-1$ >+ ArrayList<String> hierarchy = new ArrayList<String>(); >+ JavaFXHierarchyContainer container = getHierarchyContainer(component); >+ hierarchy.add(container.getName()); >+ JavaFXHierarchyContainer parent = (JavaFXHierarchyContainer) container >+ .getPrnt(); >+ >+ while (parent != null) { >+ container = parent; >+ hierarchy.add(0, container.getName()); >+ parent = (JavaFXHierarchyContainer) container.getPrnt(); >+ } >+ return hierarchy; >+ } >+ >+ @Override >+ protected List<String> getComponentContext(Object component) { >+ JavaFXHierarchyContainer parent; >+ JavaFXHierarchyContainer comp; >+ List<String> context = new ArrayList<String>(); >+ if (component instanceof JavaFXHierarchyContainer) { >+ comp = (JavaFXHierarchyContainer) component; >+ >+ } else { >+ comp = getHierarchyContainer(component); >+ } >+ parent = (JavaFXHierarchyContainer) comp.getPrnt(); >+ >+ if (parent != null) { >+ JavaFXHierarchyContainer[] comps = parent.getChildren(); >+ for (int i = 0; i < comps.length; i++) { >+ JavaFXHierarchyContainer child = comps[i]; >+ if (!child.equals(comp)) { >+ String toAdd = child.getName(); >+ context.add(toAdd); >+ } >+ } >+ } >+ return context; >+ } >+ >+ /** >+ * Returns the hierarchy container for <code>component</code>. >+ * >+ * @param component >+ * the component from the AUT, must no be null >+ * @throws IllegalArgumentException >+ * if component is null >+ * @return the hierachy container or null if the component is not yet >+ * managed >+ */ >+ public JavaFXHierarchyContainer getHierarchyContainer(Object component) >+ throws IllegalArgumentException { >+ >+ Validate.notNull(component, "The component must not be null"); //$NON-NLS-1$ >+ JavaFXHierarchyContainer result = null; >+ try { >+ JavaFXComponent compID = (JavaFXComponent) getRealMap().get( >+ component); >+ >+ if (compID != null) { >+ result = (JavaFXHierarchyContainer) getHierarchyMap().get( >+ compID); >+ } >+ } catch (ClassCastException cce) { >+ log.error(cce); >+ } catch (NullPointerException npe) { >+ log.error(npe); >+ } >+ return result; >+ } >+ >+ /** >+ * Names the given hierarchy container. <br> >+ * If the managed component has a unique name, this name is used. Otherwise >+ * a name (unique for the hierachy level) is created. >+ * >+ * @param hierarchyContainer >+ * the SwingHierarchyContainer to name, if >+ * SwingHierarchyContainer is null, no action is performed and no >+ * exception is thrown. >+ */ >+ protected void name(JavaFXHierarchyContainer hierarchyContainer) { >+ final JavaFXComponent comp = hierarchyContainer.getComponent(); >+ String compName; >+ Object component; >+ Object realComponent = comp.getRealComponent(); >+ if (realComponent instanceof Node) { >+ component = realComponent; >+ compName = ((Node) component).getId(); >+ } else if (realComponent instanceof MenuItem) { >+ component = realComponent; >+ compName = ((MenuItem) component).getId(); >+ } else { >+ compName = null; >+ component = realComponent; >+ } >+ JavaFXHierarchyContainer hierParent = (JavaFXHierarchyContainer) >+ hierarchyContainer.getPrnt(); >+ >+ if (hierarchyContainer.getName() != null >+ && hierarchyContainer.getName().length() != 0 >+ && !(hierarchyContainer.getName().equals("null"))) { //$NON-NLS-1$ >+ // In extra if, for logging purposes >+ if (isUniqueName(hierParent, hierarchyContainer.getName(), >+ hierarchyContainer)) { >+ return; >+ } else if (log.isInfoEnabled()) { >+ log.info("New name created for " + hierarchyContainer.getName() //$NON-NLS-1$ >+ + "even though there was already a name!"); //$NON-NLS-1$ >+ } >+ } >+ >+ // isUniqueName is null safe, see description there >+ int count = 0; >+ String originalName = null; >+ String newName = null; >+ boolean newNameGenerated = (compName == null); >+ if (compName != null) { >+ originalName = compName; >+ newName = compName; >+ } >+ if (newName == null) { >+ while (!isUniqueName(hierParent, newName, hierarchyContainer)) { >+ count++; >+ newName = createName(component, count); >+ } >+ } else { >+ while (!isUniqueName(hierParent, newName, hierarchyContainer)) { >+ count++; >+ newName = createName(originalName, count); >+ } >+ } >+ comp.setName(newName); >+ hierarchyContainer.setName(newName, newNameGenerated); >+ } >+ >+ /** >+ * Checks for uniqueness of <code>name</code> for the components in >+ * <code>parent</code>.<br> >+ * If parent is null every name is unique, a null name is NEVER unique. If >+ * both parameters are null, false is returned. <br> >+ * >+ * @param parent >+ * the hierarchy container containing the components which are >+ * checked. >+ * @param name >+ * the name to check >+ * @param container >+ * The component for which the name is being checked. >+ * @return true if the name is treated as unique, false otherwise. >+ */ >+ protected boolean isUniqueName(JavaFXHierarchyContainer parent, >+ String name, JavaFXHierarchyContainer container) { >+ if (name == null) { >+ return false; >+ } >+ if (parent == null) { >+ return true; >+ } >+ JavaFXHierarchyContainer[] compIDs = parent.getChildren(); >+ final int length = compIDs.length; >+ >+ for (int index = 0; index < length; index++) { >+ JavaFXHierarchyContainer childContainer = compIDs[index]; >+ String childName = childContainer.getName(); >+ >+ if (name.equals(childName) && childContainer != container) { >+ return false; >+ } >+ } >+ return true; >+ } >+ >+ /** >+ * Returns the lock of the hierarchy >+ * >+ * @return the lock >+ */ >+ public ReentrantLock getLock() { >+ return m_lock; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTListChangeHandler.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTListChangeHandler.java >new file mode 100644 >index 0000000..1811b97 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTListChangeHandler.java >@@ -0,0 +1,43 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import java.util.List; >+ >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+ >+import javafx.collections.ListChangeListener; >+ >+/** >+ * Handles List Changes in the AUT >+ * >+ * @author BREDEX GmbH >+ * @created 24.10.2013 >+ */ >+public class AUTListChangeHandler implements ListChangeListener<Object> { >+ >+ /** Hierarchy **/ >+ private AUTJavaFXHierarchy m_hierarchy = ComponentHandler.getAutHierarchy(); >+ >+ @Override >+ public void onChanged(Change<? extends Object> c) { >+ c.next(); >+ List<? extends Object> changedObjects = c.getAddedSubList(); >+ for (Object o : changedObjects) { >+ m_hierarchy.createHierarchyFrom(o); >+ } >+ changedObjects = c.getRemoved(); >+ for (Object o : changedObjects) { >+ m_hierarchy.removeComponentFromHierarchy(o); >+ } >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTPropertyChangeHandler.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTPropertyChangeHandler.java >new file mode 100644 >index 0000000..44a019c >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/AUTPropertyChangeHandler.java >@@ -0,0 +1,41 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import javafx.beans.value.ChangeListener; >+import javafx.beans.value.ObservableValue; >+ >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+ >+/** >+ * Handles property Changes in the AUT >+ * >+ * @author BREDEX GmbH >+ * @created 24.10.2013 >+ */ >+public class AUTPropertyChangeHandler implements ChangeListener<Object> { >+ >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ AUTPropertyChangeHandler.class); >+ >+ /** Hierarchy **/ >+ private AUTJavaFXHierarchy m_hierarchy = ComponentHandler.getAutHierarchy(); >+ >+ @Override >+ public void changed(ObservableValue<? extends Object> observable, >+ Object oldValue, Object newValue) { >+ m_hierarchy.removeComponentFromHierarchy(oldValue); >+ m_hierarchy.createHierarchyFrom(newValue); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenGetter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenGetter.java >new file mode 100644 >index 0000000..527d792 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenGetter.java >@@ -0,0 +1,174 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import java.util.ArrayList; >+import java.util.List; >+ >+import javafx.beans.property.ObjectProperty; >+import javafx.beans.property.ReadOnlyObjectProperty; >+import javafx.collections.FXCollections; >+import javafx.collections.ObservableList; >+import javafx.scene.Node; >+import javafx.scene.Parent; >+import javafx.scene.Scene; >+import javafx.scene.control.Menu; >+import javafx.scene.control.MenuBar; >+import javafx.scene.control.ScrollPane; >+import javafx.stage.Stage; >+ >+/** >+ * This class handles the receiving of children from different components from a >+ * Hierarchical point of view. >+ * >+ * @author BREDEX GmbH >+ * @created 25.10.2013 >+ */ >+public class ChildrenGetter { >+ >+ /** >+ * Private Constructor >+ */ >+ private ChildrenGetter() { >+ // private >+ } >+ >+ /** >+ * Returns a list of children of a given Object >+ * >+ * @param o >+ * the object >+ * @return the children in a List of Objects. >+ */ >+ public static List<Object> getAsList(Object o) { >+ List<Object> result = new ArrayList<Object>(); >+ if (o instanceof MenuBar) { >+ result.addAll(getFrom((MenuBar) o)); >+ } else if (o instanceof Menu) { >+ result.addAll(getFrom((Menu) o)); >+ } else if (o instanceof Parent) { >+ if (o instanceof ScrollPane) { >+ result.add(getFrom((ScrollPane) o).getValue()); >+ } else { >+ result.addAll(getFrom((Parent) o)); >+ } >+ } else if (o instanceof Stage) { >+ result.add(getFrom((Stage) o).getValue()); >+ } else if (o instanceof Scene) { >+ result.add(getFrom((Scene) o).getValue()); >+ } >+ return result; >+ } >+ >+ /** >+ * Returns either an ObservableList of children or an >+ * <Code>ObjectProperty</Code> of a given Object >+ * >+ * @param o >+ * the object >+ * @return the children in a List of Objects. >+ */ >+ public static Object getAsRealType(Object o) { >+ Object result = null; >+ if (o instanceof MenuBar) { >+ result = getFrom((MenuBar) o); >+ } else if (o instanceof Menu) { >+ result = getFrom((Menu) o); >+ } else if (o instanceof Parent) { >+ if (o instanceof ScrollPane) { >+ result = getFrom((ScrollPane) o); >+ } else { >+ result = getFrom((Parent) o); >+ } >+ } else if (o instanceof Stage) { >+ result = getFrom((Stage) o); >+ } else if (o instanceof Scene) { >+ result = getFrom((Scene) o); >+ } >+ return result; >+ } >+ >+ /** >+ * Returns the Root Property of a Scene. >+ * >+ * @param scene >+ * the Scene >+ * @return Root Property >+ */ >+ public static ReadOnlyObjectProperty<Parent> getFrom(Scene scene) { >+ return scene.rootProperty(); >+ } >+ >+ /** >+ * Returns the Child Property of a Stage, the Scene Property. >+ * >+ * @param stage >+ * the stage >+ * @return the Scene Property >+ */ >+ public static ReadOnlyObjectProperty<Scene> getFrom(Stage stage) { >+ return stage.sceneProperty(); >+ } >+ >+ /** >+ * Returns the Children of a Parent Node, which could be Nodes or other >+ * Parent Nodes. Some of this Nodes are Nodes from the Internal API like the >+ * Text on a Button. >+ * >+ * @param parent >+ * the Parent >+ * @return List with the child nodes >+ */ >+ public static ObservableList<Node> getFrom(Parent parent) { >+ return parent.getChildrenUnmodifiable(); >+ } >+ >+ /** >+ * Even though a ScrollPane is an Instance of Parent, the Hierarchical child >+ * Nodes of a ScrollPane aren't in the Children list, but accessible over >+ * getContent. The Return vale will be one node. >+ * >+ * @param scPane >+ * the ScrollPane >+ * @return List with one Node, the content from the ScrollPane >+ */ >+ public static ObjectProperty<Node> getFrom(ScrollPane scPane) { >+ return scPane.contentProperty(); >+ } >+ >+ /** >+ * Returns a list of MenuItems which also could be a Menu and therefore have >+ * children. >+ * >+ * @param menu >+ * the Menu >+ * @return List with MenuItems >+ */ >+ public static ObservableList<Object> getFrom(Menu menu) { >+ ObservableList<Object> result = FXCollections.observableArrayList(); >+ result.addAll(menu.getItems()); >+ return result; >+ } >+ >+ /** >+ * Returns the Menus on A MenuBar. >+ * >+ * @param menuBar >+ * the MenuBar >+ * @return List with Menus >+ */ >+ public static ObservableList<Object> getFrom(MenuBar menuBar) { >+ ObservableList<Object> result = FXCollections.observableArrayList(); >+ result.addAll(menuBar.getMenus()); >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenListenerHelper.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenListenerHelper.java >new file mode 100644 >index 0000000..637a614 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ChildrenListenerHelper.java >@@ -0,0 +1,80 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import javafx.beans.property.ObjectProperty; >+import javafx.beans.property.ReadOnlyObjectProperty; >+import javafx.collections.ObservableList; >+ >+/** >+ * Helper-Class for adding listeners to children of components, this is relevant >+ * for noticing changes in the AUT and changing the Hierarchy respectively. >+ * >+ * @author BREDEX GmbH >+ * @created 24.10.2013 >+ */ >+public class ChildrenListenerHelper { >+ >+ /** List Handler **/ >+ private static AUTListChangeHandler listhandler = >+ new AUTListChangeHandler(); >+ >+ /** Property Handler **/ >+ private static AUTPropertyChangeHandler prophandler = >+ new AUTPropertyChangeHandler(); >+ >+ /** >+ * Private Constructor >+ */ >+ private ChildrenListenerHelper() { >+ // private >+ } >+ >+ /** >+ * Adds the correct change listener to the given object >+ * >+ * @param list >+ * the list to listen to for changes >+ */ >+ public static void addListener(ObservableList<?> list) { >+ list.addListener(listhandler); >+ } >+ >+ /** >+ * Adds the correct change listener to the given object >+ * >+ * @param prop >+ * the property to listen to for changes >+ */ >+ public static void addListener(ReadOnlyObjectProperty<?> prop) { >+ prop.addListener(prophandler); >+ } >+ >+ /** >+ * Removes the correct change listener from the given object >+ * >+ * @param list >+ * the list to remove the listener from >+ */ >+ public static void removeListener(ObservableList<?> list) { >+ list.removeListener(listhandler); >+ } >+ >+ /** >+ * Removes the correct change listener from the given object >+ * >+ * @param prop >+ * the prop to remove the listener from >+ */ >+ public static void removeListener(ObjectProperty<?> prop) { >+ prop.removeListener(prophandler); >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/CurrentStages.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/CurrentStages.java >new file mode 100644 >index 0000000..e2fc446 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/CurrentStages.java >@@ -0,0 +1,100 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import java.lang.reflect.Field; >+ >+import javafx.collections.ListChangeListener; >+import javafx.collections.ObservableList; >+import javafx.stage.Stage; >+ >+import org.slf4j.Logger; >+import org.slf4j.LoggerFactory; >+ >+/** >+ * Provides access to all instantiated Stages, by accessing a private field in >+ * the <code>Stage</code> class with reflection. Whenever a <code>Stage</code> >+ * is instantiated or closed a reference is stored in this field automatically >+ * by JavaFX. >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ * >+ */ >+public class CurrentStages { >+ >+ /** the logger */ >+ private static final Logger LOG = LoggerFactory >+ .getLogger(CurrentStages.class); >+ >+ /** The Stage list **/ >+ private static ObservableList<Stage> stages; >+ >+ /** private Constructor **/ >+ private CurrentStages() { >+ // private Constructor >+ } >+ >+ static { >+ Class<Stage> stageC = Stage.class; >+ >+ Field stagesField; >+ try { >+ stagesField = stageC.getDeclaredField("stages"); //$NON-NLS-1$ >+ stagesField.setAccessible(true); >+ Object fieldObj = stagesField.get(null); >+ if (fieldObj instanceof ObservableList<?>) { >+ stages = (ObservableList<Stage>) fieldObj; >+ } else { >+ throw new NoSuchFieldException( >+ "The type of the field is not the expected type"); //$NON-NLS-1$ >+ } >+ } catch (NoSuchFieldException | SecurityException >+ | IllegalArgumentException | IllegalAccessException e) { >+ LOG.error(e.getMessage()); >+ } >+ } >+ >+ /** >+ * Gets the first Stage in the list >+ * >+ * @return the Stage >+ */ >+ public static Stage getfirstStage() { >+ return stages.get(0); >+ } >+ >+ /** >+ * Gets the Stage with focus in the list >+ * >+ * @return the Stage >+ */ >+ public static Stage getfocusStage() { >+ Stage fStage = null; >+ for (Stage stage : stages) { >+ if (stage.isFocused()) { >+ fStage = stage; >+ } >+ } >+ return fStage; >+ } >+ >+ /** >+ * Adds a <code>ListChangeListener</code> to the Stages-List >+ * >+ * @param listener >+ * the listener >+ */ >+ public static void addStagesListener(ListChangeListener<Stage> listener) { >+ stages.addListener(listener); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/FindJavaFXComponentBP.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/FindJavaFXComponentBP.java >new file mode 100644 >index 0000000..8eb1979 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/FindJavaFXComponentBP.java >@@ -0,0 +1,83 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import javafx.scene.Node; >+import javafx.scene.Scene; >+import javafx.scene.control.MenuItem; >+import javafx.stage.Stage; >+import javafx.stage.Window; >+ >+import org.eclipse.jubula.rc.common.components.FindComponentBP; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class FindJavaFXComponentBP extends FindComponentBP { >+ >+ /** >+ * Searchs for the component in the AUT with the given >+ * <code>componentIdentifier</code>. >+ * >+ * @param componentIdentifier >+ * the identifier created in object mapping mode >+ * @param autHierarchy >+ * the current aut hierarchy >+ * @throws IllegalArgumentException >+ * if the given identifer is null or <br> >+ * the hierarchy is not valid: empty or containing null elements >+ * @return the instance of the component of the AUT >+ */ >+ public Object findComponent(IComponentIdentifier componentIdentifier, >+ AUTJavaFXHierarchy autHierarchy) throws IllegalArgumentException { >+ return super.findComponent(componentIdentifier, autHierarchy); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public String getCompName(Object currComp) { >+ if (currComp instanceof Scene) { >+ return null; >+ } else if (currComp instanceof Stage) { >+ return null; >+ } else if (currComp instanceof Node) { >+ return ((Node) currComp).getId(); >+ } else { >+ return ((MenuItem) currComp).getId(); >+ } >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public boolean isAvailable(Object currComp) { >+ if (currComp instanceof Scene) { >+ // null check, because it can happen that >+ // a scene instance is found but the >+ // Window property isn't set. >+ // And therefore the scene isn't available >+ Window w = ((Scene) currComp).getWindow(); >+ if (w != null) { >+ return w.isShowing(); >+ } >+ return false; >+ } else if (currComp instanceof Stage) { >+ return ((Stage) currComp).isShowing(); >+ } else if (currComp instanceof Node) { >+ return ((Node) currComp).isVisible(); >+ } else { >+ return ((MenuItem) currComp).isVisible(); >+ } >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXComponent.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXComponent.java >new file mode 100644 >index 0000000..d19ea43 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXComponent.java >@@ -0,0 +1,92 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import javafx.beans.property.ObjectProperty; >+import javafx.beans.property.ReadOnlyObjectProperty; >+import javafx.collections.ObservableList; >+ >+import org.eclipse.jubula.rc.common.components.AUTComponent; >+ >+/** >+ * Wrapper for concrete JavaFX components. >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class JavaFXComponent extends AUTComponent { >+ >+ /** concrete JavaFX component **/ >+ private Object m_realComponent; >+ >+ /** >+ * the type of the component. This is also stored because, on various Points >+ * there has to be a distinction between Stage,Scene and Nodes >+ */ >+ private Class<?> m_type; >+ >+ /** >+ * create an instance from a JavaFX component. This constructor is used when >+ * working with real instances. >+ * >+ * @param component >+ * the JavaFX component >+ * >+ */ >+ public JavaFXComponent(Object component) { >+ super(component); >+ m_type = component.getClass(); >+ m_realComponent = component; >+ addChangeListener(); >+ } >+ >+ /** >+ * >+ * @return the real AUT component instance >+ */ >+ public Object getRealComponent() { >+ return m_realComponent; >+ } >+ >+ /** >+ * >+ * @return the real AUT component type >+ */ >+ public Class<?> getRealComponentType() { >+ return m_type; >+ } >+ >+ /** >+ * Add a change Listener >+ */ >+ public void addChangeListener() { >+ Object children = ChildrenGetter.getAsRealType(m_realComponent); >+ if (children instanceof ReadOnlyObjectProperty) { >+ ChildrenListenerHelper >+ .addListener((ReadOnlyObjectProperty<?>) children); >+ } else if (children instanceof ObservableList) { >+ ChildrenListenerHelper.addListener((ObservableList<?>) children); >+ } >+ } >+ >+ /** >+ * Remove a change Listener >+ */ >+ public void removeChangeListener() { >+ Object children = ChildrenGetter.getAsRealType(m_realComponent); >+ if (children instanceof ObjectProperty) { >+ ChildrenListenerHelper.removeListener((ObjectProperty<?>) children); >+ } else if (children instanceof ObservableList) { >+ ChildrenListenerHelper.removeListener((ObservableList<?>) children); >+ } >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXHierarchyContainer.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXHierarchyContainer.java >new file mode 100644 >index 0000000..3fc7d76 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/JavaFXHierarchyContainer.java >@@ -0,0 +1,104 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import org.eclipse.jubula.rc.common.components.AUTComponent; >+import org.eclipse.jubula.rc.common.components.HierarchyContainer; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+ >+/** >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class JavaFXHierarchyContainer extends HierarchyContainer { >+ >+ /** >+ * Constructor >+ * >+ * @param component >+ * the JavaFXComponentWrapper >+ */ >+ public JavaFXHierarchyContainer(JavaFXComponent component) { >+ super(component); >+ } >+ >+ /** >+ * Constructor >+ * >+ * @param component >+ * the JavaFXComponentWrapper >+ * @param container >+ * the JavaFHierarchyContainer >+ */ >+ public JavaFXHierarchyContainer(AUTComponent component, >+ JavaFXHierarchyContainer container) { >+ super(component, container); >+ } >+ >+ /** >+ * @return JavaFXComponent >+ */ >+ public JavaFXComponent getComponent() { >+ return (JavaFXComponent) super.getCompID(); >+ } >+ >+ /** >+ * Get all child container of this container. >+ * >+ * @return JavaFXHierarchyContainer Array with all children >+ */ >+ public JavaFXHierarchyContainer[] getChildren() { >+ if (super.getComps().length == 0) { >+ return new JavaFXHierarchyContainer[0]; >+ } >+ HierarchyContainer[] containerArray = super.getComps(); >+ JavaFXHierarchyContainer[] fxContainerArray = >+ new JavaFXHierarchyContainer[containerArray.length]; >+ for (int i = 0; i < containerArray.length; i++) { >+ fxContainerArray[i] = (JavaFXHierarchyContainer) containerArray[i]; >+ } >+ return fxContainerArray; >+ } >+ >+ /** >+ * Checks if this container has the given container as child container >+ * >+ * @param child >+ * the child container >+ * @return true if this container has the given container, false if not. >+ */ >+ public boolean contains(JavaFXHierarchyContainer child) { >+ JavaFXHierarchyContainer[] children = getChildren(); >+ for (JavaFXHierarchyContainer cont : children) { >+ if (cont.equals(child)) { >+ return true; >+ } >+ } >+ return false; >+ } >+ >+ /** >+ * Adds a component to the container. Renames it if there is already a >+ * container with this name. >+ * >+ * @param component >+ * The component to add. >+ */ >+ public void add(JavaFXHierarchyContainer component) { >+ if (!(ComponentHandler.getAutHierarchy().isUniqueName(this, >+ component.getName(), component))) { >+ ComponentHandler.getAutHierarchy().name(component); >+ } >+ getContainerList().add(component); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ParentGetter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ParentGetter.java >new file mode 100644 >index 0000000..2925547 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/components/ParentGetter.java >@@ -0,0 +1,111 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.components; >+ >+import javafx.scene.Node; >+import javafx.scene.Scene; >+import javafx.scene.control.Menu; >+import javafx.stage.Stage; >+import javafx.stage.Window; >+ >+/** >+ * This class handles the receiving of Parents from different components from a >+ * Hierarchical point of view. >+ * >+ * @author BREDEX GmbH >+ * @created 25.10.2013 >+ */ >+public class ParentGetter { >+ >+ /** >+ * Private Constructor >+ */ >+ private ParentGetter() { >+ // private >+ } >+ >+ /** >+ * Returns the Parent of a given Object. Will return null if the given >+ * Object has no Parent or isn't handled. >+ * >+ * @param o >+ * the object >+ * @return the Parent as Object. >+ */ >+ public static Object get(Object o) { >+ Object result = null; >+ >+ if (o instanceof Menu) { >+ result = getFrom((Menu) o); >+ } else if (o instanceof Node) { >+ result = getFrom((Node) o); >+ } else if (o instanceof Stage) { >+ result = getFrom((Stage) o); >+ } else if (o instanceof Scene) { >+ result = getFrom((Scene) o); >+ } >+ return result; >+ } >+ >+ /** >+ * >+ * @param scene >+ * the Scene >+ * @return the Parent of the Scene a Window. >+ */ >+ private static Object getFrom(Scene scene) { >+ return scene.getWindow(); >+ } >+ >+ /** >+ * A stage can optionally have an owner Window. >+ * >+ * @param stage >+ * the Stage >+ * @return the owner Window or null >+ */ >+ private static Window getFrom(Stage stage) { >+ return stage.getOwner(); >+ } >+ >+ /** >+ * >+ * @param node >+ * the Node >+ * @return the Parent of the Node or the Scene if the given Node is the Root >+ * node. >+ */ >+ private static Object getFrom(Node node) { >+ Object parent = node.getParent(); >+ if (parent == null) { >+ parent = node.getScene(); >+ } >+ return parent; >+ } >+ >+ /** >+ * >+ * @param menu >+ * the Menu >+ * @return Returns the parent Menu if the given Menu is a sub Menu or the >+ * owner Node >+ */ >+ private static Object getFrom(Menu menu) { >+ Object parent = menu.getParentMenu(); >+ if (parent == null) { >+ parent = menu.getParentPopup().getOwnerNode(); >+ } >+ System.out.println(menu.getParentMenu()); >+ System.out.println(menu.getParentPopup().getOwnerNode()); >+ return parent; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/ClickJavaFXEventMatcher.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/ClickJavaFXEventMatcher.java >new file mode 100644 >index 0000000..25d4989 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/ClickJavaFXEventMatcher.java >@@ -0,0 +1,111 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.util.List; >+ >+import javafx.event.EventType; >+import javafx.scene.input.MouseEvent; >+ >+import org.eclipse.jubula.rc.common.driver.ClickOptions; >+ >+/** >+ * This event matcher checks wether a mouse click event matches the requested >+ * properties. The properties are defined by a <code>ClickOptions</code> >+ * instance. >+ * >+ * @author BREDEX GmbH >+ * @created 31.10.2013 >+ */ >+public class ClickJavaFXEventMatcher extends >+ DefaultJavaFXEventMatcher<MouseEvent> { >+ >+ /** The click options. */ >+ private ClickOptions m_clickOptions; >+ >+ /** >+ * Creates a new matcher instance. >+ * >+ * @param clickOptions >+ * The click options containing the properties the event is >+ * checked against. >+ */ >+ public ClickJavaFXEventMatcher(ClickOptions clickOptions) { >+ super(getClickOptionType(clickOptions)); >+ m_clickOptions = clickOptions; >+ } >+ >+ /** >+ * Converts the click type to the corresponding AWT event ID. >+ * >+ * @param cOpt >+ * The click options. >+ * @return The event ID. >+ */ >+ private static EventType<MouseEvent> getClickOptionType(ClickOptions cOpt) { >+ if (cOpt.getClickType() == ClickOptions.ClickType.CLICKED) { >+ >+ return MouseEvent.MOUSE_CLICKED; >+ } >+ return MouseEvent.MOUSE_RELEASED; >+ } >+ >+ /** >+ * @param eventObject >+ * the AWT event >+ * @return The click count if the event is a mouse event, <code>-1</code> >+ * otherwise >+ */ >+ private int getClickCount(Object eventObject) { >+ int count = -1; >+ if (eventObject instanceof MouseEvent) { >+ MouseEvent e = (MouseEvent) eventObject; >+ count = e.getClickCount(); >+ } >+ return count; >+ } >+ >+ /** >+ * @param eventObject >+ * the AWT event >+ * @return <code>true</code> if the click count matches >+ */ >+ private boolean isClickCountMatching(Object eventObject) { >+ return getClickCount(eventObject) == m_clickOptions.getClickCount(); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ @Override >+ public boolean isMatching(Object event) { >+ return isClickCountMatching(event); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ @Override >+ public boolean isFallBackEventMatching(List eventObjects, >+ Object graphicsComponent) { >+ return false; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public String toString() { >+ String str = this.getClass().getName() + " ClickOptions: " //$NON-NLS-1$ >+ + m_clickOptions.toString(); >+ return str; >+ } >+ >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/DefaultJavaFXEventMatcher.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/DefaultJavaFXEventMatcher.java >new file mode 100644 >index 0000000..e14bed9 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/DefaultJavaFXEventMatcher.java >@@ -0,0 +1,65 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.util.List; >+ >+import javafx.event.Event; >+import javafx.event.EventType; >+ >+import org.eclipse.jubula.rc.common.driver.IEventMatcher; >+ >+/** >+ * Eventmatcher should extend this class. >+ * >+ * @param <T> >+ * event type >+ * @author BREDEX GmbH >+ * @created 31.10.2013 >+ */ >+public class DefaultJavaFXEventMatcher<T extends Event> implements >+ IEventMatcher { >+ >+ /** The JavaFX Event that is used as control */ >+ private EventType<T> m_eventToCheck; >+ >+ /** >+ * Creates a new matcher which checks AWT events against the given event ID. >+ * >+ * @param eventType >+ * The JavaFX Event that is used as control. >+ */ >+ public DefaultJavaFXEventMatcher(EventType<T> eventType) { >+ m_eventToCheck = eventType; >+ } >+ >+ @Override >+ public int getEventId() { >+ return 0; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ @Override >+ public boolean isMatching(Object event) { >+ return ((Event) event).getEventType() == m_eventToCheck; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public boolean isFallBackEventMatching(List eventObjects, >+ Object graphicsComponent) { >+ >+ return false; >+ } >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventFlusher.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventFlusher.java >new file mode 100644 >index 0000000..0120d09 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventFlusher.java >@@ -0,0 +1,53 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.awt.Robot; >+ >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+ >+/** >+ * Could be used to ensure that event occur in the right order but currently >+ * only does a Thread.sleep for the given timeout. >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class EventFlusher { >+ >+ /** the logger */ >+ private static AutServerLogger log = >+ new AutServerLogger(EventFlusher.class); >+ >+ /** the robot to use */ >+ private final Robot m_robot; >+ /** the flush timeout to use */ >+ private final Long m_flushTimeout; >+ /** >+ * indicates whether the default toolkit is compatible to the required >+ * toolkit implementation for native event flushing >+ */ >+ private boolean m_isCompatibleToolkit = false; >+ >+ /** >+ * Constructor >+ * >+ * @param robot >+ * the robot >+ * @param flushTimeout >+ * the flush timeout >+ */ >+ public EventFlusher(Robot robot, long flushTimeout) { >+ m_robot = robot; >+ m_flushTimeout = new Long(flushTimeout); >+ >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventThreadQueuerJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventThreadQueuerJavaFXImpl.java >new file mode 100644 >index 0000000..8be4e8b >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/EventThreadQueuerJavaFXImpl.java >@@ -0,0 +1,123 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.util.concurrent.Callable; >+import java.util.concurrent.ExecutionException; >+import java.util.concurrent.FutureTask; >+ >+import javafx.application.Platform; >+ >+import org.apache.commons.lang.Validate; >+import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; >+import org.eclipse.jubula.rc.common.driver.IRunnable; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+ >+/** >+ * Executes the given Callable on the JavaFX-Thread and waits for the >+ * termination >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class EventThreadQueuerJavaFXImpl implements IEventThreadQueuer { >+ >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ EventThreadQueuerJavaFXImpl.class); >+ >+ /** >+ * Executes the given Callable on the JavaFX-Thread and waits for the >+ * termination >+ * >+ * @param name >+ * a name to identifier which Callable is being executed >+ * @param <V> >+ * return value type >+ * @param call >+ * the Callable >+ * @return >+ * @return the return value of the given Callable >+ * @throws ExecutionException >+ * @throws InterruptedException >+ */ >+ public static <V> V invokeAndWait(String name, Callable<V> call) { >+ >+ if (Platform.isFxApplicationThread()) { >+ try { >+ return call.call(); >+ } catch (Exception e) { >+ // the run() method from IRunnable has thrown an exception >+ // -> log on info >+ // -> throw a StepExecutionException >+ Throwable thrown = e.getCause(); >+ if (thrown instanceof StepExecutionException) { >+ if (log.isInfoEnabled()) { >+ log.info(e); >+ } >+ throw (StepExecutionException) thrown; >+ } >+ >+ // any other (unchecked) Exception from IRunnable.run() >+ log.error("exception thrown by '" + name //$NON-NLS-1$ >+ + "':", thrown); //$NON-NLS-1$ >+ throw new StepExecutionException(thrown); >+ } >+ } >+ try { >+ FutureTask<V> task = new FutureTask<>(call); >+ Platform.runLater(task); >+ return task.get(); >+ >+ } catch (InterruptedException ie) { >+ // this (the waiting) thread was interrupted -> error >+ log.error(ie); >+ throw new StepExecutionException(ie); >+ } catch (ExecutionException ee) { >+ // the run() method from IRunnable has thrown an exception >+ // -> log on info >+ // -> throw a StepExecutionException >+ Throwable thrown = ee.getCause(); >+ if (thrown instanceof StepExecutionException) { >+ if (log.isInfoEnabled()) { >+ log.info(ee); >+ } >+ throw (StepExecutionException) thrown; >+ } >+ >+ // any other (unchecked) Exception from IRunnable.run() >+ log.error("exception thrown by '" + name //$NON-NLS-1$ >+ + "':", thrown); //$NON-NLS-1$ >+ throw new StepExecutionException(thrown); >+ } >+ } >+ >+ @Override >+ public Object invokeAndWait(String name, final IRunnable runnable) { >+ >+ return invokeAndWait(name, new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ return runnable.run(); >+ } >+ }); >+ } >+ >+ @Override >+ public void invokeLater(String name, Runnable runnable) { >+ >+ Validate.notNull(runnable, "runnable must not be null"); //$NON-NLS-1$ >+ Platform.runLater(runnable); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/KeyJavaFXEventMatcher.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/KeyJavaFXEventMatcher.java >new file mode 100644 >index 0000000..d5ed9ee >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/KeyJavaFXEventMatcher.java >@@ -0,0 +1,43 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.util.List; >+ >+import javafx.event.EventType; >+import javafx.scene.input.KeyEvent; >+ >+/** >+ * Event matcher for key events. >+ * >+ * @author BREDEX GmbH >+ * @created 1.11.2013 >+ */ >+public class KeyJavaFXEventMatcher extends DefaultJavaFXEventMatcher<KeyEvent> { >+ >+ /** >+ * Creates a new matcher >+ * >+ * @param keyEvent >+ * the key event type that will be checked >+ */ >+ public KeyJavaFXEventMatcher(EventType<KeyEvent> keyEvent) { >+ super(keyEvent); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public boolean isFallBackEventMatching(List eventObjects, >+ Object graphicsComponent) { >+ return false; >+ } >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMotionTrackerJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMotionTrackerJavaFXImpl.java >new file mode 100644 >index 0000000..a022c20 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMotionTrackerJavaFXImpl.java >@@ -0,0 +1,56 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.awt.MouseInfo; >+import java.awt.Point; >+ >+import org.eclipse.jubula.rc.common.driver.IMouseMotionTracker; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+ >+/** >+ * Doesn't really track the mouse, because this is not necessary and would cause >+ * an unnecessary performance overhead. To get the mouse position >+ * MouseInfo.getPointerInfo().getLocation() is used. >+ * >+ * @author BREDEX GmbH >+ * @created 1.11.2013 >+ */ >+public class MouseMotionTrackerJavaFXImpl implements IMouseMotionTracker { >+ /** >+ * The logger. >+ */ >+ private static AutServerLogger log = new AutServerLogger( >+ MouseMotionTrackerJavaFXImpl.class); >+ >+ /** >+ * Add a new Instance of a Mouse Move tracker to all Stages in the Hierarchy >+ */ >+ public MouseMotionTrackerJavaFXImpl() { >+ >+ } >+ >+ /** >+ * This is not implemented, because it is currently not used! >+ * >+ * @return null >+ */ >+ public Object getLastMouseMotionEvent() { >+ return null; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public Point getLastMousePointOnScreen() { >+ return MouseInfo.getPointerInfo().getLocation(); >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMovedEventMatcher.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMovedEventMatcher.java >new file mode 100644 >index 0000000..bd13b28 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/MouseMovedEventMatcher.java >@@ -0,0 +1,35 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import javafx.event.EventType; >+import javafx.scene.input.MouseEvent; >+ >+/** >+ * Matches MOUSE_MOVED or MOUSE_DRAGGED. >+ * >+ * @author BREDEX GmbH >+ * @created 1.11.2013 >+ */ >+public class MouseMovedEventMatcher extends >+ DefaultJavaFXEventMatcher<MouseEvent> { >+ >+ /** >+ * Constructor. >+ * >+ * @param event >+ * the move event type that will be checked >+ */ >+ public MouseMovedEventMatcher(EventType<MouseEvent> event) { >+ super(event); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventConfirmerJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventConfirmerJavaFXImpl.java >new file mode 100644 >index 0000000..47a970a >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventConfirmerJavaFXImpl.java >@@ -0,0 +1,200 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.util.Arrays; >+import java.util.concurrent.LinkedBlockingQueue; >+import java.util.concurrent.TimeUnit; >+ >+import javafx.event.Event; >+import javafx.event.EventHandler; >+import javafx.stage.Stage; >+ >+import org.eclipse.jubula.rc.common.driver.IEventMatcher; >+import org.eclipse.jubula.rc.common.driver.IRobotEventConfirmer; >+import org.eclipse.jubula.rc.common.driver.InterceptorOptions; >+import org.eclipse.jubula.rc.common.driver.RobotTiming; >+import org.eclipse.jubula.rc.common.exception.RobotException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.util.WorkaroundUtil; >+import org.eclipse.jubula.rc.javafx.components.CurrentStages; >+import org.eclipse.jubula.rc.javafx.util.JavaFXEventConverter; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+ >+/** >+ * <p> >+ * This event confirmer works on a class of AWT events defined by an >+ * <code>InterceptorOptions</code> instance. The confirmer adds a >+ * {@link java.awt.event.AWTEventListener} to the AWT event queue using the >+ * <code>InterceptorOptions</code> event mask. >+ * </p> >+ * >+ * <p> >+ * To confirm an event, call <code>waitToConfirm()</code>. >+ * </p> >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+class RobotEventConfirmerJavaFXImpl implements IRobotEventConfirmer, >+ EventHandler<Event> { >+ >+ /** >+ * The logger. >+ */ >+ private static AutServerLogger log = new AutServerLogger( >+ RobotEventConfirmerJavaFXImpl.class); >+ >+ /** >+ * Stores if the confirmer is enabled. >+ */ >+ private boolean m_enabled = false; >+ /** >+ * Stores if the confirmer is being waiting for an event to confirm. >+ */ >+ private boolean m_waiting = false; >+ /** >+ * The interceptor options. >+ */ >+ private InterceptorOptions m_options; >+ /** >+ * The graphics component on which the event occurs. >+ */ >+ private Object m_eventTarget; >+ /** >+ * The event matcher. >+ */ >+ private IEventMatcher m_eventMatcher; >+ /** >+ * Stores all events of a given class after the confirmer has been enabled. >+ */ >+ private LinkedBlockingQueue<Event> m_eventList = >+ new LinkedBlockingQueue<Event>(); >+ >+ /** The stage on which events will be confirmed **/ >+ private Stage m_confirmStage; >+ >+ /** >+ * Creates a new confirmer for a class of events defined by >+ * <code>options</code>. >+ * >+ * @param options >+ * The options. >+ */ >+ protected RobotEventConfirmerJavaFXImpl(InterceptorOptions options) { >+ m_options = options; >+ } >+ >+ @Override >+ public void waitToConfirm(Object eventTarget, IEventMatcher matcher) >+ throws RobotException { >+ waitToConfirm(eventTarget, matcher, >+ RobotTiming.getEventConfirmTimeout()); >+ } >+ >+ @Override >+ public void waitToConfirm(Object eventTarget, IEventMatcher matcher, >+ long pTimeout) throws RobotException { >+ m_eventTarget = eventTarget; >+ m_eventMatcher = matcher; >+ >+ if (log.isDebugEnabled()) { >+ log.debug("Waiting for EventID: " + String.valueOf(matcher) //$NON-NLS-1$ >+ + " on Component: " + String.valueOf(m_eventTarget)); //$NON-NLS-1$ >+ } >+ >+ try { >+ m_waiting = true; >+ >+ try { >+ long timeout = pTimeout; >+ long done = System.currentTimeMillis() + timeout; >+ long now; >+ do { >+ Event e = m_eventList.poll(timeout, TimeUnit.MILLISECONDS); >+ if (e != null && m_eventMatcher.isMatching(e)) { >+ return; >+ } >+ now = System.currentTimeMillis(); >+ timeout = done - now; >+ } while (m_waiting && (timeout > 0)); >+ } catch (InterruptedException e) { >+ throw new RobotException(e); >+ } >+ if (m_waiting) { >+ // I'm still waiting. This means that the event could not >+ // be confirmed during the confirm time interval, that means >+ // the event matcher didn't find a matching event. >+ // But the event matcher may accept a different event, which has >+ // already dispatched, as a fall back. >+ boolean fallBackMatching = m_eventMatcher >+ .isFallBackEventMatching( >+ Arrays.asList(m_eventList.toArray()), >+ m_eventTarget); >+ >+ if (!fallBackMatching && !WorkaroundUtil.isIgnoreTimeout()) { >+ throw new RobotException( >+ "Timeout received before confirming the posted event: " //$NON-NLS-1$ >+ + m_eventMatcher.getEventId(), >+ EventFactory >+ .createActionError( >+ TestErrorEvent. >+ CONFIRMATION_TIMEOUT)); >+ } >+ } >+ >+ } finally { >+ setEnabled(false); >+ } >+ } >+ >+ /** >+ * Enables or disables the confirmer. If the confirmer is enabled, the >+ * JavaFX Filter is added to the currently focused stage so that the >+ * confirmer starts storing events of the configured class of events. If it >+ * is disabled, the listener is removed from the AWT event queue. >+ * >+ * @param enabled >+ * <code>true</code> or <code>false</code>. >+ */ >+ public void setEnabled(boolean enabled) { >+ m_enabled = enabled; >+ m_eventList.clear(); >+ if (m_enabled) { >+ long[] masks = m_options.getEventMask(); >+ for (int i = 0; i < masks.length; i++) { >+ >+ m_confirmStage = CurrentStages.getfocusStage(); >+ m_confirmStage.addEventFilter( >+ JavaFXEventConverter.awtToFX(masks[i]), this); >+ } >+ } else { >+ long[] masks = m_options.getEventMask(); >+ for (int i = 0; i < masks.length; i++) { >+ m_confirmStage.removeEventFilter( >+ JavaFXEventConverter.awtToFX(masks[i]), this); >+ } >+ m_eventList.clear(); >+ } >+ } >+ >+ @Override >+ public void handle(Event event) { >+ try { >+ m_eventList.put(event); >+ } catch (InterruptedException e) { >+ log.error("InterruptedException: " + event //$NON-NLS-1$ >+ + " on Component: " + String.valueOf(m_eventTarget)); //$NON-NLS-1$ >+ } >+ } >+ >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventInterceptorJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventInterceptorJavaFXImpl.java >new file mode 100644 >index 0000000..88e6d62 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotEventInterceptorJavaFXImpl.java >@@ -0,0 +1,39 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import org.eclipse.jubula.rc.common.driver.IRobotEventConfirmer; >+import org.eclipse.jubula.rc.common.driver.IRobotEventInterceptor; >+import org.eclipse.jubula.rc.common.driver.InterceptorOptions; >+ >+/** >+ * This class intercepts JavaFX events defined by the >+ * <code>InterceptorOptions</code>. When <code>intercept()</code> is called, a >+ * new >+ * {@link org.eclipse.jubula.rc.RobotEventConfirmerJavaFXImpl.driver.awtimpl.RobotEventConfirmerAwtImpl} >+ * is created and enabled, so that the confirmer starts collecting events at >+ * once. >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+class RobotEventInterceptorJavaFXImpl implements IRobotEventInterceptor { >+ /** >+ * {@inheritDoc} >+ */ >+ public IRobotEventConfirmer intercept(InterceptorOptions options) { >+ RobotEventConfirmerJavaFXImpl confirmer = >+ new RobotEventConfirmerJavaFXImpl( >+ options); >+ confirmer.setEnabled(true); >+ return confirmer; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryConfig.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryConfig.java >new file mode 100644 >index 0000000..05cc093 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryConfig.java >@@ -0,0 +1,40 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import org.eclipse.jubula.rc.common.driver.IRobotFactory; >+ >+/** >+ * <p> >+ * This class is the entry point when using the Robot API. It creates a Robot >+ * factory instance. At this point of implementation, the configuration always >+ * returns a AWT/Swing factory implementation. >+ * </p> >+ * >+ * The programming model is as follows: >+ * >+ * <pre> >+ * IRobotFactory factory = new RobotFactoryConfig().getRobotFactory(); >+ * IRobot robot = factory.getRobot(); >+ * robot.click(component, null); >+ * </pre> >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class RobotFactoryConfig { >+ /** >+ * @return A new AWT/Swing factory implementation. >+ */ >+ public IRobotFactory getRobotFactory() { >+ return new RobotFactoryJavaFXImpl(); >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryJavaFXImpl.java >new file mode 100644 >index 0000000..63d6762 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotFactoryJavaFXImpl.java >@@ -0,0 +1,87 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; >+import org.eclipse.jubula.rc.common.driver.IMouseMotionTracker; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.driver.IRobotEventInterceptor; >+import org.eclipse.jubula.rc.common.driver.IRobotFactory; >+import org.eclipse.jubula.rc.common.exception.RobotException; >+ >+/** >+ * This factory creates AWT/Swing implementations of the Robot, the interceptor >+ * and the mouse motion tracker. >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class RobotFactoryJavaFXImpl implements IRobotFactory { >+ /** >+ * The Robot. >+ */ >+ private IRobot m_robot; >+ >+ /** >+ * The AWT/Swing interceptor. >+ */ >+ private IRobotEventInterceptor m_interceptor; >+ >+ /** >+ * The AWT/Swing mouse motion tracker. >+ */ >+ private IMouseMotionTracker m_mouseMotionTracker; >+ >+ /** >+ * The AWT event thread queuer. >+ */ >+ private IEventThreadQueuer m_eventThreadQueuer; >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public IRobotEventInterceptor getRobotEventInterceptor() { >+ if (m_interceptor == null) { >+ m_interceptor = new RobotEventInterceptorJavaFXImpl(); >+ } >+ return m_interceptor; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public IRobot getRobot() throws RobotException { >+ if (m_robot == null) { >+ m_robot = new RobotJavaFXImpl(this); >+ } >+ return m_robot; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public IMouseMotionTracker getMouseMotionTracker() { >+ if (m_mouseMotionTracker == null) { >+ m_mouseMotionTracker = new MouseMotionTrackerJavaFXImpl(); >+ } >+ return m_mouseMotionTracker; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public IEventThreadQueuer getEventThreadQueuer() { >+ if (m_eventThreadQueuer == null) { >+ m_eventThreadQueuer = new EventThreadQueuerJavaFXImpl(); >+ } >+ return m_eventThreadQueuer; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotJavaFXImpl.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotJavaFXImpl.java >new file mode 100644 >index 0000000..78d2b3b >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/RobotJavaFXImpl.java >@@ -0,0 +1,976 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.awt.AWTError; >+import java.awt.AWTEvent; >+import java.awt.AWTException; >+import java.awt.MouseInfo; >+import java.awt.Point; >+import java.awt.Rectangle; >+import java.awt.Robot; >+import java.awt.Toolkit; >+import java.awt.image.BufferedImage; >+import java.lang.reflect.InvocationTargetException; >+import java.util.concurrent.Callable; >+ >+import javafx.geometry.BoundingBox; >+import javafx.geometry.Bounds; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.scene.Parent; >+import javafx.scene.Scene; >+import javafx.scene.control.ListView; >+import javafx.scene.control.TableView; >+import javafx.scene.control.TreeCell; >+import javafx.scene.control.TreeView; >+import javafx.scene.input.KeyEvent; >+import javafx.scene.input.MouseEvent; >+import javafx.stage.Screen; >+import javafx.stage.Stage; >+import javafx.stage.Window; >+ >+import javax.swing.UIManager; >+ >+import org.apache.commons.beanutils.PropertyUtils; >+import org.apache.commons.lang.ArrayUtils; >+import org.apache.commons.lang.Validate; >+import org.eclipse.jubula.rc.common.CompSystemConstants; >+import org.eclipse.jubula.rc.common.driver.ClickOptions; >+import org.eclipse.jubula.rc.common.driver.ClickOptions.ClickModifier; >+import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; >+import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; >+import org.eclipse.jubula.rc.common.driver.IMouseMotionTracker; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.driver.IRobotEventConfirmer; >+import org.eclipse.jubula.rc.common.driver.IRobotEventInterceptor; >+import org.eclipse.jubula.rc.common.driver.IRobotFactory; >+import org.eclipse.jubula.rc.common.driver.IRunnable; >+import org.eclipse.jubula.rc.common.driver.InterceptorOptions; >+import org.eclipse.jubula.rc.common.driver.KeyTyper; >+import org.eclipse.jubula.rc.common.driver.MouseMovementStrategy; >+import org.eclipse.jubula.rc.common.driver.RobotTiming; >+import org.eclipse.jubula.rc.common.exception.RobotException; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.util.LocalScreenshotUtil; >+import org.eclipse.jubula.rc.common.util.PointUtil; >+import org.eclipse.jubula.rc.javafx.components.CurrentStages; >+import org.eclipse.jubula.rc.javafx.util.NodeBounds; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+import org.eclipse.jubula.tools.constants.InputConstants; >+import org.eclipse.jubula.tools.constants.StringConstants; >+import org.eclipse.jubula.tools.i18n.I18n; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+ >+/** >+ * <p> >+ * JavaFX implementation but similar to the AWT/Swing implementation of the >+ * <code>IRobot</code> interface. It uses the {@link java.awt.Robot}to move the >+ * mouse and perform clicks. Any mouse move or click is intercepted and >+ * confirmed using the appropriate AWT/Swing implementations of >+ * {@link org.eclipse.jubula.rc.swing.driver.IRobotEventInterceptor}and >+ * {@link org.eclipse.jubula.rc.swing.driver.IRobotEventConfirmer}. >+ * </p> >+ * >+ * <p> >+ * The <code>click()</code> and <code>move()</code> implementations expect that >+ * the graphics component is of type {@link java.awt.Component}and the >+ * constraints object is <code>null</code> or of type {@link java.awt.Rectangle} >+ * . >+ * </p> >+ * >+ * @author BREDEX GmbH >+ * @created 31.10.2013 >+ */ >+public class RobotJavaFXImpl implements IRobot { >+ /** the timeout to flush native events. CURRENTLY NOT USED! */ >+ private static final int FLUSH_TIMEOUT = 1; >+ >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ RobotJavaFXImpl.class); >+ /** max retries to get the location on screen */ >+ private static final int MAX_RETRIES = 1; >+ /** ID of Metal Look and Feel */ >+ private static final String METAL_LAF_ID = "Metal"; //$NON-NLS-1$ >+ /** The AWT Robot instance. */ >+ private Robot m_robot; >+ /** The toolkit utilities. CURRENTLY NOT USED */ >+ private EventFlusher m_eventFlusher; >+ /** The event interceptor. */ >+ private IRobotEventInterceptor m_interceptor; >+ /** The mouse motion tracker. */ >+ private IMouseMotionTracker m_mouseMotionTracker; >+ /** The event thread queuer. */ >+ private IEventThreadQueuer m_queuer; >+ >+ /** >+ * Scrolls to a component, to make it visible. Currently only ListView and >+ * TableView are supported. >+ */ >+ private class Scroller { >+ /** The component to scroll to visible. */ >+ private Node m_component; >+ >+ /** >+ * @param component >+ * The component to scroll to visible. >+ */ >+ public Scroller(Node component) { >+ m_component = component; >+ } >+ >+ /** >+ * Scrolls the component to visible. >+ * >+ * @param component >+ * The component. >+ */ >+ private void scrollObjectToVisible(Node component) { >+ Parent parent = component.getParent(); >+ Node scrollNode = component; >+ for (; (parent != null) && !(parent instanceof ListView) >+ && !(parent instanceof TableView) >+ && !(parent instanceof TreeView); parent = parent >+ .getParent()) { >+ if (parent instanceof TreeCell) { >+ scrollNode = parent; >+ } >+ } >+ if ((parent != null) && (parent instanceof ListView)) { >+ >+ ((ListView) parent).scrollTo(scrollNode); >+ >+ } else if (parent != null && (parent instanceof TableView)) { >+ ((TableView) parent).scrollTo(scrollNode); >+ } else if (parent != null && (parent instanceof TreeView)) { >+ if (scrollNode instanceof TreeCell) { >+ ((TreeView) parent).scrollTo(((TreeView) parent) >+ .getRow(((TreeCell) scrollNode).getTreeItem())); >+ } >+ } >+ } >+ >+ /** >+ * Scrolls the component passed to the constructor to visible. >+ * >+ */ >+ public void scrollToVisible() { >+ scrollObjectToVisible(m_component); >+ } >+ } >+ >+ /** >+ * Creates a new instance. >+ * >+ * @param factory >+ * The Robot factory instance. >+ * @throws RobotException >+ * If the AWT-Robot cannot be created. >+ */ >+ public RobotJavaFXImpl(IRobotFactory factory) throws RobotException { >+ try { >+ m_robot = new Robot(); >+ m_robot.setAutoWaitForIdle(true); >+ m_robot.setAutoDelay(0); >+ } catch (AWTException awte) { >+ log.error(awte); >+ m_robot = null; >+ throw new RobotException(awte); >+ } catch (SecurityException se) { >+ log.error(se); >+ m_robot = null; >+ throw new RobotException(se); >+ } >+ m_interceptor = factory.getRobotEventInterceptor(); >+ m_mouseMotionTracker = factory.getMouseMotionTracker(); >+ m_queuer = factory.getEventThreadQueuer(); >+ m_eventFlusher = new EventFlusher(m_robot, FLUSH_TIMEOUT); >+ } >+ >+ /** >+ * Gets a location inside the component. If <code>offset</code> is >+ * <code>null</code>, it returns the middle of the component otherwise it >+ * adds the offset to the upper left corner. >+ * >+ * @param comp >+ * the component to get the location for >+ * @param offset >+ * the offset >+ * @throws IllegalArgumentException >+ * if <code>component</code> is null >+ * @return the <b>global </b> coordinates of <code>component</code> >+ */ >+ private Point getLocation(Node comp, final Point offset) >+ throws IllegalArgumentException { >+ >+ Validate.notNull(comp, "component must not be null"); //$NON-NLS-1$ >+ >+ Scene s = comp.getScene(); >+ s.getRoot().layout(); >+ >+ Point2D pos = comp.localToScreen(0, 0); >+ >+ double x = pos.getX(); >+ double y = pos.getY(); >+ if (offset == null) { >+ x += comp.getBoundsInParent().getWidth() / 2; >+ y += comp.getBoundsInParent().getHeight() / 2; >+ } else { >+ x += offset.x; >+ y += offset.y; >+ } >+ >+ return new Point(Rounding.round(x), Rounding.round(y)); >+ } >+ >+ /** >+ * Implementation of the mouse click. The mouse is moved into the graphics >+ * component by calling <code>moveImpl()</code> before performing the click. >+ * >+ * @param graphicsComponent >+ * The graphics component to click on >+ * @param constraints >+ * The constraints, must be a <code>java.awt.Rectangle</code> or >+ * <code>null</code>. The constraints are <em>relative</em> to >+ * the location/origin of the <code>graphicsComponent</code>. >+ * @param clickOptions >+ * The click options >+ * @param xPos >+ * xPos in component >+ * @param yPos >+ * yPos in component >+ * @param yAbsolute >+ * true if y-position should be absolute >+ * @param xAbsolute >+ * true if x-position should be absolute >+ * @throws RobotException >+ * If the click delay is interrupted or the event confirmation >+ * receives a timeout. >+ */ >+ private void clickImpl(Object graphicsComponent, Object constraints, >+ ClickOptions clickOptions, int xPos, boolean xAbsolute, int yPos, >+ boolean yAbsolute) throws RobotException { >+ moveImpl(graphicsComponent, (Rectangle) constraints, xPos, xAbsolute, >+ yPos, yAbsolute, clickOptions); >+ clickImpl(graphicsComponent, clickOptions); >+ } >+ >+ /** >+ * Clicks at the current mouse position. >+ * >+ * @param graphicsComp >+ * The component used for confirming the click. >+ * @param clickOp >+ * Configuration for the click. >+ */ >+ private void clickImpl(Object graphicsComp, ClickOptions clickOp) { >+ >+ int buttonMask = getButtonMask(clickOp.getMouseButton()); >+ int clickCount = clickOp.getClickCount(); >+ int[] modifierMask = getModifierMask(clickOp.getClickModifier()); >+ if (clickCount > 0) { >+ IRobotEventConfirmer confirmer = null; >+ if (clickOp.isConfirmClick()) { >+ InterceptorOptions options = new InterceptorOptions( >+ new long[] { AWTEvent.MOUSE_EVENT_MASK }); >+ confirmer = m_interceptor.intercept(options); >+ } >+ try { >+ pressModifier(modifierMask); >+ RobotTiming.sleepPreClickDelay(); >+ >+ for (int i = 0; i < clickCount; i++) { >+ m_robot.mousePress(buttonMask); >+ RobotTiming.sleepPostMouseDownDelay(); >+ >+ m_robot.mouseRelease(buttonMask); >+ RobotTiming.sleepPostMouseUpDelay(); >+ } >+ if (confirmer != null) { >+ confirmer.waitToConfirm(graphicsComp, >+ new ClickJavaFXEventMatcher(clickOp)); >+ } >+ } finally { >+ releaseModifier(modifierMask); >+ } >+ } >+ } >+ >+ /** >+ * @param modifierMask >+ * array of modifiers to press before click >+ */ >+ private void pressModifier(int[] modifierMask) { >+ for (int i = 0; i < modifierMask.length; i++) { >+ keyPress(null, modifierMask[i]); >+ } >+ } >+ >+ /** >+ * @param modifierMask >+ * array of modifiers release after click >+ */ >+ private void releaseModifier(int[] modifierMask) { >+ for (int i = 0; i < modifierMask.length; i++) { >+ keyRelease(null, modifierMask[i]); >+ } >+ } >+ >+ /** >+ * @param clickModifier >+ * the click modifier to use for this click >+ * @return an array of modifiers to press before click and release after >+ * click >+ */ >+ private int[] getModifierMask(ClickModifier clickModifier) { >+ int[] modifier = new int[0]; >+ if (clickModifier.hasModifiers(ClickModifier.M1)) { >+ modifier = ArrayUtils.add(modifier, 1 << 7); >+ } >+ if (clickModifier.hasModifiers(ClickModifier.M2)) { >+ modifier = ArrayUtils.add(modifier, 1 << 6); >+ } >+ if (clickModifier.hasModifiers(ClickModifier.M3)) { >+ modifier = ArrayUtils.add(modifier, 1 << 9); >+ } >+ if (clickModifier.hasModifiers(ClickModifier.M4)) { >+ modifier = ArrayUtils.add(modifier, 1 << 7); >+ } >+ return modifier; >+ } >+ >+ /** >+ * Checks if the mouse has to be moved on <code>p</code> or if the mouse >+ * pointer already resides on this location. >+ * >+ * @param p >+ * The point to move to >+ * @return <code>true</code> if the mouse pointer resides on a different >+ * point, otherwise <code>false</code>. >+ */ >+ private boolean isMouseMoveRequired(Point p) { >+ boolean result = true; >+ Point point = getCurrentMousePosition(); >+ if (point != null) { >+ result = !point.equals(p); >+ if (log.isDebugEnabled()) { >+ log.debug("Last converted screen point : " + point); //$NON-NLS-1$ >+ log.debug("Required screen point : " + p); //$NON-NLS-1$ >+ log.debug("Mouse move required? : " + result); //$NON-NLS-1$ >+ } >+ } >+ return result; >+ } >+ >+ /** >+ * Implementation of the mouse move. The mouse is moved into the graphics >+ * component. >+ * >+ * @param graphicsComponent >+ * The component to move to >+ * @param constraints >+ * The more specific constraints. Use this, for example when you >+ * want the click point to be relative to a part of the component >+ * (e.g. tree node, table cell, etc) rather than the overall >+ * component itself. May be <code>null</code>. >+ * @param xPos >+ * xPos in component >+ * @param yPos >+ * yPos in component >+ * @param xAbsolute >+ * true if x-position should be absolute >+ * @param yAbsolute >+ * true if y-position should be absolute >+ * @param clickOptions >+ * The click options >+ * @throws StepExecutionException >+ * If the click delay is interrupted or the event confirmation >+ * receives a timeout. >+ */ >+ private void moveImpl(final Object graphicsComponent, >+ final Rectangle constraints, final int xPos, >+ final boolean xAbsolute, final int yPos, final boolean yAbsolute, >+ final ClickOptions clickOptions) throws StepExecutionException { >+ Rectangle bounds = getComponentBounds(graphicsComponent, clickOptions); >+ if (constraints != null) { >+ bounds.x += constraints.x; >+ bounds.y += constraints.y; >+ bounds.height = constraints.height; >+ bounds.width = constraints.width; >+ } >+ Point p = PointUtil.calculateAwtPointToGo(xPos, xAbsolute, yPos, >+ yAbsolute, bounds); >+ // Move if necessary >+ if (isMouseMoveRequired(p)) { >+ if (log.isDebugEnabled()) { >+ log.debug("Moving mouse to: " + p); //$NON-NLS-1$ >+ } >+ IRobotEventConfirmer confirmer = null; >+ if (clickOptions.isConfirmClick()) { >+ InterceptorOptions options = new InterceptorOptions( >+ new long[] { AWTEvent.MOUSE_MOTION_EVENT_MASK }); >+ confirmer = m_interceptor.intercept(options); >+ } >+ Point startpoint = m_mouseMotionTracker.getLastMousePointOnScreen(); >+ if (startpoint == null) { >+ // If there is no starting point the center of the root >+ // component is used >+ if (graphicsComponent instanceof Stage) { >+ Stage s = (Stage) graphicsComponent; >+ Node root = s.getScene().getRoot(); >+ startpoint = (root != null) ? getLocation(root, null) >+ : new Point(Rounding.round(s.getWidth() / 2), >+ Rounding.round(s.getHeight() / 2)); >+ } else { >+ Node node = (Node) graphicsComponent; >+ Node root = node.getScene().getRoot(); >+ Node c = (root != null) ? root : node; >+ startpoint = getLocation(c, null); >+ } >+ } >+ final Point[] mouseMove = MouseMovementStrategy.getMovementPath( >+ startpoint, p, clickOptions.getStepMovement(), >+ clickOptions.getFirstHorizontal()); >+ Point currP = new Point(0, 0); >+ for (int i = 0; i < mouseMove.length; i++) { >+ m_robot.mouseMove(mouseMove[i].x, mouseMove[i].y); >+ currP.x = mouseMove[i].x; >+ currP.y = mouseMove[i].y; >+ if (!currP.equals(MouseInfo.getPointerInfo().getLocation())) { >+ mouseMoveFallback(currP); >+ } >+ } >+ if (confirmer != null) { >+ confirmMove(confirmer, graphicsComponent); >+ } >+ } >+ } >+ >+ /** >+ * Checks whether the move was really successful. If not, a few workarounds >+ * are attempted in order to correct the situation. The workarounds are >+ * logged at the warn-level as they are used. If, after all workarounds have >+ * been applied, the mouse pointer is still not at the correct position, >+ * then an error is logged. >+ * >+ * @param pointToGo >+ * The point where the mouse pointer should currently be. >+ */ >+ private void mouseMoveFallback(Point pointToGo) { >+ Point curPoint = MouseInfo.getPointerInfo().getLocation(); >+ int i = 0; >+ while (!(curPoint.equals(pointToGo))) { >+ m_robot.delay(1); >+ curPoint = MouseInfo.getPointerInfo().getLocation(); >+ } >+ } >+ >+ /** >+ * Confirms a move, either a normal move or a drag move. >+ * >+ * @param confirmer >+ * the confirmer >+ * @param comp >+ * the component to confirm for >+ */ >+ private void confirmMove(IRobotEventConfirmer confirmer, Object comp) { >+ if (DragAndDropHelper.getInstance().isDragMode()) { >+ confirmer.waitToConfirm(comp, new MouseMovedEventMatcher( >+ MouseEvent.MOUSE_DRAGGED)); >+ } else { >+ confirmer.waitToConfirm(comp, new MouseMovedEventMatcher( >+ MouseEvent.MOUSE_MOVED)); >+ } >+ } >+ >+ /** >+ * Refreshes the complete layout and returns the bounds of the given >+ * Component. >+ * >+ * @param comp >+ * the Component >+ * @param clickOp >+ * not used >+ * @return Rectangle with the Bounds >+ */ >+ private Rectangle getComponentBounds(final Object comp, >+ ClickOptions clickOp) { >+ Rectangle bounds = null; >+ if (comp instanceof Stage) { >+ Stage s = (Stage) comp; >+ bounds = new Rectangle(new Point(Rounding.round(s.getX()), >+ Rounding.round(s.getY()))); >+ if (s.isFullScreen()) { >+ Screen screen = Screen.getPrimary(); >+ bounds.width = Rounding.round(screen.getBounds().getWidth()); >+ bounds.height = Rounding.round(screen.getBounds().getHeight()); >+ } else { >+ bounds.width = Rounding.round(s.getWidth()); >+ bounds.height = Rounding.round(s.getHeight()); >+ } >+ } else { >+ final Node node = (Node) comp; >+ if (clickOp.isScrollToVisible()) { >+ ensureComponentVisible(node); >+ } >+ bounds = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "Robot get node bounds", new Callable<Rectangle>() { >+ >+ @Override >+ public Rectangle call() throws Exception { >+ Rectangle bs = new Rectangle(getLocation(node, >+ new Point(0, 0))); >+ Bounds b = node.getBoundsInParent(); >+ bs.width = Rounding.round(b.getWidth()); >+ bs.height = Rounding.round(b.getHeight()); >+ return bs; >+ } >+ }); >+ >+ } >+ return bounds; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void click(Object graphicsComponent, Object constraints) >+ throws RobotException { >+ click(graphicsComponent, constraints, ClickOptions.create()); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void click(Object graphicsComponent, Object constraints, >+ ClickOptions clickOptions) throws RobotException { >+ >+ clickImpl(graphicsComponent, constraints, clickOptions, 50, false, 50, >+ false); >+ } >+ >+ /** >+ * Gets the InputEvent-ButtonMask of the given mouse button number >+ * >+ * @param button >+ * the button number >+ * @return the InputEvent button mask >+ */ >+ private int getButtonMask(int button) { >+ switch (button) { >+ case InputConstants.MOUSE_BUTTON_LEFT: >+ return java.awt.event.InputEvent.BUTTON1_MASK; >+ case InputConstants.MOUSE_BUTTON_MIDDLE: >+ return java.awt.event.InputEvent.BUTTON2_MASK; >+ case InputConstants.MOUSE_BUTTON_RIGHT: >+ return java.awt.event.InputEvent.BUTTON3_MASK; >+ default: >+ throw new RobotException("unsupported mouse button", null); //$NON-NLS-1$ >+ } >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void clickAtCurrentPosition(Object graphicsComponent, >+ int clickCount, int button) { >+ ClickOptions clickOptions = new ClickOptions(); >+ clickOptions.setClickCount(clickCount); >+ clickOptions.setMouseButton(button); >+ clickImpl(graphicsComponent, clickOptions); >+ } >+ >+ /** >+ * {@inheritDoc} java.lang.Object) >+ */ >+ public void doubleClick(Object graphicsComponent, Object constraints) >+ throws RobotException { >+ >+ click(graphicsComponent, constraints, ClickOptions.create() >+ .setClickCount(2)); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ */ >+ public void move(Object graphicsComponent, Object constraints) >+ throws RobotException { >+ >+ moveImpl(graphicsComponent, (Rectangle) constraints, 50, false, 50, >+ false, ClickOptions.create()); >+ } >+ >+ /** >+ * {@inheritDoc} <br> >+ * <b>* Currently delegates the key type to the Robot </b> >+ */ >+ public void type(Object graphicsComponent, char c) throws RobotException { >+ >+ Validate.notNull(graphicsComponent, >+ "The graphic component must not be null"); //$NON-NLS-1$ >+ try { >+ keyType(graphicsComponent, >+ java.awt.event.KeyEvent.getExtendedKeyCodeForChar(c)); >+ } catch (AWTError awte) { >+ log.error(awte); >+ throw new RobotException(awte); >+ } catch (SecurityException se) { >+ log.error(se); >+ throw new RobotException(se); >+ } >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void type(Object graphicsComponent, String text) >+ throws RobotException { >+ if (text != null) { >+ for (int i = 0; i < text.length(); i++) { >+ char ch = text.charAt(i); >+ type(graphicsComponent, ch); >+ } >+ } >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void keyType(Object graphicsComponent, int keycode) >+ throws RobotException { >+ try { >+ InterceptorOptions options = new InterceptorOptions( >+ new long[] { AWTEvent.KEY_EVENT_MASK }); >+ IRobotEventConfirmer confirmer = m_interceptor.intercept(options); >+ try { >+ m_robot.keyPress(keycode); >+ } finally { >+ m_robot.keyRelease(keycode); >+ } >+ confirmer.waitToConfirm(graphicsComponent, >+ new KeyJavaFXEventMatcher(KeyEvent.KEY_RELEASED)); >+ } catch (IllegalArgumentException e) { >+ throw new RobotException(e); >+ } >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public String getSystemModifierSpec() { >+ String keyStrokeSpec = CompSystemConstants.MODIFIER_CONTROL; >+ if (!(UIManager.getLookAndFeel().getID().equals(METAL_LAF_ID))) { >+ if (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() >+ == java.awt.Event.META_MASK) { >+ keyStrokeSpec = CompSystemConstants.MODIFIER_META; >+ } else if (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() >+ == java.awt.Event.ALT_MASK) { >+ keyStrokeSpec = CompSystemConstants.MODIFIER_ALT; >+ } >+ } >+ return keyStrokeSpec; >+ } >+ >+ /** >+ * Implements the key press or release. >+ * >+ * @param graphicsComponent >+ * The component, may be <code>null</code> >+ * @param keyCode >+ * The key code >+ * @param press >+ * If <code>true</code>, the key is pressed, otherwise released >+ */ >+ private void keyPressReleaseImpl(Object graphicsComponent, int keyCode, >+ boolean press) { >+ >+ InterceptorOptions options = new InterceptorOptions( >+ new long[] { AWTEvent.KEY_EVENT_MASK }); >+ IRobotEventConfirmer confirmer = m_interceptor.intercept(options); >+ if (press) { >+ m_robot.keyPress(keyCode); >+ } else { >+ m_robot.keyRelease(keyCode); >+ } >+ confirmer.waitToConfirm(graphicsComponent, new KeyJavaFXEventMatcher( >+ press ? KeyEvent.KEY_PRESSED : KeyEvent.KEY_RELEASED)); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void keyPress(Object graphicsComponent, int keycode) >+ throws RobotException { >+ >+ keyPressReleaseImpl(graphicsComponent, keycode, true); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void keyRelease(Object graphicsComponent, int keycode) >+ throws RobotException { >+ >+ keyPressReleaseImpl(graphicsComponent, keycode, false); >+ } >+ >+ /** >+ * a method to turn the toggle keys caps-lock, num-lock and scroll-lock on >+ * and off. If the given key code is one of these buttons otherwise this is >+ * a normal button press. >+ * >+ * @param obj >+ * Component >+ * @param key >+ * to set key Event >+ * @param activated >+ * boolean >+ */ >+ public void keyToggle(Object obj, int key, boolean activated) { >+ keyPressReleaseImpl(null, key, true); >+ keyPressReleaseImpl(null, key, false); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void keyStroke(String keyStrokeSpec) throws RobotException { >+ try { >+ KeyTyper.getInstance().type(keyStrokeSpec, m_interceptor, >+ new KeyJavaFXEventMatcher(KeyEvent.KEY_PRESSED), >+ new KeyJavaFXEventMatcher(KeyEvent.KEY_RELEASED)); >+ } catch (AWTException e) { >+ throw new RobotException(e); >+ } >+ } >+ >+ /** >+ * Ensures that the passed component is visible. >+ * >+ * @param component >+ * The component. >+ * @throws RobotException >+ * If the component's screen location cannot be calculated. >+ */ >+ private void ensureComponentVisible(final Node component) >+ throws RobotException { >+ m_queuer.invokeAndWait("ensureVisible", new IRunnable() { //$NON-NLS-1$ >+ public Object run() { >+ Scroller scroller = new Scroller(component); >+ scroller.scrollToVisible(); >+ return null; >+ } >+ }); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void scrollToVisible(Object graphicsComponent, Object constraints) >+ throws RobotException { >+ >+ ensureComponentVisible((Node) graphicsComponent); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void activateApplication(String method) throws RobotException { >+ try { >+ final Window window = getActiveWindow(); >+ if (window == null) { >+ return; >+ } >+ WindowActivationMethod wam = WindowActivationMethod >+ .createWindowActivationMethod(method, m_robot, m_queuer); >+ wam.activate(window); >+ >+ // Verify that window was successfully activated >+ Window activeWindow = (Window) m_queuer.invokeAndWait( >+ "getActiveWindow", //$NON-NLS-1$ >+ new IRunnable() { >+ public Object run() throws StepExecutionException { >+ >+ if (window.isFocused()) { >+ return window; >+ } >+ return null; >+ } >+ }); >+ if (activeWindow != window) { >+ throw new StepExecutionException( >+ I18n.getString(TestErrorEvent.WINDOW_ACTIVATION_FAILED, >+ true), >+ EventFactory >+ .createActionError( >+ TestErrorEvent. >+ WINDOW_ACTIVATION_FAILED)); >+ } >+ >+ } catch (Exception exc) { >+ throw new RobotException(exc); >+ } >+ } >+ >+ /** >+ * @return The current mouse position as a Point {@inheritDoc} >+ */ >+ public Point getCurrentMousePosition() { >+ return MouseInfo.getPointerInfo().getLocation(); >+ } >+ >+ /** >+ * Guesses the active window. Returns null if no active window is found. >+ * >+ * @return the active window >+ */ >+ private Window getActiveWindow() { >+ return (Window) m_queuer.invokeAndWait("getActiveWindow", //$NON-NLS-1$ >+ new IRunnable() { >+ public Object run() throws StepExecutionException { >+ Window w = CurrentStages.getfocusStage(); >+ if (w == null) { >+ w = CurrentStages.getfirstStage(); >+ ((Stage) w).toFront(); >+ } >+ return w; >+ } >+ }); >+ } >+ >+ /** >+ * >+ * {@inheritDoc} >+ */ >+ public boolean isMouseInComponent(final Object graphicsComponent) { >+ final Point currMousePos = getCurrentMousePosition(); >+ return EventThreadQueuerJavaFXImpl.invokeAndWait("isMouseInComponent", >+ new Callable<Boolean>() { >+ >+ @Override >+ public Boolean call() throws Exception { >+ if (graphicsComponent instanceof Node) { >+ Node comp = (Node) graphicsComponent; >+ comp.getScene().getRoot().layout(); >+ >+ if (currMousePos == null) { >+ return false; >+ } >+ return NodeBounds.checkIfContains(new Point2D( >+ currMousePos.x, currMousePos.y), comp); >+ } else { >+ Stage comp = (Stage) graphicsComponent; >+ comp.getScene().getRoot().layout(); >+ Bounds stageBounds = new BoundingBox(comp.getX(), >+ comp.getY(), comp.getWidth(), comp >+ .getHeight()); >+ return stageBounds.contains(new Point2D( >+ currMousePos.x, currMousePos.y)); >+ } >+ } >+ }); >+ >+ } >+ >+ /** >+ * Presses the given mouse button on the given component in the given >+ * constraints. <br> >+ * <b>Note:</b> Use only for Drag and Drop! To click with the mouse, use >+ * click-methods! >+ * >+ * @param graphicsComponent >+ * the component where to press the mouse button. If null, the >+ * mouse is pressed at the current location. >+ * @param constraints >+ * A constraints object used by the Robot implementation, may be >+ * <code>null</code>. >+ * @param button >+ * the mouse button which is to be pressed. >+ */ >+ public void mousePress(Object graphicsComponent, Object constraints, >+ int button) { >+ DragAndDropHelper.getInstance().setDragMode(true); >+ if (graphicsComponent != null) { >+ move(graphicsComponent, constraints); >+ } >+ >+ RobotTiming.sleepPreClickDelay(); >+ >+ m_robot.mousePress(getButtonMask(button)); >+ } >+ >+ /** >+ * Releases the given mouse button on the given component in the given >+ * constraints. <br> >+ * <b>Note:</b> Use only for Drag and Drop! To click with the mouse, use >+ * click-methods! >+ * >+ * @param graphicsComponent >+ * The graphics component. If null, the mouse button is released >+ * at the current location. >+ * @param constraints >+ * A constraints object used by the Robot implementation, may be >+ * <code>null</code>. >+ * @param button >+ * the mouse button. >+ */ >+ public void mouseRelease(Object graphicsComponent, Object constraints, >+ int button) throws RobotException { >+ if (graphicsComponent != null) { >+ move(graphicsComponent, constraints); >+ } >+ RobotTiming.sleepPreClickDelay(); >+ m_robot.mouseRelease(getButtonMask(button)); >+ DragAndDropHelper.getInstance().setDragMode(false); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void click(Object graphicsComponent, Object constraints, >+ ClickOptions clickOptions, int xPos, boolean xAbsolute, int yPos, >+ boolean yAbsolute) throws RobotException { >+ >+ clickImpl(graphicsComponent, constraints, clickOptions, xPos, >+ xAbsolute, yPos, yAbsolute); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public String getPropertyValue(Object graphicsComp, String propertyName) >+ throws RobotException { >+ String propertyValue = StringConstants.EMPTY; >+ Validate.notNull(graphicsComp, "Tested component must not be null"); //$NON-NLS-1$ >+ try { >+ final Object prop = PropertyUtils.getProperty(graphicsComp, >+ propertyName); >+ propertyValue = String.valueOf(prop); >+ } catch (IllegalAccessException e) { >+ throw new RobotException(e); >+ } catch (InvocationTargetException e) { >+ throw new RobotException(e); >+ } catch (NoSuchMethodException e) { >+ throw new RobotException(e); >+ } >+ >+ return propertyValue; >+ } >+ >+ /** {@inheritDoc} */ >+ public BufferedImage createFullScreenCapture() { >+ return LocalScreenshotUtil.createFullScreenCapture(); >+ } >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/WindowActivationMethod.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/WindowActivationMethod.java >new file mode 100644 >index 0000000..87c5577 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/driver/WindowActivationMethod.java >@@ -0,0 +1,299 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.driver; >+ >+import java.awt.Point; >+import java.awt.Robot; >+import java.awt.event.InputEvent; >+ >+import javafx.stage.Window; >+ >+import org.eclipse.jubula.rc.common.CompSystemConstants; >+import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; >+import org.eclipse.jubula.rc.common.driver.IRunnable; >+import org.eclipse.jubula.rc.common.driver.RobotConfiguration; >+import org.eclipse.jubula.rc.common.driver.RobotTiming; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+ >+/** >+ * @author BREDEX GmbH >+ * @created 26.01.2006 >+ */ >+public abstract class WindowActivationMethod { >+ >+ /** >+ * no operation >+ */ >+ private static class NoneMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public NoneMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return null; >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public void activate(Window window) { >+ // do nothing >+ } >+ } >+ >+ /** >+ * clicks into the title >+ */ >+ private static class TitleMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public TitleMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point(((Rounding.round(window.getWidth())) / 2), 3); >+ } >+ } >+ >+ /** >+ * clicks into the upper left corner >+ */ >+ private static class NorthWestMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public NorthWestMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point(0, 0); >+ } >+ } >+ >+ /** >+ * clicks into the upper right corner >+ */ >+ private static class NorthEastMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public NorthEastMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point((Rounding.round(window.getWidth())) - 1, 0); >+ } >+ } >+ >+ /** >+ * clicks into the bottom left corner >+ */ >+ private static class SouthWestMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public SouthWestMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point(0, (Rounding.round(window.getHeight())) - 1); >+ } >+ } >+ >+ /** >+ * clicks into the center >+ */ >+ private static class CenterMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public CenterMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point((Rounding.round(window.getWidth())) / 2, >+ (Rounding.round(window.getHeight())) / 2); >+ } >+ } >+ >+ /** >+ * clicks into the bottom right corner >+ */ >+ private static class SouthEastMethod extends WindowActivationMethod { >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ public SouthEastMethod(Robot robot, IEventThreadQueuer queuer) { >+ super(robot, queuer); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ protected Point getClickPoint(Window window) { >+ return new Point((Rounding.round(window.getWidth())) - 1, >+ (Rounding.round(window.getHeight())) - 1); >+ } >+ } >+ >+ /** >+ * button used to activate the window >+ */ >+ private static final int ACTIVATE_BTN = InputEvent.BUTTON1_MASK; >+ >+ /** robot */ >+ private final Robot m_robot; >+ /** queuer */ >+ private final IEventThreadQueuer m_queuer; >+ >+ /** >+ * constructor >+ * >+ * @param robot >+ * robot >+ * @param queuer >+ * queuer >+ */ >+ protected WindowActivationMethod(Robot robot, IEventThreadQueuer queuer) { >+ m_robot = robot; >+ m_queuer = queuer; >+ } >+ >+ /** >+ * The point that is clicked to activate the window >+ * >+ * @param window >+ * the window >+ * @return the point >+ */ >+ protected abstract Point getClickPoint(Window window); >+ >+ /** >+ * activates the window >+ * >+ * @param window >+ * window >+ */ >+ public void activate(final Window window) { >+ m_queuer.invokeAndWait("window activate", new IRunnable() { //$NON-NLS-1$ >+ public Object run() throws StepExecutionException { >+ Point pos = new Point(Rounding.round(window.getX()), >+ Rounding.round(window.getY())); >+ Point cp = getClickPoint(window); >+ m_robot.mouseMove(pos.x + cp.x, pos.y + cp.y); >+ m_robot.mousePress(ACTIVATE_BTN); >+ m_robot.mouseRelease(ACTIVATE_BTN); >+ RobotTiming.sleepPostWindowActivationDelay(); >+ return null; >+ } >+ }); >+ } >+ >+ /** >+ * creates an activation method >+ * >+ * @param method >+ * a string representation of the method >+ * @param robot >+ * the robot >+ * @param queuer >+ * the queuer >+ * @return the method >+ */ >+ public static WindowActivationMethod createWindowActivationMethod( >+ String method, Robot robot, IEventThreadQueuer queuer) { >+ >+ if (CompSystemConstants.AAM_AUT_DEFAULT.equals(method)) { >+ return createWindowActivationMethod(RobotConfiguration >+ .getInstance().getDefaultActivationMethod(), robot, queuer); >+ } else if (CompSystemConstants.AAM_NONE.equals(method)) { >+ return new NoneMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_TITLE.equals(method)) { >+ return new TitleMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_NORTHWEST.equals(method)) { >+ return new NorthWestMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_NORTHEAST.equals(method)) { >+ return new NorthEastMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_SOUTHWEST.equals(method)) { >+ return new SouthWestMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_SOUTHEAST.equals(method)) { >+ return new SouthEastMethod(robot, queuer); >+ } else if (CompSystemConstants.AAM_CENTER.equals(method)) { >+ return new CenterMethod(robot, queuer); >+ } else { >+ return new NoneMethod(robot, queuer); >+ } >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/AbstractFXAUTEventHandler.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/AbstractFXAUTEventHandler.java >new file mode 100644 >index 0000000..2f7b9ba >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/AbstractFXAUTEventHandler.java >@@ -0,0 +1,120 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import javafx.application.Platform; >+import javafx.scene.Node; >+import javafx.stage.Stage; >+ >+import org.eclipse.jubula.rc.common.listener.AUTEventListener; >+import org.eclipse.jubula.rc.javafx.util.HighlightNode; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * @author BREDEX GmbH >+ * @created 15.10.2013 >+ */ >+public abstract class AbstractFXAUTEventHandler implements AUTEventListener { >+ >+ /** The current Node **/ >+ private Node m_currentNode; >+ >+ /** >+ * Sets the current <code>Node</code> that will be, or is, highlighted >+ * >+ * @param n >+ * the <code>Node</code> to be highlighted >+ */ >+ public void setCurrentNode(Node n) { >+ if (m_currentNode != null) { >+ lowlightCurrentNode(); >+ } >+ m_currentNode = n; >+ } >+ >+ /** >+ * Returns the current <code>Node</code> that will be, or is, highlighted >+ * >+ * @return the currentNode >+ */ >+ public Node getCurrentNode() { >+ return m_currentNode; >+ } >+ >+ /** >+ * Highlights the current Node >+ */ >+ public void highlightCurrentNode() { >+ if (m_currentNode != null) { >+ HighlightNode.drawHighlight(m_currentNode); >+ } >+ } >+ >+ /** >+ * Lowlights the current Node >+ */ >+ public void lowlightCurrentNode() { >+ if (m_currentNode != null) { >+ HighlightNode.removeHighlight(m_currentNode); >+ } >+ } >+ >+ /** >+ * Adds a <code>MouseHandler</code> to the given stage >+ * >+ * @param s >+ * the Stage >+ */ >+ public abstract void addHandler(Stage s); >+ >+ /** >+ * Removes a <code>MouseHandler</code> from the given stage >+ * >+ * @param s >+ * the Stage >+ */ >+ public abstract void removeHandler(Stage s); >+ >+ @Override >+ public void cleanUp() { >+ HighlightNode.clean(); >+ } >+ >+ @Override >+ public void update() { >+ >+ } >+ >+ @Override >+ public boolean highlightComponent(IComponentIdentifier comp) { >+ Node n = ComponentHandler.findNodeByID(comp); >+ if (n != null) { >+ setCurrentNode(n); >+ // Highlight only in JAVAFX Thread >+ Platform.runLater(new Runnable() { >+ >+ @Override >+ public void run() { >+ highlightCurrentNode(); >+ } >+ }); >+ >+ return true; >+ } >+ return false; >+ } >+ >+ @Override >+ public long[] getEventMask() { >+ >+ return null; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/CheckListener.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/CheckListener.java >new file mode 100644 >index 0000000..4986022 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/CheckListener.java >@@ -0,0 +1,46 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import org.eclipse.jubula.rc.common.listener.AUTEventListener; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * NEEDS MORE DESCRIPTION! >+ * >+ * @author BREDEX GmbH >+ * @created 23.08.2004 >+ */ >+public class CheckListener implements AUTEventListener { >+ >+ @Override >+ public long[] getEventMask() { >+ >+ return null; >+ } >+ >+ @Override >+ public void cleanUp() { >+ >+ } >+ >+ @Override >+ public void update() { >+ >+ } >+ >+ @Override >+ public boolean highlightComponent(IComponentIdentifier comp) { >+ >+ return false; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/ComponentHandler.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/ComponentHandler.java >new file mode 100644 >index 0000000..cea613c >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/ComponentHandler.java >@@ -0,0 +1,280 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import java.util.ArrayList; >+import java.util.List; >+import java.util.Set; >+import java.util.concurrent.locks.ReentrantLock; >+ >+import javafx.collections.ListChangeListener; >+import javafx.event.EventHandler; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.stage.Stage; >+import javafx.stage.WindowEvent; >+ >+import org.eclipse.jubula.rc.common.AUTServerConfiguration; >+import org.eclipse.jubula.rc.common.exception.ComponentNotFoundException; >+import org.eclipse.jubula.rc.common.exception.ComponentNotManagedException; >+import org.eclipse.jubula.rc.common.exception.NoIdentifierForComponentException; >+import org.eclipse.jubula.rc.common.exception.UnsupportedComponentException; >+import org.eclipse.jubula.rc.common.listener.BaseAUTListener; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.javafx.components.AUTJavaFXHierarchy; >+import org.eclipse.jubula.rc.javafx.components.CurrentStages; >+import org.eclipse.jubula.rc.javafx.components.FindJavaFXComponentBP; >+import org.eclipse.jubula.rc.javafx.components.JavaFXComponent; >+import org.eclipse.jubula.rc.javafx.util.NodeBounds; >+import org.eclipse.jubula.tools.constants.TimingConstantsServer; >+import org.eclipse.jubula.tools.exception.InvalidDataException; >+import org.eclipse.jubula.tools.messagehandling.MessageIDs; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * This class is responsible for handling the components of the AUT. <br> >+ * >+ * The static methods for fetching an identifier for a component and getting the >+ * component for an identifier delegates to this AUTHierarchy. >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class ComponentHandler implements ListChangeListener<Stage>, >+ BaseAUTListener { >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ ComponentHandler.class); >+ >+ /** the Container hierarchy of the AUT */ >+ private static AUTJavaFXHierarchy hierarchy = new AUTJavaFXHierarchy(); >+ >+ /** Businessprocess for getting components */ >+ private static FindJavaFXComponentBP findBP = new FindJavaFXComponentBP(); >+ >+ /** >+ * Constructor. Adds itself as ListChangeListener to the Stages-List >+ */ >+ public ComponentHandler() { >+ CurrentStages.addStagesListener(this); >+ } >+ >+ @Override >+ public void onChanged(Change<? extends Stage> change) { >+ change.next(); >+ List<? extends Stage> changedStages = change.getAddedSubList(); >+ for (final Stage stage : changedStages) { >+ stage.setOnShown(new EventHandler<WindowEvent>() { >+ >+ @Override >+ public void handle(WindowEvent event) { >+ hierarchy.createHierarchyFrom(stage); >+ stage.setOnShown(null); >+ } >+ }); >+ >+ } >+ changedStages = change.getRemoved(); >+ for (final Stage stage : changedStages) { >+ hierarchy.removeComponentFromHierarchy(stage); >+ } >+ } >+ >+ @Override >+ public long[] getEventMask() { >+ return null; >+ } >+ >+ /** >+ * @return the Container hierarchy of the AUT >+ */ >+ public static AUTJavaFXHierarchy getAutHierarchy() { >+ return hierarchy; >+ } >+ >+ /** >+ * Searches the hierarchy-map for components that are assignable from the >+ * given type >+ * >+ * @param type >+ * the type to look for >+ * @return List >+ */ >+ public static List<Object> getAssignableFromType(Class<?> type) { >+ Set<JavaFXComponent> keys = hierarchy.getHierarchyMap().keySet(); >+ List<Object> result = new ArrayList<Object>(); >+ for (JavaFXComponent object : keys) { >+ if (object.getRealComponentType().isAssignableFrom(type) >+ || type.isAssignableFrom(object.getRealComponentType())) { >+ result.add(object.getRealComponent()); >+ } >+ } >+ return result; >+ } >+ >+ /** >+ * Searches the hierarchy-map for components of the given type >+ * >+ * @param type >+ * the type to look for >+ * @return List >+ */ >+ public static List<Object> getInstancesOfType(Class<?> type) { >+ Set<JavaFXComponent> keys = hierarchy.getHierarchyMap().keySet(); >+ List<Object> result = new ArrayList<Object>(); >+ for (JavaFXComponent object : keys) { >+ if (type.isAssignableFrom(object.getRealComponentType())) { >+ result.add(object.getRealComponent()); >+ } >+ } >+ return result; >+ } >+ >+ /** >+ * Returns the node under the given point >+ * >+ * @param pos >+ * the point >+ * @return the component >+ */ >+ public static Node getComponentByPos(Point2D pos) { >+ List<Object> comps = getAssignableFromType(Node.class); >+ for (Object component : comps) { >+ Node n = (Node) component; >+ >+ Object clazz = null; >+ try { >+ if (n != null) { >+ clazz = AUTServerConfiguration.getInstance() >+ .getImplementationClass(n.getClass()); >+ } >+ } catch (UnsupportedComponentException | >+ IllegalArgumentException e) { >+ // DO nothing >+ } >+ >+ if (NodeBounds.checkIfContains(pos, n) && clazz != null) { >+ return (Node) component; >+ } >+ } >+ return null; >+ } >+ >+ /** >+ * Investigates the given <code>component</code> for an identifier. It must >+ * be distinct for the whole AUT. To obtain this identifier the AUTHierarchy >+ * is queried. >+ * >+ * @param node >+ * the node to get an identifier for >+ * @throws NoIdentifierForComponentException >+ * if an identifier could not created for <code>component</code> >+ * . >+ * @return the identifier, containing the identification >+ */ >+ public static IComponentIdentifier getIdentifier(Node node) >+ throws NoIdentifierForComponentException { >+ >+ try { >+ return hierarchy.getComponentIdentifier(node); >+ } catch (ComponentNotManagedException cnme) { >+ log.warn(cnme); >+ throw new NoIdentifierForComponentException( >+ "unable to create an identifier for '" //$NON-NLS-1$ >+ + node + "'", //$NON-NLS-1$ >+ MessageIDs.E_COMPONENT_ID_CREATION); >+ } >+ } >+ >+ /** >+ * Finds a Node by id >+ * >+ * @param id >+ * the id >+ * @return the node ore null if there is nothing or something else than a >+ * node found >+ */ >+ public static Node findNodeByID(IComponentIdentifier id) { >+ Object comp = findBP.findComponent(id, hierarchy); >+ if (comp != null && comp instanceof Node) { >+ return (Node) comp; >+ } >+ return null; >+ } >+ >+ /** >+ * Searchs the component in the AUT, which belongs to the given >+ * <code>componentIdentifier</code>. >+ * >+ * @param componentIdentifier >+ * the identifier of the component to search for >+ * @param retry >+ * number of tries to get object >+ * @param timeout >+ * timeout for retries >+ * @throws ComponentNotFoundException >+ * if no component is found for the given identifier. >+ * @throws IllegalArgumentException >+ * if the identifier is null or contains invalid data >+ * {@inheritDoc} >+ * @return the found component >+ */ >+ public static Object findComponent( >+ IComponentIdentifier componentIdentifier, boolean retry, int timeout) >+ throws ComponentNotFoundException, IllegalArgumentException { >+ >+ long start = System.currentTimeMillis(); >+ ReentrantLock lock = hierarchy.getLock(); >+ try { >+ return hierarchy.findComponent(componentIdentifier); >+ } catch (ComponentNotManagedException cnme) { >+ if (retry) { >+ >+ while (System.currentTimeMillis() - start < timeout) { >+ try { >+ lock.lock(); >+ return hierarchy.findComponent(componentIdentifier); >+ } catch (ComponentNotManagedException e) { // NOPMD by zeb >+ // on 10.04.07 >+ // 15:25 >+ // OK, we will throw a corresponding exception later >+ // if we really can't find the component >+ lock.unlock(); >+ try { >+ Thread.sleep(TimingConstantsServer. >+ POLLING_DELAY_FIND_COMPONENT); >+ } catch (InterruptedException e1) { >+ // ok >+ } >+ } catch (InvalidDataException ide) { // NOPMD by zeb on >+ // 10.04.07 15:25 >+ // OK, we will throw a corresponding exception later >+ // if we really can't find the component >+ } >+ } >+ } >+ throw new ComponentNotFoundException(cnme.getMessage(), >+ MessageIDs.E_COMPONENT_NOT_FOUND); >+ } catch (IllegalArgumentException iae) { >+ log.error(iae); >+ throw iae; >+ } catch (InvalidDataException ide) { >+ log.error(ide); >+ throw new ComponentNotFoundException(ide.getMessage(), >+ MessageIDs.E_COMPONENT_NOT_FOUND); >+ } finally { >+ if (lock.isHeldByCurrentThread()) { >+ lock.unlock(); >+ } >+ >+ } >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/KeyAcceptor.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/KeyAcceptor.java >new file mode 100644 >index 0000000..092617e >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/KeyAcceptor.java >@@ -0,0 +1,162 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import javafx.scene.input.InputEvent; >+import javafx.scene.input.KeyCode; >+import javafx.scene.input.KeyEvent; >+import javafx.scene.input.MouseButton; >+import javafx.scene.input.MouseEvent; >+ >+import org.eclipse.jubula.rc.common.AUTServerConfiguration; >+import org.eclipse.jubula.tools.constants.InputConstants; >+ >+/** >+ * This class is responsible for accepting an InputEvent as the (combination of >+ * the) key(s)/mouse button for picking a component in the OBJECT_MAPPING mode. <br> >+ * >+ * @author BREDEX GmbH >+ * @created 18.10.2013 >+ */ >+public class KeyAcceptor { >+ >+ /** >+ * <code>MAPPING_KEY_COMB</code> >+ */ >+ public static final int MAPPING_KEY_COMB = 1; >+ >+ /** >+ * <code>CHECKMODE_KEY_COMB</code> >+ */ >+ public static final int CHECKMODE_KEY_COMB = 2; >+ >+ /** >+ * <code>CHECKCOMP_KEY_COMB</code> >+ */ >+ public static final int CHECKCOMP_KEY_COMB = 3; >+ >+ /** >+ * private Constructor >+ */ >+ private KeyAcceptor() { >+ // private Constructor >+ } >+ >+ /** >+ * The method queried by the <code>MappingListener</code> or >+ * <code>RecordListener</code>. >+ * >+ * @param event >+ * the occured key event >+ * @return true if the combination Ctrl+Alt+<a> or Ctrl+Shift+<a> was >+ * pressed, false otherwise >+ */ >+ public static int accept(InputEvent event) { >+ int keyMod = 0; >+ >+ int inputCode = 0; >+ if (event instanceof KeyEvent) { >+ KeyEvent kEvent = (KeyEvent) event; >+ >+ inputCode = getAWTKeyCode(kEvent); >+ >+ if (kEvent.isAltDown()) { >+ keyMod = keyMod | 1 << 9; >+ } >+ if (kEvent.isShiftDown()) { >+ keyMod = keyMod | 1 << 6; >+ } >+ if (kEvent.isControlDown()) { >+ keyMod = keyMod | 1 << 7; >+ } >+ } else if (event instanceof MouseEvent) { >+ MouseEvent mEvent = (MouseEvent) event; >+ MouseButton button = mEvent.getButton(); >+ >+ switch (button) { >+ case PRIMARY: >+ inputCode = InputConstants.MOUSE_BUTTON_LEFT; >+ break; >+ case MIDDLE: >+ inputCode = InputConstants.MOUSE_BUTTON_MIDDLE; >+ break; >+ case SECONDARY: >+ inputCode = InputConstants.MOUSE_BUTTON_RIGHT; >+ break; >+ default: >+ break; >+ } >+ } >+ if (inputCode == AUTServerConfiguration.getInstance().getKey() >+ || inputCode == AUTServerConfiguration.getInstance() >+ .getMouseButton() >+ && keyMod == AUTServerConfiguration.getInstance().getKeyMod()) { >+ return MAPPING_KEY_COMB; >+ } >+ if (inputCode == AUTServerConfiguration.getInstance().getCheckModeKey() >+ && keyMod == AUTServerConfiguration.getInstance() >+ .getCheckModeKeyMod()) { >+ return CHECKMODE_KEY_COMB; >+ } >+ if (inputCode == AUTServerConfiguration.getInstance().getCheckCompKey() >+ && keyMod == AUTServerConfiguration.getInstance() >+ .getCheckCompKeyMod()) { >+ return CHECKCOMP_KEY_COMB; >+ } >+ return 0; >+ } >+ >+ /** >+ * >+ * @param event >+ * the event >+ * @return the awt key code >+ */ >+ public static int getAWTKeyCode(KeyEvent event) { >+ KeyCode code = event.getCode(); >+ if (code.isLetterKey()) { >+ return java.awt.event.KeyEvent.getExtendedKeyCodeForChar((int) code >+ .getName().charAt(0)); >+ } else if (code.isFunctionKey()) { >+ switch (code) { >+ case F1: >+ return java.awt.event.KeyEvent.VK_F1; >+ case F2: >+ return java.awt.event.KeyEvent.VK_F2; >+ case F3: >+ return java.awt.event.KeyEvent.VK_F3; >+ case F4: >+ return java.awt.event.KeyEvent.VK_F4; >+ case F5: >+ return java.awt.event.KeyEvent.VK_F5; >+ case F6: >+ return java.awt.event.KeyEvent.VK_F6; >+ case F7: >+ return java.awt.event.KeyEvent.VK_F7; >+ case F8: >+ return java.awt.event.KeyEvent.VK_F8; >+ case F9: >+ return java.awt.event.KeyEvent.VK_F9; >+ case F10: >+ return java.awt.event.KeyEvent.VK_F10; >+ case F11: >+ return java.awt.event.KeyEvent.VK_F1; >+ case F12: >+ return java.awt.event.KeyEvent.VK_F12; >+ default: >+ // can not happen >+ break; >+ } >+ } >+ // NUMPAD currently doesn't differ from other keys >+ return 0; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MappingListener.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MappingListener.java >new file mode 100644 >index 0000000..d584e46 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MappingListener.java >@@ -0,0 +1,140 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import javafx.concurrent.WorkerStateEvent; >+import javafx.event.EventHandler; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.scene.input.InputEvent; >+import javafx.scene.input.KeyEvent; >+import javafx.scene.input.MouseEvent; >+import javafx.stage.Stage; >+ >+import org.eclipse.jubula.communication.message.ObjectMappedMessage; >+import org.eclipse.jubula.rc.common.AUTServer; >+import org.eclipse.jubula.rc.common.exception.NoIdentifierForComponentException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.javafx.util.NodeBounds; >+import org.eclipse.jubula.tools.exception.CommunicationException; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * Realizes Object-Mapping. >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class MappingListener extends AbstractFXAUTEventHandler { >+ >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ MappingListener.class); >+ >+ /** The mouse move threshold in ms **/ >+ private static final long THRESHOLD = 100; >+ >+ /** The delta x for mouse move **/ >+ private static final double DX = 0; >+ >+ /** The delta x for mouse move **/ >+ private static final double DY = 0; >+ /** The mouse move handler **/ >+ private MouseMoveDone m_mHandler = new MouseMoveDone(THRESHOLD, DX, DY); >+ >+ /** The highlight handler **/ >+ private HighlightHandler m_hHandler = new HighlightHandler(); >+ >+ /** The key input handler **/ >+ private InputMappingHandler m_iHandler = new InputMappingHandler(); >+ >+ @Override >+ public void addHandler(Stage s) { >+ s.addEventFilter(MouseEvent.MOUSE_CLICKED, m_iHandler); >+ s.addEventFilter(MouseEvent.MOUSE_MOVED, m_mHandler); >+ s.addEventFilter(KeyEvent.KEY_PRESSED, m_iHandler); >+ >+ m_mHandler.addMoveDoneHandler(m_hHandler); >+ } >+ >+ @Override >+ public void removeHandler(Stage s) { >+ s.removeEventFilter(MouseEvent.MOUSE_MOVED, m_mHandler); >+ s.removeEventFilter(MouseEvent.MOUSE_CLICKED, m_iHandler); >+ s.removeEventFilter(KeyEvent.KEY_PRESSED, m_iHandler); >+ >+ m_mHandler.removeMoveDoneHandler(m_hHandler); >+ } >+ >+ /** >+ * Private class for handling "mouse-move-done-events" >+ */ >+ private class HighlightHandler implements EventHandler<WorkerStateEvent> { >+ >+ @Override >+ public void handle(WorkerStateEvent workerEvent) { >+ MouseEvent event = (MouseEvent) workerEvent.getSource().getValue(); >+ Point2D pos = new Point2D(event.getSceneX(), event.getSceneY()); >+ Node currN = getCurrentNode(); >+ if (currN != null) { >+ if (!(NodeBounds.checkIfContains(pos, currN))) { >+ lowlightCurrentNode(); >+ setCurrentNode(null); >+ } >+ } >+ >+ Node n = ComponentHandler.getComponentByPos(pos); >+ >+ if (n != null && n != currN) { >+ >+ setCurrentNode(n); >+ highlightCurrentNode(); >+ } >+ } >+ >+ } >+ >+ /** >+ * Private class for handling keyboard events >+ */ >+ private class InputMappingHandler implements EventHandler<InputEvent> { >+ >+ @Override >+ public void handle(InputEvent event) { >+ if (getCurrentNode() != null >+ && KeyAcceptor.accept(event) == KeyAcceptor. >+ MAPPING_KEY_COMB) { >+ IComponentIdentifier id; >+ try { >+ id = ComponentHandler.getIdentifier(getCurrentNode()); >+ if (log.isInfoEnabled()) { >+ log.info("send a message with identifier for the component '" //$NON-NLS-1$ >+ + id + "'"); //$NON-NLS-1$ >+ } >+ // send a message with the identifier of the selected >+ // component >+ ObjectMappedMessage message = new ObjectMappedMessage(); >+ message.setComponentIdentifier(id); >+ AUTServer.getInstance().getCommunicator().send(message); >+ } catch (NoIdentifierForComponentException nifce) { >+ // no identifier for the component, log this as an error >+ log.error("no identifier for '" + getCurrentNode()); //$NON-NLS-1$ >+ } catch (CommunicationException ce) { >+ log.error(ce); >+ // do nothing here: a closed connection is handled by the >+ // AUTServer >+ } >+ } >+ } >+ >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MouseMoveDone.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MouseMoveDone.java >new file mode 100644 >index 0000000..b9311aa >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/MouseMoveDone.java >@@ -0,0 +1,139 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import java.util.concurrent.Executor; >+import java.util.concurrent.Executors; >+ >+import javafx.application.Platform; >+import javafx.concurrent.Service; >+import javafx.concurrent.Task; >+import javafx.concurrent.WorkerStateEvent; >+import javafx.event.EventHandler; >+import javafx.scene.input.MouseEvent; >+ >+/** >+ * Alters the JavaFx mouse moved event, which is always fired when the mouse >+ * moves on a node, to an event that is only fired when a mouse move is over. >+ * >+ * @author BREDEX GmbH >+ * @created 18.10.2013 >+ */ >+public class MouseMoveDone implements EventHandler<MouseEvent> { >+ >+ /** deadzone on the x-axis **/ >+ private double m_deltaX; >+ >+ /** deadzone on the y-axis **/ >+ private double m_deltaY; >+ >+ /** >+ * threshold the threshold in milliseconds when a mouse move is interpreted >+ * as done >+ **/ >+ private volatile long m_threshold; >+ >+ /** Last event **/ >+ private volatile MouseEvent m_lastEvent; >+ >+ /** Timer Service **/ >+ private Service<MouseEvent> m_timeService; >+ >+ /** >+ * >+ * @param threshold >+ * threshold the threshold in milliseconds when a mouse move is >+ * interpreted as done >+ * @param deltaX >+ * deadzone on the x-axis >+ * @param deltaY >+ * deadzone on the y-axis >+ */ >+ public MouseMoveDone(long threshold, double deltaX, double deltaY) { >+ m_threshold = threshold; >+ m_deltaX = deltaX; >+ m_deltaY = deltaY; >+ >+ m_timeService = new Service<MouseEvent>() { >+ private final Executor m_threadPool = Executors >+ .newFixedThreadPool(1); >+ >+ @Override >+ protected Task<MouseEvent> createTask() { >+ >+ this.setExecutor(m_threadPool); >+ return new WaitingTask(); >+ } >+ }; >+ >+ } >+ >+ @Override >+ public void handle(MouseEvent event) { >+ if (m_lastEvent == null) { >+ m_lastEvent = event; >+ } >+ double currDX = Math.abs((event.getSceneX() - m_lastEvent.getSceneX())); >+ double currDY = Math.abs((event.getSceneX() - m_lastEvent.getSceneX())); >+ if (currDX >= m_deltaX && currDY >= m_deltaY) { >+ m_timeService.restart(); >+ m_lastEvent = event; >+ } >+ } >+ >+ /** >+ * Adds a handler to the Service. This handler will be notified when the >+ * Task in this service succeeds. Therefore when a mouse move is completed. >+ * >+ * @param hl >+ * the handler >+ */ >+ public void addMoveDoneHandler(final EventHandler<WorkerStateEvent> hl) { >+ Platform.runLater(new Runnable() { >+ >+ @Override >+ public void run() { >+ m_timeService.setOnSucceeded(hl); >+ } >+ }); >+ >+ } >+ >+ /** >+ * Removes a handler from the Service. >+ * >+ * @param hl >+ * the handler >+ */ >+ public void removeMoveDoneHandler(final EventHandler<WorkerStateEvent> hl) { >+ Platform.runLater(new Runnable() { >+ >+ @Override >+ public void run() { >+ m_timeService.removeEventHandler( >+ WorkerStateEvent.WORKER_STATE_SUCCEEDED, hl); >+ } >+ }); >+ >+ } >+ >+ /** >+ * Realizes the waiting >+ * >+ */ >+ private class WaitingTask extends Task<MouseEvent> { >+ @Override >+ protected MouseEvent call() throws Exception { >+ Thread.sleep(m_threshold); >+ return m_lastEvent; >+ } >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/RecordListener.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/RecordListener.java >new file mode 100644 >index 0000000..e3fb7e6 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/listener/RecordListener.java >@@ -0,0 +1,46 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.listener; >+ >+import org.eclipse.jubula.rc.common.listener.AUTEventListener; >+import org.eclipse.jubula.tools.objects.IComponentIdentifier; >+ >+/** >+ * Not implemented! >+ * >+ * @author BREDEX GmbH >+ * @created 23.08.2004 >+ */ >+public class RecordListener implements AUTEventListener { >+ >+ @Override >+ public long[] getEventMask() { >+ >+ return null; >+ } >+ >+ @Override >+ public void cleanUp() { >+ >+ } >+ >+ @Override >+ public void update() { >+ >+ } >+ >+ @Override >+ public boolean highlightComponent(IComponentIdentifier comp) { >+ >+ return false; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/JavaFXApplicationTester.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/JavaFXApplicationTester.java >new file mode 100644 >index 0000000..47ccf08 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/JavaFXApplicationTester.java >@@ -0,0 +1,491 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester; >+ >+import java.awt.Rectangle; >+import java.awt.event.KeyEvent; >+import java.util.List; >+import java.util.concurrent.Callable; >+import java.util.concurrent.CountDownLatch; >+import java.util.concurrent.TimeUnit; >+ >+import javafx.beans.value.ChangeListener; >+import javafx.beans.value.ObservableValue; >+import javafx.event.EventHandler; >+import javafx.stage.Stage; >+import javafx.stage.WindowEvent; >+ >+import org.eclipse.jubula.rc.common.AUTServer; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.tester.AbstractApplicationTester; >+import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; >+import org.eclipse.jubula.rc.common.util.MatchUtil; >+import org.eclipse.jubula.rc.common.util.Verifier; >+import org.eclipse.jubula.rc.javafx.components.CurrentStages; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+import org.eclipse.jubula.tools.utils.TimeUtil; >+ >+/** >+ * Tester-Class for the Application as a whole. >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class JavaFXApplicationTester extends AbstractApplicationTester { >+ /** >+ * The logging. >+ */ >+ private static AutServerLogger log = new AutServerLogger( >+ JavaFXApplicationTester.class); >+ >+ @Override >+ public String[] getTextArrayFromComponent() { >+ return null; >+ } >+ >+ @Override >+ public Rectangle getActiveWindowBounds() { >+ Stage window = CurrentStages.getfocusStage(); >+ Rectangle rec = new Rectangle(Rounding.round(window.getX()), >+ Rounding.round(window.getY()), >+ Rounding.round(window.getWidth()), Rounding.round(window >+ .getHeight())); >+ >+ return rec; >+ } >+ >+ @Override >+ protected IRobot getRobot() { >+ return AUTServer.getInstance().getRobot(); >+ } >+ >+ /** >+ * perform a keystroke specified according <a >+ * href=http://java.sun.com/j2se/1.4 >+ * .2/docs/api/javax/swing/KeyStroke.html#getKeyStroke(java.lang.String)> >+ * string representation of a keystroke </a>, >+ * >+ * @param modifierSpec >+ * the string representation of the modifiers >+ * @param keySpec >+ * the string representation of the key >+ */ >+ @Override >+ public void rcKeyStroke(String modifierSpec, String keySpec) { >+ if (keySpec == null || keySpec.trim().length() == 0) { >+ throw new StepExecutionException( >+ "The base key of the key stroke must not be null or empty", //$NON-NLS-1$ >+ EventFactory.createActionError()); >+ } >+ String key = keySpec.trim().toUpperCase(); >+ String mod = KeyStrokeUtil.getModifierString(modifierSpec); >+ if (mod.length() > 0) { >+ getRobot().keyStroke(mod.toString() + " " + key); //$NON-NLS-1$ >+ } else { >+ int code = getKeyCode(key); >+ if (code != -1) { >+ rcKeyType(code); >+ } else { >+ getRobot().keyStroke(key); >+ } >+ } >+ } >+ >+ @Override >+ protected Object getFocusOwner() { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getFocusOwner", new Callable<Object>() { //$NON-NLS-1$ >+ >+ @Override >+ public Object call() throws Exception { >+ Stage s = (Stage) getActiveWindow(); >+ return s.getScene().getFocusOwner(); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ protected int getEventCode(int key) { >+ int event = 0; >+ switch (key) { >+ case 1: >+ event = KeyEvent.VK_NUM_LOCK; >+ break; >+ case 2: >+ event = KeyEvent.VK_CAPS_LOCK; >+ break; >+ case 3: >+ event = KeyEvent.VK_SCROLL_LOCK; >+ break; >+ default: >+ break; >+ } >+ return event; >+ } >+ >+ @Override >+ protected Object getActiveWindow() { >+ return CurrentStages.getfocusStage(); >+ } >+ >+ /** >+ * @param keyCodeName >+ * The name of a key code, e.g. <code>TAB</code> for a tabulator >+ * key code >+ * @return The key code or <code>-1</code>, if the key code name doesn't >+ * exist in the <code>KeyEvent</code> class >+ * @throws StepExecutionException >+ * If the key code name cannot be converted to a key code due to >+ * the reflection call >+ */ >+ public int getKeyCode(String keyCodeName) throws StepExecutionException { >+ int code = -1; >+ String codeName = "VK_" + keyCodeName; //$NON-NLS-1$ >+ try { >+ code = KeyEvent.class.getField(codeName).getInt(KeyEvent.class); >+ } catch (IllegalArgumentException e) { >+ throw new StepExecutionException(e.getMessage(), >+ EventFactory.createActionError()); >+ } catch (SecurityException e) { >+ throw new StepExecutionException(e.getMessage(), >+ EventFactory.createActionError()); >+ } catch (IllegalAccessException e) { >+ throw new StepExecutionException(e.getMessage(), >+ EventFactory.createActionError()); >+ } catch (NoSuchFieldException e) { >+ if (log.isInfoEnabled()) { >+ log.info("The key expression '" + keyCodeName //$NON-NLS-1$ >+ + "' is not a key code, typed as key stroke instead"); //$NON-NLS-1$ >+ } >+ } >+ return code; >+ } >+ >+ /** >+ * Checks for the existence of a window with the given title >+ * >+ * @param title >+ * the title >+ * @param operator >+ * the comparing operator >+ * @param exists >+ * <code>True</code> if the window is expected to exist and be >+ * visible, otherwise <code>false</code>. >+ */ >+ public void rcCheckExistenceOfWindow(final String title, String operator, >+ boolean exists) { >+ Verifier.equals(exists, isStageInHierarchy(title, operator)); >+ } >+ >+ /** >+ * Checks if the Window(Stage) is in in the Hierarchy and therefore open and >+ * accessible. >+ * >+ * @param title >+ * the title of the Stage to look for >+ * @param operator >+ * the operator >+ * @return true if the Stage is open, otherwise false >+ */ >+ private boolean isStageInHierarchy(final String title, >+ final String operator) { >+ // We are doing this on the JavaFX thread to avoid concurrent >+ // modification in the hierarchy map. >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isWindowInHierarchy", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ Stage stage = getStageByTitle(title, operator); >+ if (stage != null) { >+ return true; >+ } >+ return false; >+ } >+ }); >+ return result; >+ } >+ >+ /** >+ * Looks through the Hierarchy for a Stage with a given Title. >+ * >+ * @param title >+ * the Title of the Stage to look for >+ * @param operator >+ * the operator >+ * @return the Stage or null >+ */ >+ private Stage getStageByTitle(final String title, final String operator) { >+ Stage result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getStageByTitle", new Callable<Stage>() { //$NON-NLS-1$ >+ >+ @Override >+ public Stage call() throws Exception { >+ List<Object> stages = ComponentHandler >+ .getAssignableFromType(Stage.class); >+ for (final Object object : stages) { >+ Stage stage = (Stage) object; >+ if (MatchUtil.getInstance().match(stage.getTitle(), >+ title, operator)) { >+ return stage; >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ /** >+ * Waits <code>timeMillSec</code> if the application opens a window with the >+ * given title. >+ * >+ * @param title >+ * the title >+ * @param operator >+ * the comparing operator >+ * @param pTimeout >+ * the time in ms >+ * @param delay >+ * delay after the window is shown >+ */ >+ public void rcWaitForWindow(final String title, String operator, >+ int pTimeout, int delay) { >+ final Stage s = getStageByTitle(title, operator); >+ >+ if (s == null) { >+ log.error("no Window found! In rcWaitForWindowActivation. Title: " >+ + title + "operator: " + operator); >+ throw new StepExecutionException("no Window found!", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent.COMP_NOT_FOUND)); >+ } >+ >+ final CountDownLatch signal = new CountDownLatch(1); >+ final EventHandler<WindowEvent> showHandler = >+ new EventHandler<WindowEvent>() { >+ >+ @Override >+ public void handle(WindowEvent event) { >+ signal.countDown(); >+ } >+ }; >+ >+ boolean isShowing = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcWaitForWindow", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ if (!s.isShowing()) { >+ s.addEventFilter(WindowEvent.WINDOW_SHOWN, >+ showHandler); >+ return false; >+ } >+ return true; >+ } >+ }); >+ if (!isShowing) { >+ try { >+ signal.await(pTimeout, TimeUnit.MILLISECONDS); >+ } catch (InterruptedException e) { >+ throw new StepExecutionException( >+ "Interrupted while waiting for window!", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent. >+ EXECUTION_ERROR)); >+ } finally { >+ s.removeEventFilter(WindowEvent.WINDOW_SHOWN, showHandler); >+ } >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcWaitForWindowConfirm", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return s.isShowing(); >+ } >+ }); >+ if (!result) { >+ throw new StepExecutionException("window did not open", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent.TIMEOUT_EXPIRED)); >+ } >+ } >+ TimeUtil.delay(delay); >+ } >+ >+ /** >+ * Waits <code>timeMillSec</code> if the application activates a window with >+ * the given title. >+ * >+ * @param title >+ * the title >+ * @param operator >+ * the comparing operator >+ * @param pTimeout >+ * the time in ms >+ * @param delay >+ * delay after the window is activated >+ */ >+ public void rcWaitForWindowActivation(final String title, String operator, >+ int pTimeout, int delay) { >+ final Stage s = getStageByTitle(title, operator); >+ >+ if (s == null) { >+ log.error("no Window found! In rcWaitForWindowActivation. Title: " >+ + title + "operator: " + operator); >+ throw new StepExecutionException("no Window found!", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent.EXECUTION_ERROR)); >+ } >+ >+ final CountDownLatch signal = new CountDownLatch(1); >+ final ChangeListener<Boolean> focusListener = >+ new ChangeListener<Boolean>() { >+ >+ @Override >+ public void changed(ObservableValue<? extends Boolean> >+ observable, Boolean oldValue, Boolean newValue) { >+ if (newValue) { >+ signal.countDown(); >+ } >+ } >+ }; >+ >+ boolean isFocused = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcWaitForWindowActivation", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ if (!s.isFocused()) { >+ s.focusedProperty().addListener(focusListener); >+ return false; >+ } >+ return true; >+ } >+ }); >+ if (isFocused) { >+ try { >+ signal.await(pTimeout, TimeUnit.MILLISECONDS); >+ } catch (InterruptedException e) { >+ throw new StepExecutionException( >+ "Interrupted while waiting for window activation!", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent. >+ EXECUTION_ERROR)); >+ } finally { >+ s.focusedProperty().removeListener(focusListener); >+ } >+ boolean result = EventThreadQueuerJavaFXImpl >+ .invokeAndWait( >+ "rcWaitForWindowActivationConfirm", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return s.isFocused(); >+ } >+ }); >+ if (!result) { >+ throw new StepExecutionException("window was not activated", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent.TIMEOUT_EXPIRED)); >+ } >+ } >+ TimeUtil.delay(delay); >+ } >+ >+ /** >+ * Waits <code>timeMillSec</code> if the application closes (or hides) a >+ * window with the given title. If no window with the given title can be >+ * found, then it is assumed that the window has already closed. >+ * >+ * @param title >+ * the title >+ * @param operator >+ * the comparing operator >+ * @param pTimeout >+ * the time in ms >+ * @param delay >+ * delay after the window is closed >+ */ >+ public void rcWaitForWindowToClose(final String title, >+ final String operator, int pTimeout, int delay) { >+ >+ final Stage s = getStageByTitle(title, operator); >+ >+ if (s == null) { >+ return; >+ } >+ >+ final CountDownLatch signal = new CountDownLatch(1); >+ final EventHandler<WindowEvent> closeHandler = >+ new EventHandler<WindowEvent>() { >+ >+ @Override >+ public void handle(WindowEvent event) { >+ signal.countDown(); >+ } >+ }; >+ >+ boolean isClosing = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcWaitForWindowToClose", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ s.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, >+ closeHandler); >+ return false; >+ } >+ }); >+ if (isClosing) { >+ try { >+ signal.await(pTimeout, TimeUnit.MILLISECONDS); >+ } catch (InterruptedException e) { >+ throw new StepExecutionException( >+ "Interrupted while waiting for window closing!", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent.EXECUTION_ERROR)); >+ } finally { >+ s.removeEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, >+ closeHandler); >+ } >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcWaitForWindowToCloseConfirm", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ final Stage tmpS = getStageByTitle(title, operator); >+ >+ if (tmpS == null) { >+ return true; >+ } >+ return false; >+ } >+ }); >+ if (!result) { >+ throw new StepExecutionException("window was not closed", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent.TIMEOUT_EXPIRED)); >+ } >+ } >+ TimeUtil.delay(delay); >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TableTester.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TableTester.java >new file mode 100644 >index 0000000..72ac2a4 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TableTester.java >@@ -0,0 +1,328 @@ >+package org.eclipse.jubula.rc.javafx.tester; >+ >+import java.awt.Point; >+import java.awt.Rectangle; >+import java.awt.event.KeyEvent; >+import java.util.List; >+import java.util.concurrent.Callable; >+ >+import javafx.geometry.Bounds; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.scene.Parent; >+import javafx.scene.control.CheckBox; >+import javafx.scene.control.TableCell; >+import javafx.scene.control.TableColumn; >+import javafx.scene.control.TableView; >+import javafx.scene.control.cell.CheckBoxTableCell; >+ >+import org.eclipse.jubula.rc.common.driver.ClickOptions; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.implclasses.table.Cell; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.tester.AbstractTableTester; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITableComponent; >+import org.eclipse.jubula.rc.common.util.Verifier; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.util.NodeBounds; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+ >+/** >+ * Toolkit specific commands for the <code>TableView</code> >+ * >+ * @author BREDEX GmbH >+ * @created 27.11.2013 >+ */ >+public class TableTester extends AbstractTableTester { >+ /** The AUT Server logger. */ >+ private static AutServerLogger log = new AutServerLogger(TableTester.class); >+ >+ @Override >+ protected Object setEditorToReplaceMode(Object editor, boolean replace) { >+ Object returnvalue = editor; >+ if (replace) { >+ getRobot().clickAtCurrentPosition(editor, 3, 1); >+ } else { >+ returnvalue = getComponent().getRealComponent(); >+ } >+ return returnvalue; >+ } >+ >+ @Override >+ protected Object activateEditor(Cell cell, Rectangle rectangle) { >+ Object table = getComponent().getRealComponent(); >+ getRobot().click(table, rectangle); >+ TableCell<?, ?> realCell = getCellAt(cell.getRow(), cell.getCol()); >+ // Check if setting the cell in its edit state was successful >+ if (realCell.isEditing()) { >+ ClickOptions co = ClickOptions.create().setClickCount(2); >+ getRobot().click(table, rectangle, co); >+ } >+ return realCell; >+ } >+ >+ /** >+ * Returns the TableCell at the given position. >+ * >+ * @param row >+ * the row >+ * @param column >+ * the column >+ * @return the TableCell at the specified position. >+ */ >+ private TableCell<?, ?> getCellAt(final int row, final int column) { >+ TableCell result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getCellText", new Callable<TableCell>() { >+ >+ @Override >+ public TableCell call() throws Exception { >+ TableView<?> table = (TableView<?>) getRealComponent(); >+ table.scrollTo(row); >+ table.scrollToColumnIndex(column); >+ table.layout(); >+ TableColumn<?, ?> col = table >+ .getVisibleLeafColumn(column); >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell<?, ?> cell = (TableCell<?, ?>) o; >+ if (cell.getIndex() == row >+ && cell.getTableColumn() == col) { >+ return cell; >+ } >+ } >+ return null; >+ } >+ >+ }); >+ return result; >+ } >+ >+ @Override >+ protected int getExtendSelectionModifier() { >+ return KeyEvent.VK_CONTROL; >+ } >+ >+ @Override >+ protected Cell getCellAtMousePosition() throws StepExecutionException { >+ final Point p = getRobot().getCurrentMousePosition(); >+ Cell result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getCellAtMousePosition", new Callable<Cell>() { >+ >+ @Override >+ public Cell call() throws Exception { >+ TableView table = (TableView<?>) getRealComponent(); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ table.layout(); >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell<?, ?> cell = (TableCell<?, ?>) o; >+ Rectangle rec = getCellRect(cell); >+ Point2D tablePos = table.localToScreen(0, 0); >+ rec.x = rec.x + Rounding.round(tablePos.getX()); >+ rec.y = rec.y + Rounding.round(tablePos.getY()); >+ if (rec.contains(p) >+ && cell.getTableView().equals(table)) { >+ int col = table.getColumns().indexOf( >+ cell.getTableColumn()); >+ return new Cell(cell.getIndex(), col); >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ /** >+ * Get a rectangle with the Bounds of a cell in its parent. >+ * >+ * @param cell >+ * the cell to get the rectangle from >+ * @return the rectangle >+ */ >+ private Rectangle getCellRect(final TableCell<?, ?> cell) { >+ Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getCellRect", new Callable<Rectangle>() { >+ >+ @Override >+ public Rectangle call() throws Exception { >+ TableView<?> table = (TableView<?>) getRealComponent(); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ table.layout(); >+ Bounds b = cell.getBoundsInParent(); >+ Point2D pos = cell.localToScreen(0, 0); >+ Point2D parentPos = table.localToScreen(0, 0); >+ return new Rectangle(Rounding.round( >+ pos.getX() - parentPos.getX()), >+ Rounding.round(pos.getY() - parentPos.getY()), >+ Rounding.round(b.getWidth()), >+ Rounding.round(b.getHeight())); >+ } >+ >+ }); >+ return result; >+ } >+ >+ @Override >+ protected boolean isMouseOnHeader() { >+ Point p = getRobot().getCurrentMousePosition(); >+ final Point2D pos = new Point2D(p.x, p.y); >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getTableHeader", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ TableView<?> table = (TableView<?>) getRealComponent(); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ table.layout(); >+ Parent header = (Parent) table.lookup("TableHeaderRow"); >+ return NodeBounds.checkIfContains(pos, header); >+ } >+ }); >+ return result; >+ } >+ >+ /** >+ * Toggles the checkbox in the selected row >+ */ >+ public void rcToggleCheckboxInSelectedRow() { >+ int row = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "rcToggleCheckboxInSelectedRow", new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws StepExecutionException { >+ TableView<?> table = (TableView<?>) getRealComponent(); >+ return new Integer(table.getSelectionModel() >+ .getSelectedIndex()); >+ } >+ }); >+ clickCheckBoxFirstColumn(row); >+ } >+ >+ /** >+ * Toggles the checkbox in the row under the Mouse Pointer >+ */ >+ public void rcToggleCheckboxInRowAtMousePosition() { >+ clickCheckBoxFirstColumn(getCellAtMousePosition().getRow()); >+ } >+ >+ /** >+ * Verifies whether the checkbox in the row of the selected cell is checked >+ * >+ * @param checked >+ * true if checkbox in cell should be selected, false otherwise >+ * @throws StepExecutionException >+ * If no cell is selected or the verification fails. >+ */ >+ public void rcVerifyCheckboxInSelectedRow(boolean checked) >+ throws StepExecutionException { >+ int row = ((ITableComponent) getComponent()).getSelectedCell().getRow(); >+ verifyCheckboxInRow(checked, row); >+ } >+ >+ /** >+ * Verifies whether the checkbox in the row under the mouse pointer is >+ * checked >+ * >+ * @param checked >+ * true if checkbox in cell is selected, false otherwise >+ */ >+ public void rcVerifyCheckboxInRowAtMousePosition(boolean checked) { >+ Cell cell = getCellAtMousePosition(); >+ if (cell != null) { >+ int row = cell.getRow(); >+ verifyCheckboxInRow(checked, row); >+ } else { >+ log.error("No Ceckbox found at Mouseposition: " >+ + getRobot().getCurrentMousePosition()); >+ } >+ } >+ >+ /** >+ * Clicks on the CheckBox in the first Column of the given row; >+ * >+ * @param row >+ * the Row >+ */ >+ private void clickCheckBoxFirstColumn(final int row) { >+ >+ Node box = getCheckBoxFirstColumn(row); >+ if (box != null) { >+ getRobot().click(box, null, >+ ClickOptions.create().setClickCount(1).setMouseButton(1)); >+ } >+ } >+ >+ /** >+ * Verifies whether the checkbox in the row with the given >+ * <code>index</code> is checked >+ * >+ * @param checked >+ * true if checkbox in cell is selected, false otherwise >+ * @param row >+ * the row-index of the cell in which the checkbox-state should >+ * be verified >+ */ >+ private void verifyCheckboxInRow(boolean checked, final int row) { >+ final CheckBox box = (CheckBox) getCheckBoxFirstColumn(row); >+ Boolean checkIndex = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "verifyCheckboxInRow", new Callable<Boolean>() { >+ >+ @Override >+ public Boolean call() throws StepExecutionException { >+ return box.isSelected(); >+ } >+ }); >+ Verifier.equals(checked, checkIndex.booleanValue()); >+ } >+ >+ /** >+ * get the CheckBox in the first TableColumn of the given row >+ * >+ * @param row >+ * the Row >+ * @return the CheckBox or null >+ */ >+ private Node getCheckBoxFirstColumn(final int row) { >+ >+ return EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "clickCheckBoxFirstColumn", new Callable<Node>() { >+ >+ @Override >+ public Node call() throws Exception { >+ TableView<?> table = (TableView<?>) getRealComponent(); >+ table.layout(); >+ TableColumn<?, ?> col = table.getVisibleLeafColumn(0); >+ // Check if the CheckBox is realized via a CheckBoxCell >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(CheckBoxTableCell.class); >+ for (Object o : tCells) { >+ CheckBoxTableCell cell = (CheckBoxTableCell) o; >+ if (cell.getTableColumn().equals(col) >+ && cell.getIndex() == row) { >+ return cell.lookup("CheckBox"); >+ } >+ } >+ // No CheckBoxCell found. Now we have to check all >+ // Cells! >+ tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell cell = (TableCell) o; >+ if (cell.getTableColumn().equals(col) >+ && cell.getIndex() == row) { >+ return cell.lookup("CheckBox"); >+ } >+ } >+ return null; >+ } >+ }); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TreeViewTester.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TreeViewTester.java >new file mode 100644 >index 0000000..1533d8c >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/TreeViewTester.java >@@ -0,0 +1,128 @@ >+package org.eclipse.jubula.rc.javafx.tester; >+ >+import java.awt.Point; >+import java.util.List; >+import java.util.concurrent.Callable; >+ >+import javafx.geometry.Point2D; >+import javafx.scene.control.TreeCell; >+import javafx.scene.control.TreeView; >+ >+import org.eclipse.jubula.rc.common.CompSystemConstants; >+import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.tester.AbstractTreeTester; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.util.NodeBounds; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+ >+/** >+ * Tester Class for the <code>TreeView</code>. If you are looking for more >+ * implemented actions on Trees look at <code>TreeOperationContext</code>. >+ * >+ * @author BREDEX GmbH >+ * @created 19.11.2013 >+ */ >+public class TreeViewTester extends AbstractTreeTester { >+ >+ /** The AUT Server logger. */ >+ private static AutServerLogger log = new AutServerLogger( >+ TreeViewTester.class); >+ >+ @Override >+ public void rcVerifyTextAtMousePosition(String txt, String operator) { >+ checkNodeText(new Object[] { getNodeAtMousePosition() }, txt, operator); >+ } >+ >+ @Override >+ protected Object getNodeAtMousePosition() throws StepExecutionException { >+ Point awtPoint = getRobot().getCurrentMousePosition(); >+ final Point2D point = new Point2D(awtPoint.x, awtPoint.y); >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getNodeBounds", new Callable<Object>() { >+ @Override >+ public Object call() throws Exception { >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ ((TreeView) getRealComponent()).layout(); >+ >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TreeCell.class); >+ for (Object o : tCells) { >+ TreeCell<?> cell = (TreeCell<?>) o; >+ if (NodeBounds.checkIfContains(point, cell)) { >+ return cell.getTreeItem(); >+ } >+ } >+ throw new StepExecutionException( >+ "No tree node found at mouse position: " >+ + "X: " + point.getX() >+ + "Y: " + point.getY(), //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent.NOT_FOUND)); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public void rcDragByTextPath(int mouseButton, String modifier, >+ String pathType, int preAscend, String treeTextPath, String operator) { >+ >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ dndHelper.setModifier(modifier); >+ dndHelper.setMouseButton(mouseButton); >+ rcSelect(pathType, preAscend, treeTextPath, operator, 0, 1, >+ CompSystemConstants.EXTEND_SELECTION_NO); >+ pressOrReleaseModifiers(modifier, true); >+ getRobot().mousePress(null, null, mouseButton); >+ >+ } >+ >+ @Override >+ public void rcDropByTextPath(String pathType, int preAscend, >+ String treeTextPath, String operator, int delayBeforeDrop) { >+ >+ try { >+ rcSelect(pathType, preAscend, treeTextPath, operator, 0, 1, >+ CompSystemConstants.EXTEND_SELECTION_NO); >+ waitBeforeDrop(delayBeforeDrop); >+ } finally { >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); >+ pressOrReleaseModifiers(dndHelper.getModifier(), false); >+ } >+ } >+ >+ @Override >+ public void rcDragByIndexPath(int mouseButton, String modifier, >+ String pathType, int preAscend, String treeIndexPath) { >+ >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ dndHelper.setModifier(modifier); >+ dndHelper.setMouseButton(mouseButton); >+ rcSelectByIndices(pathType, preAscend, treeIndexPath, 0, 1, >+ CompSystemConstants.EXTEND_SELECTION_NO); >+ pressOrReleaseModifiers(modifier, true); >+ getRobot().mousePress(null, null, mouseButton); >+ } >+ >+ @Override >+ public void rcDropByIndexPath(String pathType, int preAscend, >+ String treeIndexPath, int delayBeforeDrop) { >+ try { >+ rcSelectByIndices(pathType, preAscend, treeIndexPath, 0, 1, >+ CompSystemConstants.EXTEND_SELECTION_NO); >+ waitBeforeDrop(delayBeforeDrop); >+ } finally { >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); >+ pressOrReleaseModifiers(dndHelper.getModifier(), false); >+ } >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/AbstractComponentAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/AbstractComponentAdapter.java >new file mode 100644 >index 0000000..ec8bc60 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/AbstractComponentAdapter.java >@@ -0,0 +1,62 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.driver.IRobotFactory; >+import org.eclipse.jubula.rc.common.exception.RobotException; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent; >+import org.eclipse.jubula.rc.javafx.driver.RobotFactoryConfig; >+ >+/** >+ * @param <T> >+ * Type of the component >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class AbstractComponentAdapter<T> implements IComponent { >+ >+ /** the component */ >+ private T m_component; >+ >+ /** >+ * Used to store the component into the adapter. >+ * >+ * @param objectToAdapt >+ * the object to adapt >+ */ >+ public AbstractComponentAdapter(T objectToAdapt) { >+ m_component = objectToAdapt; >+ } >+ >+ @Override >+ public T getRealComponent() { >+ return m_component; >+ } >+ >+ @Override >+ public IRobotFactory getRobotFactory() { >+ IRobotFactory robotFactory = new RobotFactoryConfig().getRobotFactory(); >+ return robotFactory; >+ } >+ >+ /** >+ * Gets the Robot. >+ * >+ * @return The Robot >+ * @throws RobotException >+ * If the Robot cannot be created. >+ */ >+ protected IRobot getRobot() throws RobotException { >+ return getRobotFactory().getRobot(); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/ButtonBaseAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/ButtonBaseAdapter.java >new file mode 100644 >index 0000000..4c4fd70 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/ButtonBaseAdapter.java >@@ -0,0 +1,81 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.util.concurrent.Callable; >+ >+import javafx.scene.control.ButtonBase; >+import javafx.scene.control.CheckBox; >+import javafx.scene.control.Toggle; >+ >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IButtonComponent; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+ >+/** >+ * Implementation of the button interface as an adapter which holds the >+ * <code>javax.swing.AbstractButton</code>. >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class ButtonBaseAdapter extends JavaFXComponentAdapter<ButtonBase> >+ implements IButtonComponent { >+ >+ /** >+ * Creates an object with the adapted Button. >+ * >+ * @param objectToAdapt >+ * this must be an object of the Type <code>ButtonBase</code> >+ */ >+ public ButtonBaseAdapter(ButtonBase objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ @Override >+ public String getText() { >+ String text = EventThreadQueuerJavaFXImpl.invokeAndWait("getText", //$NON-NLS-1$ >+ new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ return getRealComponent().getText(); >+ } >+ }); >+ return text; >+ } >+ >+ @Override >+ public boolean isSelected() { >+ final ButtonBase real = getRealComponent(); >+ boolean result = false; >+ if (real.getClass().isAssignableFrom(Toggle.class)) { >+ result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isSelected", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return ((Toggle) real).isSelected(); >+ } >+ }); >+ } else if (real instanceof CheckBox) { >+ result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isSelected", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return ((CheckBox) real).isSelected(); >+ } >+ }); >+ } >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/JavaFXComponentAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/JavaFXComponentAdapter.java >new file mode 100644 >index 0000000..58a814d >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/JavaFXComponentAdapter.java >@@ -0,0 +1,259 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.awt.event.KeyEvent; >+import java.util.HashMap; >+import java.util.Map; >+import java.util.StringTokenizer; >+import java.util.concurrent.Callable; >+ >+import javafx.scene.Node; >+ >+import org.eclipse.jubula.rc.common.CompSystemConstants; >+import org.eclipse.jubula.rc.common.driver.ClickOptions; >+import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.exception.RobotException; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.tester.AbstractMenuTester; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IWidgetComponent; >+import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+import org.eclipse.jubula.tools.utils.TimeUtil; >+ >+/** >+ * Implements the interface for widgets and supports basic methods which are >+ * needed for nearly all JavaFX UI components. >+ * >+ * @param <T> >+ * type of the Component >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class JavaFXComponentAdapter<T extends Node> extends >+ AbstractComponentAdapter<T> implements IWidgetComponent { >+ >+ /** >+ * The Converter Map. >+ */ >+ private static Map converterTable = null; >+ >+ static { >+ converterTable = new HashMap(); >+ converterTable.put(CompSystemConstants.MODIFIER_NONE, new Integer(-1)); >+ converterTable.put(CompSystemConstants.MODIFIER_SHIFT, new Integer( >+ KeyEvent.VK_SHIFT)); >+ converterTable.put(CompSystemConstants.MODIFIER_CONTROL, new Integer( >+ KeyEvent.VK_CONTROL)); >+ converterTable.put(CompSystemConstants.MODIFIER_ALT, new Integer( >+ KeyEvent.VK_ALT)); >+ converterTable.put(CompSystemConstants.MODIFIER_META, new Integer( >+ KeyEvent.VK_META)); >+ converterTable.put(CompSystemConstants.MODIFIER_CMD, new Integer( >+ KeyEvent.VK_META)); >+ converterTable.put(CompSystemConstants.MODIFIER_MOD, new Integer( >+ KeyEvent.VK_CONTROL)); >+ } >+ >+ /** >+ * Used to store the component into the adapter. >+ * >+ * @param objectToAdapt >+ * the object to adapt >+ */ >+ public JavaFXComponentAdapter(T objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ @Override >+ public boolean isShowing() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isShowing", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return getRealComponent().isVisible(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public boolean isEnabled() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isEnabled", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ // because the logic in JavaFX >+ // is switched the return value is inverted >+ return !(getRealComponent().isDisabled()); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public boolean hasFocus() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "hasFocus", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return getRealComponent().isFocused(); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public String getPropteryValue(final String propertyname) { >+ Object prop = EventThreadQueuerJavaFXImpl.invokeAndWait("getProperty", //$NON-NLS-1$ >+ new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ try { >+ return getRobot().getPropertyValue( >+ getRealComponent(), propertyname); >+ } catch (RobotException e) { >+ throw new StepExecutionException( >+ e.getMessage(), >+ EventFactory >+ .createActionError( >+ TestErrorEvent. >+ PROPERTY_NOT_ACCESSABLE)); >+ } >+ } >+ }); >+ return String.valueOf(prop); >+ } >+ >+ @Override >+ public AbstractMenuTester showPopup(int xPos, String xUnits, int yPos, >+ String yUnits, int button) throws StepExecutionException { >+ // Not implemented >+ return null; >+ } >+ >+ @Override >+ public AbstractMenuTester showPopup(int button) { >+ // Not implemented >+ return null; >+ } >+ >+ @Override >+ public void showToolTip(String text, int textSize, int timePerWord, >+ int windowWidth) { >+ // Not Implemented >+ } >+ >+ @Override >+ public void rcDrag(int mouseButton, String modifier, int xPos, >+ String xUnits, int yPos, String yUnits) { >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ dndHelper.setMouseButton(mouseButton); >+ dndHelper.setModifier(modifier); >+ final IRobot robot = getRobot(); >+ clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); >+ pressOrReleaseModifiers(modifier, true); >+ robot.mousePress(null, null, mouseButton); >+ } >+ >+ @Override >+ public void rcDrop(int xPos, String xUnits, int yPos, String yUnits, >+ int delayBeforeDrop) { >+ final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); >+ final String modifier = dndHelper.getModifier(); >+ final int mouseButton = dndHelper.getMouseButton(); >+ try { >+ clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); >+ TimeUtil.delay(delayBeforeDrop); >+ } finally { >+ getRobot().mouseRelease(null, null, mouseButton); >+ pressOrReleaseModifiers(modifier, false); >+ } >+ } >+ >+ /** >+ * Presses or releases the given modifier. >+ * >+ * @param modifier >+ * the modifier. >+ * @param press >+ * if true, the modifier will be pressed. if false, the modifier >+ * will be released. >+ */ >+ private void pressOrReleaseModifiers(String modifier, boolean press) { >+ final IRobot robot = getRobot(); >+ final StringTokenizer modTok = new StringTokenizer( >+ KeyStrokeUtil.getModifierString(modifier), " "); //$NON-NLS-1$ >+ while (modTok.hasMoreTokens()) { >+ final String mod = modTok.nextToken(); >+ final int keyCode = getKeyCode(mod); >+ if (press) { >+ robot.keyPress(null, keyCode); >+ } else { >+ robot.keyRelease(null, keyCode); >+ } >+ } >+ } >+ >+ /** >+ * clicks into the component. >+ * >+ * @param count >+ * amount of clicks >+ * @param button >+ * what mouse button should be used >+ * @param xPos >+ * what x position >+ * @param xUnits >+ * should x position be pixel or percent values >+ * @param yPos >+ * what y position >+ * @param yUnits >+ * should y position be pixel or percent values >+ * @throws StepExecutionException >+ * error >+ */ >+ private void clickDirect(int count, int button, int xPos, String xUnits, >+ int yPos, String yUnits) throws StepExecutionException { >+ >+ getRobot().click( >+ getRealComponent(), >+ null, >+ ClickOptions.create().setClickCount(count) >+ .setMouseButton(button), xPos, >+ xUnits.equalsIgnoreCase(CompSystemConstants.POS_UNIT_PIXEL), >+ yPos, >+ yUnits.equalsIgnoreCase(CompSystemConstants.POS_UNIT_PIXEL)); >+ } >+ >+ @Override >+ public int getKeyCode(String key) { >+ if (key == null) { >+ throw new RobotException("Key is null!", //$NON-NLS-1$ >+ EventFactory.createConfigErrorEvent()); >+ } >+ final Integer keyCode = (Integer) converterTable.get(key.toLowerCase()); >+ if (keyCode == null) { >+ throw new RobotException("No KeyCode found for key '" + key + "'", //$NON-NLS-1$//$NON-NLS-2$ >+ EventFactory.createConfigErrorEvent()); >+ } >+ return keyCode.intValue(); >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/LabelAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/LabelAdapter.java >new file mode 100644 >index 0000000..59893bc >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/LabelAdapter.java >@@ -0,0 +1,54 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.util.concurrent.Callable; >+ >+import javafx.scene.control.Label; >+ >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITextComponent; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+ >+/** >+ * Label Adapter >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class LabelAdapter extends JavaFXComponentAdapter<Label> implements >+ ITextComponent { >+ >+ /** >+ * Creates an object with the adapted Label. >+ * >+ * @param objectToAdapt >+ * this must be an object of the Type <code>Label</code> >+ */ >+ public LabelAdapter(Label objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ /** >+ * {@inheritDoc} >+ */ >+ public String getText() { >+ String text = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<String>() { //$NON-NLS-1$ >+ >+ @Override >+ public String call() throws Exception { >+ return getRealComponent().getText(); >+ } >+ }); >+ return text; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TableAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TableAdapter.java >new file mode 100644 >index 0000000..518387c >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TableAdapter.java >@@ -0,0 +1,456 @@ >+/******************************************************************************* >+ * Copyright (c) 2012 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.awt.Rectangle; >+import java.util.List; >+import java.util.Set; >+import java.util.concurrent.Callable; >+ >+import javafx.collections.ObservableList; >+import javafx.geometry.Bounds; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.scene.Parent; >+import javafx.scene.control.TableCell; >+import javafx.scene.control.TableColumn; >+import javafx.scene.control.TablePosition; >+import javafx.scene.control.TableView; >+import javafx.scene.control.TextField; >+import javafx.scene.control.cell.TextFieldTableCell; >+import javafx.scene.layout.Pane; >+ >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.implclasses.table.Cell; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITableComponent; >+import org.eclipse.jubula.rc.common.util.IndexConverter; >+import org.eclipse.jubula.rc.common.util.MatchUtil; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+import org.eclipse.jubula.tools.objects.event.EventFactory; >+import org.eclipse.jubula.tools.objects.event.TestErrorEvent; >+ >+/** >+ * Adapter for a TableView(Table) >+ * >+ * @author BREDEX GmbH >+ * @created 7.11.2013 >+ */ >+public class TableAdapter extends JavaFXComponentAdapter<TableView> implements >+ ITableComponent { >+ >+ /** The AUT Server logger. */ >+ private static AutServerLogger log = >+ new AutServerLogger(TableAdapter.class); >+ >+ /** >+ * Creates an adapter for a TableView. >+ * >+ * @param objectToAdapt >+ * the object which needed to be adapted >+ */ >+ public TableAdapter(TableView objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ @Override >+ public String getText() { >+ String result = EventThreadQueuerJavaFXImpl.invokeAndWait("getText", >+ new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ ObservableList sCells = getRealComponent() >+ .getSelectionModel().getSelectedCells(); >+ if (!sCells.isEmpty()) { >+ TablePosition pos = (TablePosition) sCells.get(0); >+ return getCellText(pos.getRow(), pos.getColumn()); >+ } >+ throw new StepExecutionException("No selection found", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent. >+ NO_SELECTION)); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public int getColumnCount() { >+ int result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getColumnCount", new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws Exception { >+ return getRealComponent().getColumns().size(); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public int getRowCount() { >+ int result = EventThreadQueuerJavaFXImpl.invokeAndWait("getRowCount", >+ new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws Exception { >+ return getRealComponent().getItems().size(); //$NON-NLS-1$ >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public String getCellText(final int row, final int column) { >+ String result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getCellText", new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ TableView<?> table = getRealComponent(); >+ TableColumn<?, ?> col = table >+ .getVisibleLeafColumn(column); >+ table.scrollTo(row); >+ table.scrollToColumnIndex(column); >+ table.layout(); >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell<?, ?> cell = (TableCell<?, ?>) o; >+ if (cell.getIndex() == row >+ && cell.getTableColumn() == col >+ && cell.getTableView() == table) { >+ String txt = cell.getText(); >+ if (txt == null >+ && cell instanceof TextFieldTableCell >+ && cell.isEditing()) { >+ // The cell is in its editing state, >+ // therefore its text property is empty. >+ // We have to check the TextField for the >+ // text. >+ TextField f = (TextField) cell.getGraphic(); >+ txt = f.getText(); >+ } >+ return txt; >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public String getColumnHeaderText(final int column) { >+ String result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getColumnHeaderText", //$NON-NLS-1$ >+ new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ TableColumn tCol = getRealComponent() >+ .getVisibleLeafColumn(column); >+ return tCol.getText(); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public int getColumnFromString(final String col, final String operator) { >+ Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getColumnFromString", new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws Exception { >+ int column = -2; >+ TableView table = getRealComponent(); >+ try { >+ int usrIdxCol = Integer.parseInt(col); >+ if (usrIdxCol == 0) { >+ usrIdxCol = usrIdxCol + 1; >+ } >+ column = IndexConverter >+ .toImplementationIndex(usrIdxCol); >+ } catch (NumberFormatException nfe) { >+ try { >+ if (table.getColumns().size() <= 0) { >+ throw new StepExecutionException( >+ "No Columns", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent. >+ NO_HEADER)); >+ } >+ int colN = table.getColumns().size(); >+ for (int i = 0; i < colN; i++) { >+ TableColumn c = (TableColumn) table >+ .getColumns().get(i); >+ String header = c.getText(); >+ if (MatchUtil.getInstance().match(header, >+ col, operator)) { >+ column = i; >+ } >+ } >+ } catch (IllegalArgumentException iae) { >+ // do nothing here >+ } >+ } >+ >+ return new Integer(column); >+ } >+ >+ }); >+ return result.intValue(); >+ } >+ >+ @Override >+ public String getRowText(int row) { >+ // TableView does not act like lists >+ return null; >+ } >+ >+ @Override >+ public int getRowFromString(final String row, final String operator) { >+ Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getRowFromString", new Callable<Integer>() { //$NON-NLS-1$ >+ @Override >+ public Integer call() throws Exception { >+ int rowInt = -2; >+ TableView<?> table = getRealComponent(); >+ try { >+ rowInt = IndexConverter >+ .toImplementationIndex(Integer >+ .parseInt(row)); >+ if (rowInt == -1) { >+ if (table.getColumns().size() <= 0) { >+ throw new StepExecutionException( >+ "No Header", //$NON-NLS-1$ >+ EventFactory >+ .createActionError( >+ TestErrorEvent. >+ NO_HEADER)); >+ } >+ } >+ } catch (NumberFormatException nfe) { >+ for (int i = 0; i < table.getItems().size(); i++) { >+ String cellTxt = getCellText(i, 0); >+ if (MatchUtil.getInstance().match(cellTxt, row, >+ operator)) { >+ return new Integer(i); >+ } >+ } >+ } >+ return new Integer(rowInt); >+ } >+ }); >+ return result.intValue(); >+ } >+ >+ @Override >+ public Rectangle getHeaderBounds(final int column) { >+ final Rectangle columnCell = scrollCellToVisible(0, column); >+ Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getHeaderBounds", new Callable<Rectangle>() { >+ >+ @Override >+ public Rectangle call() throws Exception { >+ TableView<?> table = getRealComponent(); >+ TableColumn col = table.getVisibleLeafColumn(column); >+ table.scrollToColumn(col); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ table.layout(); >+ Parent headerRow = (Parent) table >+ .lookup("TableHeaderRow"); >+ Set<Node> columnHeader = headerRow >+ .lookupAll("column-header"); >+ Point2D parentPos = table.localToScreen(0, 0); >+ >+ for (Node n : columnHeader) { >+ Bounds b = n.getBoundsInParent(); >+ Point2D pos = n.localToScreen(0, 0); >+ >+ Rectangle columnRec = new Rectangle(Rounding >+ .round(pos.getX() - parentPos.getX()), >+ Rounding.round(pos.getY() >+ - parentPos.getY()), Rounding >+ .round(b.getWidth()), Rounding >+ .round(b.getHeight())); >+ if (columnCell.x == columnRec.x) { >+ return columnRec; >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public Cell getSelectedCell() throws StepExecutionException { >+ Cell result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getSelectedCell", new Callable<Cell>() { //$NON-NLS-1$ >+ >+ @Override >+ public Cell call() throws Exception { >+ ObservableList list = getRealComponent() >+ .getSelectionModel().getSelectedCells(); >+ TableView table = getRealComponent(); >+ if (list.size() > 0) { >+ TablePosition pos = null; >+ for (Object object : list) { >+ TablePosition curr = (TablePosition) object; >+ if (curr.getRow() == table.getSelectionModel() >+ .getSelectedIndex()) { >+ pos = curr; >+ break; >+ } >+ } >+ if (pos != null) { >+ return new Cell(pos.getRow(), pos.getColumn()); >+ } >+ } >+ throw new StepExecutionException("No selection found", //$NON-NLS-1$ >+ EventFactory >+ .createActionError(TestErrorEvent. >+ NO_SELECTION)); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public boolean isHeaderVisible() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isHeaderVisible", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ Pane header = (Pane) getRealComponent().lookup( >+ "TableHeaderRow"); >+ if (header != null) { >+ return header.isVisible(); >+ } >+ return false; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public boolean isCellEditable(final int row, final int column) { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isCellEditable", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ TableView<?> table = getRealComponent(); >+ if (table.isEditable()) { >+ TableColumn<?, ?> col = table >+ .getVisibleLeafColumn(column); >+ if (col.isEditable()) { >+ table.scrollTo(row); >+ table.scrollToColumnIndex(column); >+ table.layout(); >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell<?, ?> cell = (TableCell<?, ?>) o; >+ if (cell.getIndex() == row >+ && cell.getTableColumn() == col >+ && cell.getTableView() == table) { >+ return cell.isEditable(); >+ } >+ } >+ } >+ } >+ return false; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public boolean hasCellSelection() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "hasCellSelection", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ TableView<?> table = getRealComponent(); >+ >+ return table.getSelectionModel().getSelectedCells() >+ .size() > 0; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public Rectangle scrollCellToVisible(final int row, final int column) >+ throws StepExecutionException { >+ Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "scrollCellToVisible", new Callable<Rectangle>() { >+ >+ @Override >+ public Rectangle call() throws Exception { >+ TableView<?> table = getRealComponent(); >+ TableColumn col = table.getVisibleLeafColumn(column); >+ >+ table.scrollTo(row); >+ table.scrollToColumn(col); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ table.layout(); >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TableCell.class); >+ for (Object o : tCells) { >+ TableCell<?, ?> cell = (TableCell<?, ?>) o; >+ if (cell.getIndex() == row >+ && cell.getTableColumn() == col >+ && cell.getTableView() == table) { >+ >+ Bounds b = cell.getBoundsInParent(); >+ Point2D pos = cell.localToScreen(0, 0); >+ Point2D parentPos = table.localToScreen(0, 0); >+ return new Rectangle( >+ Rounding.round(pos.getX() >+ - parentPos.getX()), >+ Rounding.round(pos.getY() >+ - parentPos.getY()), >+ Rounding.round(b.getWidth()), >+ Rounding.round(b.getHeight())); >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public Object getTableHeader() { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getTableHeader", new Callable<Object>() { //$NON-NLS-1$ >+ >+ @Override >+ public Object call() throws Exception { >+ return getRealComponent().lookup("TableHeaderRow"); >+ } >+ }); >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TextComponentAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TextComponentAdapter.java >new file mode 100644 >index 0000000..ba41203 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TextComponentAdapter.java >@@ -0,0 +1,119 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.util.concurrent.Callable; >+ >+import javafx.scene.control.TextInputControl; >+ >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITextInputComponent; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+ >+/** >+ * Text input adapter >+ * >+ * @author BREDEX GmbH >+ * @created 30.10.2013 >+ */ >+public class TextComponentAdapter extends >+ JavaFXComponentAdapter<TextInputControl> >+ implements ITextInputComponent { >+ >+ /** >+ * Creates an object with the adapted TextInputControl. >+ * >+ * @param objectToAdapt >+ * this must be an object of the Type >+ * <code>TextInputControl</code> >+ */ >+ public TextComponentAdapter(TextInputControl objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ @Override >+ public String getText() { >+ String text = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<String>() { //$NON-NLS-1$ >+ >+ @Override >+ public String call() throws Exception { >+ return getRealComponent().getText(); >+ } >+ }); >+ return text; >+ } >+ >+ @Override >+ public void setSelection(final int start) { >+ EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<Void>() { //$NON-NLS-1$ >+ >+ @Override >+ public Void call() throws Exception { >+ getRealComponent().positionCaret(start); >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public void setSelection(final int start, final int end) { >+ EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<Void>() { //$NON-NLS-1$ >+ >+ @Override >+ public Void call() throws Exception { >+ getRealComponent().selectRange(start, end); >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public String getSelectionText() { >+ String text = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<String>() { //$NON-NLS-1$ >+ >+ @Override >+ public String call() throws Exception { >+ return getRealComponent().getSelectedText(); >+ } >+ }); >+ return text; >+ } >+ >+ @Override >+ public void selectAll() { >+ EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getText", new Callable<Void>() { //$NON-NLS-1$ >+ >+ @Override >+ public Void call() throws Exception { >+ getRealComponent().selectAll(); >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public boolean isEditable() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isEditable", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return getRealComponent().isEditable(); >+ } >+ }); >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeOperationContext.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeOperationContext.java >new file mode 100644 >index 0000000..6e0819d >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeOperationContext.java >@@ -0,0 +1,523 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.awt.Rectangle; >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.List; >+import java.util.concurrent.Callable; >+ >+import javafx.geometry.Bounds; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+import javafx.scene.control.TreeCell; >+import javafx.scene.control.TreeItem; >+import javafx.scene.control.TreeView; >+ >+import org.apache.commons.lang.ObjectUtils; >+import org.apache.commons.lang.Validate; >+import org.eclipse.jubula.rc.common.driver.ClickOptions; >+import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; >+import org.eclipse.jubula.rc.common.driver.IRobot; >+import org.eclipse.jubula.rc.common.exception.StepExecutionException; >+import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+import org.eclipse.jubula.rc.common.util.SelectionUtil; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+import org.eclipse.jubula.rc.javafx.listener.ComponentHandler; >+import org.eclipse.jubula.rc.javafx.util.Rounding; >+ >+/** >+ * This context holds the tree and supports access to the Robot. It also >+ * implements some general operations on trees. >+ * >+ * @author BREDEX GmbH >+ * @created 19.11.2013 >+ */ >+public class TreeOperationContext extends AbstractTreeOperationContext { >+ >+ /** The AUT Server logger. */ >+ private static AutServerLogger log = new AutServerLogger( >+ TreeOperationContext.class); >+ >+ /** >+ * Creates a new instance. The JTree must have a tree model. >+ * >+ * @param queuer >+ * The queuer >+ * @param robot >+ * The Robot >+ * @param tree >+ * The tree >+ */ >+ public TreeOperationContext(IEventThreadQueuer queuer, IRobot robot, >+ TreeView<?> tree) { >+ super(queuer, robot, tree); >+ Validate.notNull(tree.getRoot()); >+ } >+ >+ /** >+ * {@inheritDoc} >+ * >+ * @param row >+ * Not used! >+ */ >+ @Override >+ protected String convertValueToText(final Object node, final int row) >+ throws StepExecutionException { >+ String result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "convertValueToText", new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ if (item != null) { >+ Object val = item.getValue(); >+ if (val != null) { >+ return val.toString(); >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public Collection<String> getNodeTextList(Object node) { >+ List<String> res = new ArrayList<String>(); >+ int rowNotUsed = 0; >+ String valText = convertValueToText(node, rowNotUsed); >+ if (valText != null) { >+ res.add(valText); >+ } >+ String rendText = getRenderedText(node); >+ if (rendText != null) { >+ res.add(rendText); >+ } >+ return res; >+ } >+ >+ @Override >+ public String getRenderedText(final Object node) >+ throws StepExecutionException { >+ String result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getRenderedText", new Callable<String>() { >+ >+ @Override >+ public String call() throws Exception { >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TreeCell.class); >+ for (Object o : tCells) { >+ TreeCell<?> cell = (TreeCell<?>) o; >+ TreeItem<?> item = cell.getTreeItem(); >+ if (item != null && item.equals(node)) { >+ return cell.getText(); >+ } >+ } >+ return null; >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public boolean isVisible(final Object node) { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait("isVisible", >+ new Callable<Boolean>() { >+ >+ @Override >+ public Boolean call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ return item.isExpanded() >+ && ((TreeView<?>) getTree()).isVisible(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public Rectangle getVisibleRowBounds(final Rectangle rowBounds) { >+ Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getVisibleRowBounds", new Callable<Rectangle>() { >+ >+ @Override >+ public Rectangle call() throws Exception { >+ TreeView<?> tree = ((TreeView<?>) getTree()); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ tree.layout(); >+ Rectangle visibleTreeBounds = new Rectangle(0, 0, >+ Rounding.round(tree.getWidth()), Rounding >+ .round(tree.getHeight())); >+ return rowBounds.intersection(visibleTreeBounds); >+ } >+ }); >+ return result; >+ >+ } >+ >+ @Override >+ public boolean isExpanded(final Object node) { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isExpanded", new Callable<Boolean>() { >+ >+ @Override >+ public Boolean call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ return item.isExpanded(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public void scrollNodeToVisible(final Object node) { >+ EventThreadQueuerJavaFXImpl.invokeAndWait("scrollNodeToVisible", >+ new Callable<Void>() { >+ >+ @Override >+ public Void call() throws Exception { >+ int index = ((TreeView<?>) getTree()) >+ .getRow((TreeItem) node); >+ ((TreeView<?>) getTree()).scrollTo(index); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ ((TreeView<?>) getTree()).layout(); >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public void clickNode(Object node, ClickOptions clickOps) { >+ scrollNodeToVisible(node); >+ Rectangle rowBounds = getNodeBounds(node); >+ Rectangle visibleRowBounds = getVisibleRowBounds(rowBounds); >+ getRobot().click(getTree(), visibleRowBounds, clickOps); >+ } >+ >+ @Override >+ public void expandNode(final Object node) { >+ scrollNodeToVisible(node); >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("expandNode", >+ new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TreeCell.class); >+ for (Object o : tCells) { >+ TreeCell<?> cell = (TreeCell<?>) o; >+ TreeItem<?> item = cell.getTreeItem(); >+ if (item != null && item.equals(node) >+ && !item.isExpanded()) { >+ TreeView<?> tree = ((TreeView<?>) getTree()); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ tree.layout(); >+ >+ Node n = cell.getDisclosureNode(); >+ Bounds b = n.getBoundsInParent(); >+ >+ Rectangle cBounds = new Rectangle( >+ Rounding.round(b.getMinX()), >+ Rounding.round(b.getMinY()), >+ Rounding.round(b.getWidth() >+ - cell.getGraphicTextGap()), >+ Rounding.round(cell.getHeight())); >+ return n; >+ } >+ } >+ return null; >+ } >+ }); >+ if (result != null) { >+ getRobot().click(result, null, >+ ClickOptions.create().setClickCount(1).setMouseButton(1)); >+ } >+ EventThreadQueuerJavaFXImpl.invokeAndWait("expandNodeCheckIfExpanded", >+ new Callable<Void>() { >+ >+ @Override >+ public Void call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ if (!((TreeView<?>) getTree()).isDisabled() >+ && !item.isExpanded()) { >+ log.warn("Expand node fallback used for: " >+ + item.getValue()); >+ >+ item.setExpanded(true); >+ } >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public void collapseNode(final Object node) { >+ scrollNodeToVisible(node); >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "collapseNode", new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TreeCell.class); >+ for (Object o : tCells) { >+ TreeCell<?> cell = (TreeCell<?>) o; >+ TreeItem<?> item = cell.getTreeItem(); >+ if (item != null && item.equals(node) >+ && item.isExpanded()) { >+ TreeView<?> tree = ((TreeView<?>) getTree()); >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ tree.layout(); >+ >+ Node n = cell.getDisclosureNode(); >+ Bounds b = n.getBoundsInParent(); >+ >+ Rectangle cBounds = new Rectangle( >+ Rounding.round(b.getMinX()), >+ Rounding.round(b.getMinY()), >+ Rounding.round(b.getWidth() >+ - cell.getGraphicTextGap()), >+ Rounding.round(cell.getHeight())); >+ return n; >+ } >+ } >+ return null; >+ } >+ }); >+ if (result != null) { >+ getRobot().click(result, null, >+ ClickOptions.create().setClickCount(1).setMouseButton(1)); >+ } >+ EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "collapseNodeCheckIfCollapsed", new Callable<Void>() { >+ >+ @Override >+ public Void call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ if (!((TreeView<?>) getTree()).isDisabled() >+ && item.isExpanded()) { >+ log.warn("Collapse node fallback used for: " >+ + item.getValue()); >+ >+ item.setExpanded(false); >+ } >+ return null; >+ } >+ }); >+ } >+ >+ @Override >+ public Object getSelectedNode() { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getSelectedNode", new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ >+ return ((TreeView<?>) getTree()).getSelectionModel() >+ .getSelectedItem(); >+ } >+ }); >+ if (result != null) { >+ SelectionUtil.validateSelection(new Object[] { result }); >+ } else { >+ SelectionUtil.validateSelection(new Object[] {}); >+ } >+ return result; >+ } >+ >+ @Override >+ public Object[] getSelectedNodes() { >+ Object[] result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getSelectedNode", new Callable<Object[]>() { >+ >+ @Override >+ public Object[] call() throws Exception { >+ >+ return ((TreeView<?>) getTree()).getSelectionModel() >+ .getSelectedItems().toArray(); >+ } >+ }); >+ SelectionUtil.validateSelection(result); >+ return result; >+ } >+ >+ @Override >+ public Object[] getRootNodes() { >+ Object[] result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getRootNodes", new Callable<Object[]>() { >+ >+ @Override >+ public Object[] call() throws Exception { >+ TreeView<?> tree = (TreeView<?>) getTree(); >+ >+ // If the root is visible, just return that. >+ if (tree.showRootProperty().getValue()) { >+ return new Object[] { tree.getRoot() }; >+ } >+ >+ // If the root is not visible, return all direct >+ // children of the >+ // non-visible root. >+ return getChildren(tree.getRoot()); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public Object getParent(final Object child) { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("getParent", >+ new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ >+ return ((TreeItem<?>) child).getParent(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public Object getChild(final Object parent, final int index) { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("getChild", >+ new Callable<Object>() { >+ >+ @Override >+ public Object call() throws Exception { >+ >+ return ((TreeItem<?>) parent).getChildren().get(index); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public int getNumberOfChildren(final Object parent) { >+ Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getNumberOfChildren", new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws Exception { >+ >+ return ((TreeItem<?>) parent).getChildren().size(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public boolean isLeaf(final Object node) { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait("isLeaf", >+ new Callable<Boolean>() { >+ >+ @Override >+ public Boolean call() throws Exception { >+ TreeItem<?> item = (TreeItem<?>) node; >+ return item.isLeaf(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public Object[] getChildren(final Object parent) { >+ Object[] result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getSelectedNode", new Callable<Object[]>() { >+ >+ @Override >+ public Object[] call() throws Exception { >+ >+ return ((TreeItem<?>) parent).getChildren().toArray(); >+ } >+ }); >+ >+ return result; >+ } >+ >+ @Override >+ public Rectangle getNodeBounds(final Object node) { >+ Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getNodeBounds", new Callable<Rectangle>() { >+ @Override >+ public Rectangle call() throws Exception { >+ List<Object> tCells = ComponentHandler >+ .getInstancesOfType(TreeCell.class); >+ for (Object o : tCells) { >+ TreeCell cell = (TreeCell<?>) o; >+ TreeItem<?> item = cell.getTreeItem(); >+ TreeView<?> tree = (TreeView<?>) getTree(); >+ if ((item != null && item.equals(node))) { >+ // Update the layout coordinates otherwise >+ // we would get old position values >+ tree.layout(); >+ >+ Point2D posTree = tree.localToScreen(0, 0); >+ Point2D posCell = cell.localToScreen(0, 0); >+ Bounds b = cell.getBoundsInParent(); >+ Rectangle cBounds = new Rectangle( >+ Math.abs(Rounding.round((posCell.getX() >+ - posTree.getX()))), >+ Math.abs(Rounding.round((posCell.getY() >+ - posTree.getY()))), >+ Rounding.round(b.getWidth()), >+ Rounding.round(b.getHeight())); >+ return cBounds; >+ } >+ } >+ return null; >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public int getIndexOfChild(final Object parent, final Object child) { >+ Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getIndexOfChild", new Callable<Integer>() { >+ >+ @Override >+ public Integer call() throws Exception { >+ if (parent == null) { >+ Object[] rootNodes = getRootNodes(); >+ for (int i = 0; i < rootNodes.length; i++) { >+ if (ObjectUtils.equals(rootNodes[i], child)) { >+ return i; >+ } >+ } >+ >+ return -1; >+ } >+ List<?> children = ((TreeItem<?>) parent).getChildren(); >+ if (children.contains(child)) { >+ return children.indexOf(child); >+ } >+ return -1; >+ } >+ }); >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeViewAdapter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeViewAdapter.java >new file mode 100644 >index 0000000..931a2b6 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/tester/adapter/TreeViewAdapter.java >@@ -0,0 +1,73 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.tester.adapter; >+ >+import java.util.concurrent.Callable; >+ >+import javafx.scene.control.TreeView; >+ >+import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; >+import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITreeComponent; >+import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl; >+ >+/** >+ * Implementation of the Tree interface as an adapter for <code>TreeView</code>. >+ * >+ * @author BREDEX GmbH >+ * @created 19.11.2013 >+ */ >+public class TreeViewAdapter extends JavaFXComponentAdapter<TreeView<?>> >+ implements ITreeComponent { >+ >+ /** >+ * Constructor >+ * >+ * @param objectToAdapt >+ * the object to adapt >+ */ >+ public TreeViewAdapter(TreeView<?> objectToAdapt) { >+ super(objectToAdapt); >+ } >+ >+ @Override >+ public Object getRootNode() { >+ Object result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "getRootNode", new Callable<Object>() { //$NON-NLS-1$ >+ >+ @Override >+ public Object call() throws Exception { >+ return getRealComponent().getRoot().getValue(); >+ } >+ }); >+ return result; >+ } >+ >+ @Override >+ public AbstractTreeOperationContext getContext() { >+ return new TreeOperationContext(getRobotFactory() >+ .getEventThreadQueuer(), getRobot(), getRealComponent()); >+ } >+ >+ @Override >+ public boolean isRootVisible() { >+ boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait( >+ "isRootVisible", new Callable<Boolean>() { //$NON-NLS-1$ >+ >+ @Override >+ public Boolean call() throws Exception { >+ return getRealComponent().showRootProperty().getValue(); >+ } >+ }); >+ >+ return result; >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/HighlightNode.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/HighlightNode.java >new file mode 100644 >index 0000000..fc6bea8 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/HighlightNode.java >@@ -0,0 +1,74 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.util; >+ >+import java.util.HashMap; >+import java.util.Map; >+import java.util.Set; >+ >+import javafx.scene.Node; >+import javafx.scene.effect.Effect; >+import javafx.scene.effect.InnerShadow; >+import javafx.scene.paint.Color; >+ >+/** >+ * Util class to highlight nodes >+ * >+ * @author BREDEX GmbH >+ * @created 10.10.2013 >+ */ >+public class HighlightNode { >+ >+ /** The old effect of the Node **/ >+ private static Map<Node, Effect> oldEffects = new HashMap<>(); >+ >+ /** >+ * private Constructor >+ */ >+ private HighlightNode() { >+ // private Constructor >+ } >+ >+ /** >+ * Use this method only from the FX-Thread! Draws a border around the given >+ * Node >+ * >+ * @param n >+ * the Node >+ */ >+ public static void drawHighlight(Node n) { >+ if (n.getEffect() != null) { >+ oldEffects.put(n, n.getEffect()); >+ } >+ n.setEffect(new InnerShadow(10, Color.GREEN)); >+ } >+ >+ /** >+ * Use this method only from the FX-Thread! Removes the Border >+ * >+ * @param n >+ * the Node >+ */ >+ public static void removeHighlight(Node n) { >+ n.setEffect(oldEffects.remove(n)); >+ } >+ >+ /** >+ * Resets all effects. >+ */ >+ public static void clean() { >+ Set<Node> nodes = oldEffects.keySet(); >+ for (Node node : nodes) { >+ node.setEffect(oldEffects.remove(node)); >+ } >+ >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/JavaFXEventConverter.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/JavaFXEventConverter.java >new file mode 100644 >index 0000000..19f144d >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/JavaFXEventConverter.java >@@ -0,0 +1,73 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.util; >+ >+import javafx.event.ActionEvent; >+import javafx.event.Event; >+import javafx.event.EventType; >+import javafx.scene.input.KeyEvent; >+import javafx.scene.input.MouseEvent; >+import javafx.scene.input.ScrollEvent; >+ >+import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; >+import org.eclipse.jubula.rc.common.logger.AutServerLogger; >+ >+/** >+ * Utility class for converting an AWT event type to an JavaFX event type >+ * >+ */ >+public class JavaFXEventConverter { >+ /** the logger */ >+ private static AutServerLogger log = new AutServerLogger( >+ JavaFXEventConverter.class); >+ >+ /** >+ * private Constructor >+ */ >+ private JavaFXEventConverter() { >+ // private Constructor >+ } >+ >+ /** >+ * Converts a given AWT Event-Mask to a JavaFX event >+ * >+ * @param eventMask >+ * the AWT Event-Mask >+ * @return a JavaFX event Type or null if the AWT Event-Mask is not handled. >+ * This shouldn't happen and will be logged. >+ */ >+ public static EventType<? extends Event> awtToFX(long eventMask) { >+ >+ EventType<? extends Event> fxEvent = null; >+ if (java.awt.AWTEvent.ACTION_EVENT_MASK == eventMask) { >+ fxEvent = ActionEvent.ACTION; >+ } else if (java.awt.AWTEvent.MOUSE_EVENT_MASK == eventMask) { >+ fxEvent = MouseEvent.ANY; >+ } else if (java.awt.AWTEvent.MOUSE_MOTION_EVENT_MASK == eventMask) { >+ if (DragAndDropHelper.getInstance().isDragMode()) { >+ fxEvent = MouseEvent.MOUSE_DRAGGED; >+ } else { >+ fxEvent = MouseEvent.MOUSE_MOVED; >+ } >+ } else if (java.awt.AWTEvent.MOUSE_WHEEL_EVENT_MASK == eventMask) { >+ fxEvent = ScrollEvent.SCROLL; >+ } else if (java.awt.AWTEvent.KEY_EVENT_MASK == eventMask) { >+ fxEvent = KeyEvent.ANY; >+ } >+ if (fxEvent == null) { >+ if (log.isInfoEnabled()) { >+ log.info("Could not find a JavaFX event for: " //$NON-NLS-1$ >+ + eventMask); >+ } >+ } >+ return fxEvent; >+ } >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/NodeBounds.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/NodeBounds.java >new file mode 100644 >index 0000000..6375649 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/NodeBounds.java >@@ -0,0 +1,49 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.util; >+ >+import javafx.geometry.BoundingBox; >+import javafx.geometry.Point2D; >+import javafx.scene.Node; >+ >+/** >+ * Helperclass for checking node bounds >+ */ >+public class NodeBounds { >+ >+ /** >+ * Private Constructor >+ */ >+ private NodeBounds() { >+ // Empty >+ } >+ >+ /** >+ * Checks if the given point with coordinates relative to the scene is in >+ * the given Node. >+ * >+ * @param point >+ * the Point >+ * @param n >+ * the Node >+ * @return true if the Point is in the Node, false if not. >+ */ >+ public static boolean checkIfContains(Point2D point, Node n) { >+ Point2D nodePos = n.localToScreen(0, 0); >+ >+ BoundingBox box = new BoundingBox(nodePos.getX(), >+ nodePos.getY(), >+ n.getBoundsInParent().getWidth(), >+ n.getBoundsInParent().getHeight()); >+ return box.contains(point); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/Rounding.java b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/Rounding.java >new file mode 100644 >index 0000000..c4275cb >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/src/org/eclipse/jubula/rc/javafx/util/Rounding.java >@@ -0,0 +1,41 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.rc.javafx.util; >+ >+/** >+ * Because JavaFX uses doubles on various places and the RC-Architecture expects >+ * integers, we have to round a lot. This class should be used, to easily change >+ * the rounding at a central place. >+ * >+ * @author BREDEX GmbH >+ * @created 28.1.2014 >+ */ >+public class Rounding { >+ >+ /** >+ * Private Constructor >+ */ >+ private Rounding() { >+ // Private Constructor >+ } >+ >+ /** >+ * Using (int)Math.round(x) >+ * >+ * @param d >+ * the double value >+ * @return the rounded int value >+ */ >+ public static int round(double d) { >+ return (int) Math.round(d); >+ } >+ >+} >diff --git a/org.eclipse.jubula.rc.javafx/toolchains.xml b/org.eclipse.jubula.rc.javafx/toolchains.xml >new file mode 100644 >index 0000000..2b31437 >--- /dev/null >+++ b/org.eclipse.jubula.rc.javafx/toolchains.xml >@@ -0,0 +1,25 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!-- >+ Copyright (c) 2013 BREDEX GmbH. >+ 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 >+ --> >+<toolchains> >+ <toolchain> >+ <type>jdk</type> >+ <provides> >+ <id>JavaSE-1.7</id> >+ </provides> >+ <configuration> >+ <jdkHome>/devapps/java64/jdk1.8.0</jdkHome> >+ <bootClassPath> >+ <includes> >+ <include>/jre/lib/*.jar</include> >+ <include>/jre/lib/ext/*.jar</include> >+ </includes> >+ </bootClassPath> >+ </configuration> >+ </toolchain> >+</toolchains> >\ No newline at end of file >diff --git a/org.eclipse.jubula.releng.client/pom.xml b/org.eclipse.jubula.releng.client/pom.xml >index 06d3990..635ef1d 100644 >--- a/org.eclipse.jubula.releng.client/pom.xml >+++ b/org.eclipse.jubula.releng.client/pom.xml >@@ -33,6 +33,7 @@ > <module>../org.eclipse.jubula.toolkit.provider.rcp</module> > <module>../org.eclipse.jubula.toolkit.provider.rcp.gef</module> > <module>../org.eclipse.jubula.toolkit.provider.swing</module> >+ <module>../org.eclipse.jubula.toolkit.provider.javafx</module> > <module>../org.eclipse.jubula.toolkit.provider.swt</module> > <module>../org.eclipse.jubula.toolkit.provider.win</module> > <module>../org.eclipse.jubula.toolkit.provider.win.apps</module> >diff --git a/org.eclipse.jubula.releng.server/pom.xml b/org.eclipse.jubula.releng.server/pom.xml >index 8ab4fb3..577b2d5 100644 >--- a/org.eclipse.jubula.releng.server/pom.xml >+++ b/org.eclipse.jubula.releng.server/pom.xml >@@ -20,6 +20,7 @@ > <module>../org.eclipse.jubula.rc.common</module> > <module>../org.eclipse.jubula.rc.common.agent</module> > <module>../org.eclipse.jubula.rc.swing</module> >+ <module>../org.eclipse.jubula.rc.javafx</module> > <module>../org.eclipse.jubula.rc.swt</module> > <module>../org.eclipse.jubula.releng.server.rc.rcp</module> > <module>../org.eclipse.jubula.rc.rcp</module> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/.checkstyle b/org.eclipse.jubula.toolkit.provider.javafx/.checkstyle >new file mode 100644 >index 0000000..f69a865 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/.checkstyle >@@ -0,0 +1,7 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+ >+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false"> >+ <fileset name="all" enabled="true" check-config-name="Jubula" local="false"> >+ <file-match-pattern match-pattern="." include-pattern="true"/> >+ </fileset> >+</fileset-config> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/.classpath b/org.eclipse.jubula.toolkit.provider.javafx/.classpath >new file mode 100644 >index 0000000..b277a8a >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/.classpath >@@ -0,0 +1,7 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<classpath> >+ <classpathentry kind="src" path="src"/> >+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> >+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> >+ <classpathentry kind="output" path="bin"/> >+</classpath> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/.gitignore b/org.eclipse.jubula.toolkit.provider.javafx/.gitignore >new file mode 100644 >index 0000000..934e0e0 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/.gitignore >@@ -0,0 +1,2 @@ >+/bin >+/target >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/.project b/org.eclipse.jubula.toolkit.provider.javafx/.project >new file mode 100644 >index 0000000..3dbbca5 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/.project >@@ -0,0 +1,41 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<projectDescription> >+ <name>org.eclipse.jubula.toolkit.provider.javafx</name> >+ <comment></comment> >+ <projects> >+ </projects> >+ <buildSpec> >+ <buildCommand> >+ <name>org.eclipse.jdt.core.javabuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>org.eclipse.pde.ManifestBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>org.eclipse.pde.SchemaBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ <buildCommand> >+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name> >+ <arguments> >+ </arguments> >+ </buildCommand> >+ </buildSpec> >+ <natures> >+ <nature>org.eclipse.pde.PluginNature</nature> >+ <nature>org.eclipse.jdt.core.javanature</nature> >+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature> >+ </natures> >+ <linkedResources> >+ <link> >+ <name>.settings</name> >+ <type>2</type> >+ <locationURI>PARENT-1-PROJECT_LOC/org.eclipse.jubula.project.configuration/settings/1.7</locationURI> >+ </link> >+ </linkedResources> >+</projectDescription> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jubula.toolkit.provider.javafx/.settings/org.eclipse.jdt.core.prefs >new file mode 100644 >index 0000000..416f4fb >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/.settings/org.eclipse.jdt.core.prefs >@@ -0,0 +1,11 @@ >+eclipse.preferences.version=1 >+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled >+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 >+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve >+org.eclipse.jdt.core.compiler.compliance=1.5 >+org.eclipse.jdt.core.compiler.debug.lineNumber=generate >+org.eclipse.jdt.core.compiler.debug.localVariable=generate >+org.eclipse.jdt.core.compiler.debug.sourceFile=generate >+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error >+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error >+org.eclipse.jdt.core.compiler.source=1.5 >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/META-INF/MANIFEST.MF b/org.eclipse.jubula.toolkit.provider.javafx/META-INF/MANIFEST.MF >new file mode 100644 >index 0000000..25c8cfe >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/META-INF/MANIFEST.MF >@@ -0,0 +1,14 @@ >+Manifest-Version: 1.0 >+Bundle-ManifestVersion: 2 >+Bundle-Name: Jubula Toolkit - JavaFX >+Bundle-SymbolicName: org.eclipse.jubula.toolkit.provider.javafx;singleton:=true >+Bundle-Version: 2.3.0.qualifier >+Bundle-Vendor: Eclipse Jubula >+Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.6.0,4.0.0)", >+ org.eclipse.jubula.toolkit.common;bundle-version="[2.3.0,2.4.0)", >+ org.eclipse.jubula.client.ui.rcp;bundle-version="[2.3.0,2.4.0)";resolution:=optional, >+ org.eclipse.jubula.ui.compatibility;bundle-version="[2.3.0,2.4.0)" >+Bundle-RequiredExecutionEnvironment: JavaSE-1.7 >+Bundle-ActivationPolicy: lazy >+Bundle-ClassPath: . >+Bundle-Activator: org.eclipse.jubula.toolkit.provider.javafx.Activator >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/about.html b/org.eclipse.jubula.toolkit.provider.javafx/about.html >new file mode 100644 >index 0000000..23f53f0 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/about.html >@@ -0,0 +1,28 @@ >+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" >+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> >+<html xmlns="http://www.w3.org/1999/xhtml"> >+<head> >+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> >+<title>About</title> >+</head> >+<body lang="EN-US"> >+<h2>About This Content</h2> >+ >+<p>September 23, 2013</p> >+<h3>License</h3> >+ >+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise >+indicated below, the Content is provided to you under the terms and conditions of the >+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available >+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. >+For purposes of the EPL, "Program" will mean the Content.</p> >+ >+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is >+being redistributed by another party ("Redistributor") and different terms and conditions may >+apply to your use of any object code in the Content. Check the Redistributor's license that was >+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise >+indicated below, the terms and conditions of the EPL still apply to any source code in the Content >+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> >+ >+</body> >+</html> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/build.properties b/org.eclipse.jubula.toolkit.provider.javafx/build.properties >new file mode 100644 >index 0000000..ef7d3b1 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/build.properties >@@ -0,0 +1,18 @@ >+############################################################################### >+# Copyright (c) 2013 BREDEX GmbH. >+# 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 >+############################################################################### >+source.. = src/ >+output.. = bin/ >+jars.compile.order = . >+bin.includes = about.html,\ >+ META-INF/,\ >+ resources/,\ >+ plugin.xml,\ >+ . >+javacSource = 1.5 >+javacTarget = 1.5 >+javacErrors.. = -assertIdentifier >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/plugin.xml b/org.eclipse.jubula.toolkit.provider.javafx/plugin.xml >new file mode 100644 >index 0000000..a1de81f >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/plugin.xml >@@ -0,0 +1,23 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<?eclipse version="3.2"?> <!-- >+ Copyright (c) 2013 BREDEX GmbH. >+ 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 >+ --> >+ >+<plugin> >+ <extension >+ point="org.eclipse.jubula.toolkit.common.toolkitsupport"> >+ <toolkit >+ IToolkitProvider="org.eclipse.jubula.toolkit.provider.javafx.ToolkitProvider" >+ includes="com.bredexsw.guidancer.ConcreteToolkitPlugin" >+ isUserToolkit="false" >+ level="toolkit" >+ name="JavaFX" >+ order="3" >+ toolkitID="org.eclipse.jubula.JavaFXToolkitPlugin"/> >+ </extension> >+ >+</plugin> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/pom.xml b/org.eclipse.jubula.toolkit.provider.javafx/pom.xml >new file mode 100644 >index 0000000..5d9ee77 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/pom.xml >@@ -0,0 +1,52 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" >+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> >+ <modelVersion>4.0.0</modelVersion> >+ <parent> >+ <artifactId>org.eclipse.jubula.releng.client</artifactId> >+ <groupId>org.eclipse.jubula</groupId> >+ <version>2.3.0-SNAPSHOT</version> >+ <relativePath>../org.eclipse.jubula.releng.client</relativePath> >+ </parent> >+ <artifactId>org.eclipse.jubula.toolkit.provider.javafx</artifactId> >+ <packaging>eclipse-plugin</packaging> >+ >+ <build> >+ <plugins> >+ <plugin> >+ <groupId>org.eclipse.tycho</groupId> >+ <artifactId>tycho-maven-plugin</artifactId> >+ <version>${tycho-version}</version> >+ <extensions>true</extensions> >+ </plugin> >+ <plugin> >+ <groupId>org.eclipse.tycho</groupId> >+ <artifactId>target-platform-configuration</artifactId> >+ <version>${tycho-version}</version> >+ <configuration> >+ <dependency-resolution> >+ <optionalDependencies>ignore</optionalDependencies> >+ <extraRequirements> >+ <!-- prefer RCP to RAP for compilation --> >+ <requirement> >+ <type>eclipse-plugin</type> >+ <id>org.eclipse.swt</id> >+ <versionRange>[3.6,4.0)</versionRange> >+ </requirement> >+ <requirement> >+ <type>eclipse-plugin</type> >+ <id>org.eclipse.jface</id> >+ <versionRange>[3.6,4.0)</versionRange> >+ </requirement> >+ <requirement> >+ <type>eclipse-plugin</type> >+ <id>org.eclipse.jubula.client.ui.rcp</id> >+ <versionRange>[2.3.0,2.4.0)</versionRange> >+ </requirement> >+ </extraRequirements> >+ </dependency-resolution> >+ </configuration> >+ </plugin> >+ </plugins> >+ </build> >+</project> >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/resources/xml/ComponentConfiguration.xml b/org.eclipse.jubula.toolkit.provider.javafx/resources/xml/ComponentConfiguration.xml >new file mode 100644 >index 0000000..3d13449 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/resources/xml/ComponentConfiguration.xml >@@ -0,0 +1,17 @@ >+<?xml version="1.0" encoding="ISO-8859-1"?> <!-- >+ Copyright (c) 2013 BREDEX GmbH. >+ 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 >+ --> >+ >+<!-- CAUTION: don't format any entries, especially don't use line breaks! >+ The value of the formated item may contain formating characters like tabs or >+ newlines, making them unusable for class or data lookup!--> >+<compSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../org.eclipse.jubula.toolkit.common/resources/xml/ToolkitComponentConfiguration.xsd"> <configVersion> >+ <majorVersion>4</majorVersion> >+ <minorVersion>0</minorVersion> >+ </configVersion> <toolkitComponent type="javafx.stage.Stage" visible="false" hasDefaultMapping="true"> <realizes>guidancer.concrete.GraphicApplication</realizes> <testerClass>org.eclipse.jubula.rc.javafx.tester.JavaFXApplicationTester</testerClass> <componentClass name="javafx.stage.Stage"/> </toolkitComponent> >+ <toolkitComponent type="javafx.scene.control.ButtonBase" visible="false"> <realizes>guidancer.concrete.Button</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.ButtonBase" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Button" visible="false"> <realizes>javafx.scene.control.ButtonBase</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.Button" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.CheckBox" visible="false"> <realizes>javafx.scene.control.ButtonBase</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.CheckBox" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Hyperlink" visible="false"> <realizes>javafx.scene.control.ButtonBase</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.Hyperlink" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ToggleButton" visible="false"> <realizes>javafx.scene.control.ButtonBase</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.ToggleButton" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.RadioButton" visible="false"> <realizes>javafx.scene.control.ButtonBase</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ButtonTester</testerClass> <componentClass name="javafx.scene.control.RadioButton" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Label" visible="false"> <realizes>guidancer.concrete.Label</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.LabelTester</testerClass> <componentClass name="javafx.scene.control.Label" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TitledPane" visible="false"> <realizes>guidancer.concrete.Label</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.LabelTester</testerClass> <componentClass name="javafx.scene.control.TitledPane" /> </toolkitComponent> <toolkitComponent type="javafx.scene.text.Text" visible="false"> <realizes>guidancer.concrete.Label</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.LabelTester</testerClass> <componentClass name="javafx.scene.text.Text" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TextInputControl" visible="false"> <realizes>guidancer.concrete.TextComponent</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.AbstractTextComponentTester</testerClass> <componentClass name="javafx.scene.control.TextInputControl" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TextField" visible="false"> <realizes>javafx.scene.control.TextInputControl</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.AbstractTextComponentTester</testerClass> <componentClass name="javafx.scene.control.TextField" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.PasswordField" visible="false"> <realizes>javafx.scene.control.TextField</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.AbstractTextComponentTester</testerClass> <componentClass name="javafx.scene.control.PasswordField" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TextArea" visible="false"> <realizes>javafx.scene.control.TextInputControl</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.AbstractTextComponentTester</testerClass> <componentClass name="javafx.scene.control.TextArea" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TableView" visible="false"> <realizes>guidancer.concrete.Table</realizes> <testerClass>org.eclipse.jubula.rc.javafx.tester.TableTester</testerClass> <componentClass name="javafx.scene.control.TableView" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TreeView" visible="false"> <realizes>guidancer.concrete.Tree</realizes> <testerClass>org.eclipse.jubula.rc.javafx.tester.TreeViewTester</testerClass> <componentClass name="javafx.scene.control.TreeView" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TreeTableView" visible="false"> <realizes>guidancer.concrete.Tree</realizes> <testerClass>org.eclipse.jubula.rc.javafx.tester.TreeViewTester</testerClass> <componentClass name="javafx.scene.control.TreeTableView" /> </toolkitComponent> <toolkitComponent type="javafx.scene.web.WebView" visible="false"> <realizes>guidancer.abstract.Widget</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.WidgetTester</testerClass> <componentClass name="javafx.scene.web.WebView" /> </toolkitComponent> <toolkitComponent type="javafx.scene.chart.Chart" visible="false"> <realizes>guidancer.concrete.Label</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.LabelTester</testerClass> <componentClass name="javafx.scene.chart.Chart" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Accordion" visible="false"> <realizes>guidancer.concrete.TabbedPane</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.TabbedPaneTester</testerClass> <componentClass name="javafx.scene.control.Accordion" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ChoiceBox" visible="false"> <realizes>guidancer.concrete.ComboBox</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ComboBoxTester</testerClass> <componentClass name="javafx.scene.control.ChoiceBox" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ComboBox" visible="false"> <realizes>guidancer.concrete.ComboBox</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ComboBoxTester</testerClass> <componentClass name="javafx.scene.control.ComboBox" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.DatePicker" visible="false"> <realizes>guidancer.concrete.ComboBox</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ComboBoxTester</testerClass> <componentClass name="javafx.scene.control.DatePicker" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Slider" visible="false"> <realizes>guidancer.abstract.Widget</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.WidgetTester</testerClass> <componentClass name="javafx.scene.control.Slider" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.TabPane" visible="false"> <realizes>guidancer.concrete.TabbedPane</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.TabbedPaneTester</testerClass> <componentClass name="javafx.scene.control.TabPane" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.Pagination" visible="false"> <realizes>guidancer.concrete.TabbedPane</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.TabbedPaneTester</testerClass> <componentClass name="javafx.scene.control.Pagination" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ProgressIndicator" visible="false"> <realizes>guidancer.abstract.Widget</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.WidgetTester</testerClass> <componentClass name="javafx.scene.control.ProgressIndicator" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ProgressBar" visible="false"> <realizes>javafx.scene.control.ProgressIndicator</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.WidgetTester</testerClass> <componentClass name="javafx.scene.control.ProgressBar" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.MenuBar" visible="false" hasDefaultMapping="false"> <realizes>guidancer.concrete.MenuBar</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.AbstractMenuTester</testerClass> <componentClass name="javafx.scene.control.MenuBar" /> </toolkitComponent> <toolkitComponent type="javafx.scene.control.ListView" visible="false"> <realizes>guidancer.concrete.List</realizes> <testerClass>org.eclipse.jubula.rc.common.tester.ListTester</testerClass> <componentClass name="javafx.scene.control.ListView" /> </toolkitComponent> >+</compSystem> >\ No newline at end of file >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/Activator.java b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/Activator.java >new file mode 100644 >index 0000000..db4d7c1 >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/Activator.java >@@ -0,0 +1,47 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.toolkit.provider.javafx; >+ >+import org.eclipse.core.runtime.Plugin; >+import org.osgi.framework.BundleContext; >+ >+/** >+ * The activator class controls the plug-in life cycle >+ */ >+public class Activator extends Plugin { >+ /** The shared instance */ >+ private static Activator plugin; >+ >+ /** The constructor */ >+ public Activator() { >+ plugin = this; >+ } >+ >+ /** {@inheritDoc} */ >+ public void start(BundleContext context) throws Exception { >+ super.start(context); >+ } >+ >+ /** {@inheritDoc} */ >+ public void stop(BundleContext context) throws Exception { >+ plugin = null; >+ super.stop(context); >+ } >+ >+ /** >+ * Returns the shared instance >+ * >+ * @return the shared instance >+ */ >+ public static Activator getDefault() { >+ return plugin; >+ } >+} >\ No newline at end of file >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/I18nStrings.properties b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/I18nStrings.properties >new file mode 100644 >index 0000000..1e89cbc >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/I18nStrings.properties >@@ -0,0 +1,37 @@ >+############################################################################### >+# Copyright (c) 2013 BREDEX GmbH. >+# 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 >+############################################################################### >+javafx.scene.control.ButtonBase=(JavaFX) ButtonBase >+javafx.scene.control.Button=(JavaFX) Button >+javafx.scene.control.CheckBox=(JavaFX) Check Box >+javafx.scene.control.Hyperlink=(JavaFX) Hyperlink >+javafx.scene.control.ToggleButton=(JavaFX) Toggle Button >+javafx.scene.control.RadioButton=(JavaFX) Radio Button >+javafx.scene.control.Label=(JavaFX) Label >+javafx.scene.control.TitledPane=(JavaFX) Titled Pane >+javafx.scene.text.Text=(JavaFX) Text >+javafx.scene.control.TextInputControl=(JavaFX) TextInputControl >+javafx.scene.control.TextField=(JavaFX) Text Field >+javafx.scene.control.PasswordField=(JavaFX) Password Field >+javafx.scene.control.TextArea=(JavaFX) Text Area >+javafx.scene.control.TableView=(JavaFX) Table View >+javafx.scene.control.TreeView=(JavaFX) TreeView >+javafx.scene.control.TreeTableView=(JavaFX) Tree Table View >+javafx.scene.web.WebView=(JavaFX) Web View >+javafx.scene.chart.Chart=(JavaFX) Chart >+javafx.scene.control.Accordion=(JavaFX) Accordion >+javafx.scene.control.ChoiceBox=(JavaFX) Choice Box >+javafx.scene.control.ComboBox=(JavaFX) Combo Box >+javafx.scene.control.DatePicker=(JavaFX) Date Picker >+javafx.scene.control.Slider=(JavaFX) Slider >+javafx.scene.control.TabPane=(JavaFX) Tab Pane >+javafx.scene.control.Pagination=(JavaFX) Pagination >+javafx.scene.control.ProgressIndicator=(JavaFX) Progress Indicator >+javafx.scene.control.ProgressBar=(JavaFX) Progress Bar >+javafx.scene.control.MenuBar=(JavaFX) Menu Bar >+javafx.scene.control.ListView=(JavaFX) List View >+javafx.stage.Stage =(JavaFX) Application >\ No newline at end of file >diff --git a/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/ToolkitProvider.java b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/ToolkitProvider.java >new file mode 100644 >index 0000000..3384a7f >--- /dev/null >+++ b/org.eclipse.jubula.toolkit.provider.javafx/src/org/eclipse/jubula/toolkit/provider/javafx/ToolkitProvider.java >@@ -0,0 +1,50 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 BREDEX GmbH. >+ * 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: >+ * BREDEX GmbH - initial API and implementation and/or initial documentation >+ *******************************************************************************/ >+package org.eclipse.jubula.toolkit.provider.javafx; >+ >+import java.net.URL; >+import java.util.Map; >+import java.util.ResourceBundle; >+ >+import org.eclipse.jubula.toolkit.common.IToolKitProvider; >+import org.eclipse.jubula.toolkit.common.exception.ToolkitPluginException; >+import org.eclipse.jubula.toolkit.common.utils.ToolkitUtils; >+import org.eclipse.swt.widgets.Composite; >+ >+/** >+ * @author BREDEX GmbH >+ * @created 23.09.2013 >+ */ >+public class ToolkitProvider implements IToolKitProvider { >+ /** <code>I18N_PROPERTIES</code> */ >+ private static final String I18N_PROPERTIES = >+ "org.eclipse.jubula.toolkit.provider.javafx.I18nStrings"; //$NON-NLS-1$ >+ >+ /** {@inheritDoc} */ >+ public Composite getAutConfigDialog(Composite parent, int style, >+ Map<String, String> autConfig, String autName) >+ throws ToolkitPluginException { >+ return ToolkitUtils.createAutConfigComponent( >+ "org.eclipse.jubula.client.ui.rcp.widgets.autconfig.JavaAutConfigComponent", //$NON-NLS-1$ >+ this.getClass().getClassLoader(), parent, style, >+ autConfig, autName); >+ } >+ >+ /** {@inheritDoc} */ >+ public URL getComponentConfigurationFileURL() { >+ return ToolkitUtils.getURL(Activator.getDefault(), COMP_CONFIG_PATH); >+ } >+ >+ /** {@inheritDoc} */ >+ public ResourceBundle getI18nResourceBundle() { >+ return ResourceBundle.getBundle(I18N_PROPERTIES); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
markus.tiede
:
iplog+
Actions:
View
|
Diff
Attachments on
bug 421595
:
237415
|
237428
|
239575
| 239604 |
239819