changeset 4:1d98600736c5

7902092: Add JemmyBrowser to jemmy/v3
author shurailine
date Tue, 09 Jan 2018 11:03:57 -0800
parents b3f1ec02cea7
children 898c9e02c8c9
files .jcheck/conf core/JemmyBrowser/build.xml core/JemmyBrowser/src/org/jemmy/browser/BrowserDescriptor.java core/JemmyBrowser/src/org/jemmy/browser/ElementRetriever.java core/JemmyBrowser/src/org/jemmy/browser/HierarchyDescriptor.java core/JemmyBrowser/src/org/jemmy/browser/HierarchyView.form core/JemmyBrowser/src/org/jemmy/browser/HierarchyView.java core/JemmyBrowser/src/org/jemmy/browser/ImageLabel.java core/JemmyBrowser/src/org/jemmy/browser/InterfacesPanel.form core/JemmyBrowser/src/org/jemmy/browser/InterfacesPanel.java core/JemmyBrowser/src/org/jemmy/browser/NodeDescriptor.java core/JemmyBrowser/src/org/jemmy/browser/PropertiesPanel.form core/JemmyBrowser/src/org/jemmy/browser/PropertiesPanel.java core/JemmyBrowser/src/org/jemmy/browser/ReflectionPanel.form core/JemmyBrowser/src/org/jemmy/browser/ReflectionPanel.java core/JemmyBrowser/src/org/jemmy/browser/SearchDialog.form core/JemmyBrowser/src/org/jemmy/browser/SearchDialog.java core/JemmyBrowser/src/org/jemmy/browser/jemmy.properties core/JemmyBrowser/test/TEST.ROOT core/JemmyBrowser/test/org/jemmy/browser/PropPanelTest.java core/make/jemmy-v3-ii/.idea/modules.xml core/make/jemmy-v3-ii/awt-input/awt-input.iml core/make/jemmy-v3-ii/browser/browser.iml
diffstat 23 files changed, 2172 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/.jcheck/conf	Wed Jan 03 08:05:06 2018 -0800
+++ b/.jcheck/conf	Tue Jan 09 11:03:57 2018 -0800
@@ -1,3 +1,3 @@
-project=jemmy-v3
+project=code-tools
 comments=lax
 tags=lax
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/build.xml	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+ -->
+<project name="jemmy-browser" default="compile" basedir=".">
+    <import file="${basedir}/../make/build_template.xml"/>
+    <property name="core.jar" location="../JemmyCore/build/JemmyCore.jar"/>
+    <property name="version.file" value="org/jemmy/browser/jemmy.properties"/>
+    <property name="version.class" value="org.jemmy.browser.Version"/>
+    <property name="dependencies.classpath" value="${core.jar}"/>
+    <target name="check-dependecies-impl">
+        <available file="${core.jar}" property="dependencies.are.built"/>
+    </target>
+    <target name="build-dependecies-impl">
+        <ant dir="${basedir}/../JemmyCore" target="jar" inheritAll="false"/>
+    </target>
+    <target name="test-dependecies-impl">
+        <ant dir="${basedir}/../JemmyCore" target="test" inheritAll="false"/>
+    </target>
+</project>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/BrowserDescriptor.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+/**
+ *
+ * @author shura
+ */
+public interface BrowserDescriptor extends HierarchyDescriptor {
+
+    public String getTitle();
+
+    default public boolean isActiveHighlightingProvided() {
+        return false;
+    }
+    default public ElementRetriever getElementRetriever() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/ElementRetriever.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.awt.Point;
+import java.util.List;
+
+public interface ElementRetriever {
+    Object fromPoint(Point pt);
+    List<Integer> getPath(Object element);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/HierarchyDescriptor.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import org.jemmy.control.Wrap;
+import org.jemmy.control.Wrapper;
+import org.jemmy.lookup.ControlList;
+
+/**
+ *
+ * @author shura
+ */
+public interface HierarchyDescriptor {
+    public ControlList getHierarchy();
+    public Wrapper getWrapper();
+    public HierarchyDescriptor getSubHierarchyDescriptor(Wrap wrap);
+    default public NodeDescriptor getNodeDescriptor() {
+        return new NodeDescriptor() {
+            @Override
+            public String toString(Object obj) {
+                return obj.getClass().getName();
+            }
+        };
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/HierarchyView.form	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="formKeyReleased"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jSplitPane1" alignment="1" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jSplitPane1" alignment="1" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+      <Properties>
+        <Property name="dividerLocation" type="int" value="400"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="left"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
+                  <Group type="102" alignment="1" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace pref="59" max="32767" attributes="0"/>
+                              <Component id="refreshingLbl" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="sleep" min="-2" pref="27" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="refreshBtt" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="highlightControl" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                              <Component id="watchCursor" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jScrollPane1" pref="409" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="refreshBtt" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="sleep" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="refreshingLbl" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="highlightControl" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="watchCursor" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTree" name="controlTree">
+                  <Properties>
+                    <Property name="model" type="javax.swing.tree.TreeModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                      <Connection code="getTreeModel()" type="code"/>
+                    </Property>
+                    <Property name="rootVisible" type="boolean" value="false"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="controlTreeKeyReleased"/>
+                  </Events>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Component class="javax.swing.JButton" name="refreshBtt">
+              <Properties>
+                <Property name="mnemonic" type="int" value="114"/>
+                <Property name="text" type="java.lang.String" value="Refresh"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshBttActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="In"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="sleep">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="0"/>
+                <Property name="alignmentX" type="float" value="1.0"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sleepActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="seconds"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="refreshingLbl">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Refreshing"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButton1">
+              <Properties>
+                <Property name="mnemonic" type="int" value="115"/>
+                <Property name="text" type="java.lang.String" value="Search"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JCheckBox" name="highlightControl">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Highlight control"/>
+                <Property name="enabled" type="boolean" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="descr.isActiveHighlightingProvided()" type="code"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="highlightControlActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JCheckBox" name="watchCursor">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Watch cursor"/>
+                <Property name="enabled" type="boolean" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="descr.getElementRetriever() != null" type="code"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="watchCursorActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JTabbedPane" name="controlTab">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="right"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="underPropPanel">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+                  <JTabbedPaneConstraints tabName="1. Properties">
+                    <Property name="tabTitle" type="java.lang.String" value="1. Properties"/>
+                  </JTabbedPaneConstraints>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="439" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="454" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+            </Container>
+            <Container class="javax.swing.JPanel" name="underReflectionPanel">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+                  <JTabbedPaneConstraints tabName="2. Reflection">
+                    <Property name="tabTitle" type="java.lang.String" value="2. Reflection"/>
+                  </JTabbedPaneConstraints>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="439" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="454" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+            </Container>
+            <Container class="javax.swing.JPanel" name="underIntPanel">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+                  <JTabbedPaneConstraints tabName="3. Interfaces">
+                    <Property name="tabTitle" type="java.lang.String" value="3. Interfaces"/>
+                  </JTabbedPaneConstraints>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="439" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="454" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+            </Container>
+            <Container class="javax.swing.JPanel" name="jPanel2">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+                  <JTabbedPaneConstraints tabName="4. Image">
+                    <Property name="tabTitle" type="java.lang.String" value="4. Image"/>
+                  </JTabbedPaneConstraints>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="imageScroll" alignment="1" pref="439" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="imageScroll" alignment="0" pref="454" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+              <SubComponents>
+                <Container class="javax.swing.JScrollPane" name="imageScroll">
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+                </Container>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/HierarchyView.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.MouseInfo;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.awt.geom.Area;
+import java.awt.image.BufferedImage;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.ComboBoxModel;
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import javax.swing.JWindow;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import org.jemmy.control.Wrap;
+import org.jemmy.control.Wrapper;
+import org.jemmy.lookup.ControlHierarchy;
+import org.jemmy.lookup.ControlList;
+
+/**
+ *
+ * @author shura
+ */
+public class HierarchyView extends javax.swing.JFrame {
+    private static final int MARKER_BORDER_GAP = 4;
+    private static final int MARKER_BORDER_WIDTH = 4;
+    private static final int WATCHER_LOOP_DELAY = 2000;
+
+    public static void startApp(final String[] argv) {
+        new Thread(new Runnable() {
+
+            public void run() {
+                if (argv.length > 0) {
+                    try {
+                        Class appClass = Class.forName(argv[0]);
+                        appClass.getMethod("main", new Class[]{(new String[0]).getClass()}).invoke(null, (Object) Arrays.copyOfRange(argv, 1, argv.length));
+                    } catch (IllegalAccessException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (IllegalArgumentException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (InvocationTargetException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (NoSuchMethodException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (SecurityException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (ClassNotFoundException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    }
+                }
+            }
+        }).start();
+    }
+    DefaultTreeModel model;
+    PropertiesPanel propPanel;
+    InterfacesPanel intPanel;
+    BrowserDescriptor descr;
+    Wrap<?> root;
+    ArrayList<Class> subHs;
+    ComboBoxModel comboModel = new MyComboModel();
+    ReflectionPanel reflectionPanel;
+    private int sleepValue;
+    SearchDialog sd = new SearchDialog(this);
+    ImageLabel imageLabel;
+    JWindow markerFrame;
+
+    public HierarchyView(BrowserDescriptor descr) throws AWTException {
+        this(descr, null);
+    }
+
+    private HierarchyView(BrowserDescriptor descr, Wrap<?> root) throws AWTException {
+        this.descr = descr;
+        this.root = root;
+        subHs = new ArrayList<Class>();
+        setTitle(descr.getTitle());
+        rebuildModel();
+        initComponents();
+        imageLabel = new ImageLabel();
+        imageScroll.setViewportView(imageLabel);
+        underPropPanel.setLayout(new BorderLayout());
+        propPanel = new PropertiesPanel();
+        underPropPanel.add(propPanel);
+        underIntPanel.setLayout(new BorderLayout());
+        intPanel = new InterfacesPanel();
+        underIntPanel.add(intPanel);
+        underReflectionPanel.setLayout(new BorderLayout());
+        reflectionPanel = new ReflectionPanel();
+        underReflectionPanel.add(reflectionPanel, BorderLayout.CENTER);
+        controlTree.addTreeSelectionListener(new TreeSelectionListener() {
+
+            public void valueChanged(TreeSelectionEvent arg0) {
+                if (descr.isActiveHighlightingProvided()) {
+                    try {
+                        MyTreeNode selected = (MyTreeNode) arg0.getPath().getLastPathComponent();
+                        propPanel.setWrap(selected.getWrap());
+                        intPanel.setWrap(selected.getWrap());
+                        reflectionPanel.setControl(selected.getWrap().getControl().getClass());
+                        positionImage(selected.getWrap());
+                        if (markerFrame == null) {
+                            markerFrame = new JWindow();
+                            markerFrame.setAlwaysOnTop(true);
+                            markerFrame.getContentPane().setBackground(Color.red);
+                            markerFrame.setVisible(highlightControl.isSelected());
+                        }
+                        org.jemmy.Rectangle bounds = selected.wrap.getScreenBounds();
+                        markerFrame.setLocation(bounds.x - MARKER_BORDER_GAP, bounds.y - MARKER_BORDER_GAP);
+                        markerFrame.setSize(bounds.width + MARKER_BORDER_GAP * 2, bounds.height + MARKER_BORDER_GAP * 2);
+                        Area frame = new Area(new Rectangle(bounds.width + MARKER_BORDER_GAP * 2, bounds.height + MARKER_BORDER_GAP * 2));
+                        frame.subtract(new Area(new Rectangle(MARKER_BORDER_WIDTH, MARKER_BORDER_WIDTH, bounds.width + MARKER_BORDER_GAP * 2 - MARKER_BORDER_WIDTH * 2, bounds.height + MARKER_BORDER_GAP * 2 - MARKER_BORDER_WIDTH * 2)));
+                        markerFrame.setShape(frame);
+                    } catch (IllegalAccessException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (IllegalArgumentException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    } catch (InvocationTargetException ex) {
+                        Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                    }
+                }
+            }
+        });
+        refreshingLbl.setVisible(false);
+        controlTab.setMnemonicAt(0, KeyEvent.VK_1);
+        controlTab.setMnemonicAt(1, KeyEvent.VK_2);
+        controlTab.setMnemonicAt(2, KeyEvent.VK_3);
+        controlTab.setMnemonicAt(3, KeyEvent.VK_4);
+        robot = new Robot();
+    }
+
+    private void positionImage(Wrap<?> wrap) {
+        org.jemmy.Rectangle bounds = wrap.getScreenBounds();
+        imageLabel.setBounds(bounds);
+        Point center = new Point((int)(bounds.getX() + bounds.getWidth() / 2),
+                (int)(bounds.getY() + bounds.getHeight() / 2));
+        center.x -= imageScroll.getViewport().getWidth() /  2;
+        center.y -= imageScroll.getViewport().getHeight() /  2;
+        imageScroll.getHorizontalScrollBar().setValue(center.x);
+        imageScroll.getVerticalScrollBar().setValue(center.y);
+    }
+    public ComboBoxModel getComboModel() {
+        return comboModel;
+    }
+    DefaultMutableTreeNode rootNode;
+
+    private void rebuildModel() {
+        rootNode = new DefaultMutableTreeNode("");
+        model = new DefaultTreeModel(rootNode);
+        fillAll(descr, rootNode, null);
+    }
+
+    private void fillAll(HierarchyDescriptor subDescr, DefaultMutableTreeNode parent, Wrap wrap) {
+        ControlList hierarchy = subDescr.getHierarchy();
+        Wrapper wrapper = subDescr.getWrapper();
+        List controls = null;
+        if (wrap == null) {
+            controls = hierarchy.getControls();
+        } else {
+            if (hierarchy instanceof ControlHierarchy) {
+                controls = ((ControlHierarchy) hierarchy).getChildren(wrap.getControl());
+            }
+        }
+        MyTreeNode node;
+        if (controls != null) {
+            for (Object c : controls) {
+                node = new MyTreeNode(c, wrapper.wrap(Object.class, c), subDescr.getNodeDescriptor());
+                parent.add(node);
+                fillAll(subDescr, node, node.getWrap());
+            }
+        }
+        if (wrap != null) {
+            HierarchyDescriptor hd = subDescr.getSubHierarchyDescriptor(wrap);
+            if (hd != null) {
+                fillAll(hd, parent, null);
+            }
+        }
+    }
+
+    public DefaultTreeModel getTreeModel() {
+        return model;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jPanel1 = new javax.swing.JPanel();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        controlTree = new javax.swing.JTree();
+        refreshBtt = new javax.swing.JButton();
+        jLabel1 = new javax.swing.JLabel();
+        sleep = new javax.swing.JTextField();
+        jLabel2 = new javax.swing.JLabel();
+        refreshingLbl = new javax.swing.JLabel();
+        jButton1 = new javax.swing.JButton();
+        highlightControl = new javax.swing.JCheckBox();
+        watchCursor = new javax.swing.JCheckBox();
+        controlTab = new javax.swing.JTabbedPane();
+        underPropPanel = new javax.swing.JPanel();
+        underReflectionPanel = new javax.swing.JPanel();
+        underIntPanel = new javax.swing.JPanel();
+        jPanel2 = new javax.swing.JPanel();
+        imageScroll = new javax.swing.JScrollPane();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyReleased(java.awt.event.KeyEvent evt) {
+                formKeyReleased(evt);
+            }
+        });
+
+        jSplitPane1.setDividerLocation(400);
+
+        controlTree.setModel(getTreeModel());
+        controlTree.setRootVisible(false);
+        controlTree.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyReleased(java.awt.event.KeyEvent evt) {
+                controlTreeKeyReleased(evt);
+            }
+        });
+        jScrollPane1.setViewportView(controlTree);
+
+        refreshBtt.setMnemonic('r');
+        refreshBtt.setText("Refresh");
+        refreshBtt.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                refreshBttActionPerformed(evt);
+            }
+        });
+
+        jLabel1.setText("In");
+
+        sleep.setText("0");
+        sleep.setAlignmentX(1.0F);
+        sleep.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sleepActionPerformed(evt);
+            }
+        });
+
+        jLabel2.setText("seconds");
+
+        refreshingLbl.setText("Refreshing");
+
+        jButton1.setMnemonic('s');
+        jButton1.setText("Search");
+        jButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton1ActionPerformed(evt);
+            }
+        });
+
+        highlightControl.setText("Highlight control");
+        highlightControl.setEnabled(descr.isActiveHighlightingProvided());
+        highlightControl.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                highlightControlActionPerformed(evt);
+            }
+        });
+
+        watchCursor.setText("Watch cursor");
+        watchCursor.setEnabled(descr.getElementRetriever() != null);
+        watchCursor.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                watchCursorActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jButton1)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 59, Short.MAX_VALUE)
+                        .addComponent(refreshingLbl)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel1)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(sleep, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel2)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(refreshBtt)
+                        .addContainerGap())
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(highlightControl)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(watchCursor)
+                        .addGap(0, 0, Short.MAX_VALUE))))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(refreshBtt)
+                    .addComponent(jLabel2)
+                    .addComponent(sleep, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jLabel1)
+                    .addComponent(refreshingLbl)
+                    .addComponent(jButton1))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(highlightControl)
+                    .addComponent(watchCursor))
+                .addContainerGap())
+        );
+
+        jSplitPane1.setLeftComponent(jPanel1);
+
+        javax.swing.GroupLayout underPropPanelLayout = new javax.swing.GroupLayout(underPropPanel);
+        underPropPanel.setLayout(underPropPanelLayout);
+        underPropPanelLayout.setHorizontalGroup(
+            underPropPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 439, Short.MAX_VALUE)
+        );
+        underPropPanelLayout.setVerticalGroup(
+            underPropPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 454, Short.MAX_VALUE)
+        );
+
+        controlTab.addTab("1. Properties", underPropPanel);
+
+        javax.swing.GroupLayout underReflectionPanelLayout = new javax.swing.GroupLayout(underReflectionPanel);
+        underReflectionPanel.setLayout(underReflectionPanelLayout);
+        underReflectionPanelLayout.setHorizontalGroup(
+            underReflectionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 439, Short.MAX_VALUE)
+        );
+        underReflectionPanelLayout.setVerticalGroup(
+            underReflectionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 454, Short.MAX_VALUE)
+        );
+
+        controlTab.addTab("2. Reflection", underReflectionPanel);
+
+        javax.swing.GroupLayout underIntPanelLayout = new javax.swing.GroupLayout(underIntPanel);
+        underIntPanel.setLayout(underIntPanelLayout);
+        underIntPanelLayout.setHorizontalGroup(
+            underIntPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 439, Short.MAX_VALUE)
+        );
+        underIntPanelLayout.setVerticalGroup(
+            underIntPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 454, Short.MAX_VALUE)
+        );
+
+        controlTab.addTab("3. Interfaces", underIntPanel);
+
+        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(imageScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 439, Short.MAX_VALUE)
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(imageScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 454, Short.MAX_VALUE)
+        );
+
+        controlTab.addTab("4. Image", jPanel2);
+
+        jSplitPane1.setRightComponent(controlTab);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private Robot robot;
+    private BufferedImage shot = null;
+    private Rectangle fullScreen = new Rectangle(new Point(0, 0), Toolkit.getDefaultToolkit().getScreenSize());;
+    private void takeShot() {
+        shot = robot.createScreenCapture(fullScreen);
+        imageLabel.setIcon(new ImageIcon(shot));
+    }
+    private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased
+    }//GEN-LAST:event_formKeyReleased
+
+    private void highlightControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_highlightControlActionPerformed
+        if (markerFrame != null) {
+            markerFrame.setVisible(highlightControl.isSelected());
+        }
+    }//GEN-LAST:event_highlightControlActionPerformed
+
+    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
+        sd.setLocation(getLocation().x, getLocation().y + getHeight() - sd.getHeight());
+        sd.setVisible(true);
+        if (sd.isConfirmed()) {
+            MyTreeNode res = search(rootNode, sd.getClassNameFilter(), sd.getPropertyFilter());
+            if (res != null) {
+                controlTree.setSelectionPath(new TreePath(res.getPath()));
+                controlTree.requestFocus();
+            } else {
+                String msg = "Class name: \"" + sd.getClassNameFilter() + "\""+
+                ((sd.getPropertyFilter() != null) ? (", property: \"" + sd.getPropertyFilter() + "\"") : "");
+                JOptionPane.showMessageDialog(null, msg, "None found", JOptionPane.ERROR_MESSAGE);
+            }
+        }
+    }//GEN-LAST:event_jButton1ActionPerformed
+
+    private void sleepActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sleepActionPerformed
+        // TODO add your handling code here:
+    }//GEN-LAST:event_sleepActionPerformed
+
+    private void refreshBttActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshBttActionPerformed
+        sleep.setEditable(false);
+        refreshBtt.setVisible(false);
+        refreshingLbl.setVisible(true);
+        new Thread(new Runnable() {
+
+            public void run() {
+                try {
+                    SwingUtilities.invokeAndWait(new Runnable() {
+
+                        public void run() {
+                            sleepValue = Integer.parseInt(sleep.getText());
+                        }
+                    });
+                    int restSleep = sleepValue;
+                    while (restSleep > 0) {
+                        final String newText = Integer.toString(restSleep);
+                        SwingUtilities.invokeLater(new Runnable() {
+
+                            public void run() {
+                                sleep.setText(newText);
+                            }
+                        });
+                        Thread.sleep(1000);
+                        restSleep--;
+                    }
+                    rebuildModel();
+                } catch (InvocationTargetException ex) {
+                    Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, ex);
+                } catch (InterruptedException e) {
+                    Logger.getLogger(HierarchyView.class.getName()).log(Level.SEVERE, null, e);
+                } finally {
+                    SwingUtilities.invokeLater(new Runnable() {
+
+                        public void run() {
+                            refreshingLbl.setVisible(false);
+                            refreshBtt.setVisible(true);
+                            sleep.setEditable(true);
+                            sleep.setText(Integer.toString(sleepValue));
+                            controlTree.setModel(model);
+                            controlTree.revalidate();
+                            controlTree.requestFocus();
+                            takeShot();
+                        }
+                    });
+                }
+            }
+        }).start();
+    }//GEN-LAST:event_refreshBttActionPerformed
+
+    private void controlTreeKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_controlTreeKeyReleased
+
+    }//GEN-LAST:event_controlTreeKeyReleased
+
+    private void watchCursorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_watchCursorActionPerformed
+        if (watchCursor.isSelected()) {
+            watcherRunning = true;
+            ElementRetriever retriever = descr.getElementRetriever();
+            if (retriever != null) {
+                Thread watcher = new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        while (watcherRunning) {
+                            Point pt = MouseInfo.getPointerInfo().getLocation();
+                            try {
+                                new Robot().waitForIdle();
+                                for (int i = 0; i < 10; i++) {
+                                    if (!watcherRunning) {
+                                        return;
+                                    }
+                                    Thread.sleep(WATCHER_LOOP_DELAY/10);
+                                    Point new_pt = MouseInfo.getPointerInfo().getLocation();
+                                    if (!new_pt.equals(pt)) {
+                                        pt = new_pt;
+                                        i = 0;
+                                    }
+                                }
+                            } catch (AWTException ex) {
+                            } catch (InterruptedException ex) {
+                            }
+                            Object element = retriever.fromPoint(pt);
+                            // extremely slow for MSAA proxy
+                            MyTreeNode watched = search(rootNode, element);
+                            // does not work due to the bugs in MS's walker implementation
+                            /*final List<Integer> path = retriever.getPath(element);
+                            MyTreeNode watched = search(rootNode, path);*/
+                            if (watched != null && !watched.equals(latestWatched)) {
+                                TreePath treePath = new TreePath(watched.getPath());
+                                SwingUtilities.invokeLater(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        controlTree.setSelectionPath(treePath);
+                                        controlTree.scrollPathToVisible(treePath);
+                                        controlTree.requestFocus();
+                                        latestWatched = watched;
+                                    }
+                                });
+                            }
+                        }
+                    }
+                });
+                watcher.start();
+            }
+        } else {
+            watcherRunning = false;
+        }
+    }//GEN-LAST:event_watchCursorActionPerformed
+
+    private MyTreeNode search(DefaultMutableTreeNode node, List<Integer> path) {
+        for (Integer index : path) {
+            node = (MyTreeNode)node.getChildAt(index);
+        }
+        return (MyTreeNode)node;
+    }
+
+    private MyTreeNode search(DefaultMutableTreeNode node, Object control) {
+        if (node instanceof MyTreeNode) {
+            MyTreeNode mtnode = (MyTreeNode) node;
+            Object element = mtnode.getWrap().getControl();
+            if (element.equals(control)) {
+                return mtnode;
+            }
+        }
+        MyTreeNode res;
+        for (int i = 0; i < node.getChildCount(); i++) {
+            res = search((DefaultMutableTreeNode) node.getChildAt(i), control);
+            if (res != null) {
+                return res;
+            }
+        }
+        return null;
+    }
+
+    private MyTreeNode search(DefaultMutableTreeNode node, String className, String property) {
+        if (node instanceof MyTreeNode && ((MyTreeNode) node).getWrap().getControl().getClass().getName().indexOf(className) > 1) {
+            MyTreeNode mtnode = (MyTreeNode) node;
+            if (property != null) {
+                HashMap<String, Object> props = mtnode.getWrap().getProperties();
+                for (String prop : props.keySet()) {
+                    if (props.get(prop) != null) {
+                        if (props.get(prop).toString() != null) {
+                            if (props.get(prop).toString().contains(property)) {
+                                return mtnode;
+                            }
+                        }
+                    }
+                }
+            } else {
+                return mtnode;
+            }
+        }
+        MyTreeNode res;
+        for (int i = 0; i < node.getChildCount(); i++) {
+            res = search((DefaultMutableTreeNode) node.getChildAt(i), className, property);
+            if (res != null) {
+                return res;
+            }
+        }
+        return null;
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTabbedPane controlTab;
+    private javax.swing.JTree controlTree;
+    private javax.swing.JCheckBox highlightControl;
+    private javax.swing.JScrollPane imageScroll;
+    private javax.swing.JButton jButton1;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JButton refreshBtt;
+    private javax.swing.JLabel refreshingLbl;
+    private javax.swing.JTextField sleep;
+    private javax.swing.JPanel underIntPanel;
+    private javax.swing.JPanel underPropPanel;
+    private javax.swing.JPanel underReflectionPanel;
+    private javax.swing.JCheckBox watchCursor;
+    // End of variables declaration//GEN-END:variables
+
+    // End of variables declaration
+    private volatile boolean watcherRunning;
+    private MyTreeNode latestWatched;
+
+    private class MyTreeNode extends DefaultMutableTreeNode {
+
+        Wrap wrap = null;
+        Object control;
+        NodeDescriptor descriptor;
+
+        public MyTreeNode(Object control, Wrap wrap, NodeDescriptor descriptor) {
+            super(control);
+            this.control = control;
+            this.wrap = wrap;
+            this.descriptor = descriptor;
+        }
+
+        public Wrap<?> getWrap() {
+            return wrap;
+        }
+
+        @Override
+        public String toString() {
+            return descriptor.toString(control);
+        }
+    }
+
+    private class MyComboModel implements ComboBoxModel {
+
+        Class<?> selected;
+
+        public void setSelectedItem(Object arg0) {
+            System.out.println(arg0 + " selected");
+            selected = (Class<?>) arg0;
+        }
+
+        public Object getSelectedItem() {
+            System.out.println("selected = " + selected);
+            return selected;
+        }
+
+        public int getSize() {
+            return subHs.size();
+        }
+
+        public Object getElementAt(int arg0) {
+            return subHs.get(arg0);
+        }
+
+        public void addListDataListener(ListDataListener arg0) {
+        }
+
+        public void removeListDataListener(ListDataListener arg0) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/ImageLabel.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import javax.swing.JLabel;
+import org.jemmy.Rectangle;
+
+/**
+ *
+ * @author shura
+ */
+public class ImageLabel extends JLabel {
+
+    private org.jemmy.Rectangle bounds = new org.jemmy.Rectangle(100, 100, 100, 100);
+
+    public ImageLabel() {
+        super();
+    }
+
+    public void setBounds(Rectangle bounds) {
+        this.bounds = bounds;
+        repaint();
+    }
+
+    @Override
+    public void paint(Graphics grphcs) {
+        super.paint(grphcs);
+        grphcs.setColor(Color.red);
+        if(bounds != null) {
+            grphcs.drawRect(bounds.x - 1, bounds.y - 1, bounds.width + 2, bounds.height + 2);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/InterfacesPanel.form	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,46 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="481" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="480" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTable" name="interfacesTable">
+          <Properties>
+            <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="getTableModel()" type="code"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/InterfacesPanel.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import javax.swing.table.DefaultTableModel;
+import org.jemmy.control.ControlInterfaces;
+import org.jemmy.control.Property;
+import org.jemmy.control.Wrap;
+import org.jemmy.interfaces.ControlInterface;
+import org.jemmy.interfaces.InterfaceException;
+
+/**
+ *
+ * @author shura
+ */
+public class InterfacesPanel extends javax.swing.JPanel {
+
+    private static final String OFFSET = "    ";
+    Wrap<?> wrap;
+    DefaultTableModel tableModel;
+
+    /** Creates new form InterfacesPanel */
+    public InterfacesPanel() {
+        tableModel = new DefaultTableModel();
+        tableModel.addColumn("Interface/Property");
+        tableModel.addColumn("Class/Value");
+        initComponents();
+    }
+
+    public void setWrap(Wrap<?> wrap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        this.wrap = wrap;
+        buildModel();
+        revalidate();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        interfacesTable = new javax.swing.JTable();
+
+        interfacesTable.setModel(getTableModel());
+        jScrollPane1.setViewportView(interfacesTable);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 481, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTable interfacesTable;
+    private javax.swing.JScrollPane jScrollPane1;
+    // End of variables declaration//GEN-END:variables
+
+    public DefaultTableModel getTableModel() {
+        return tableModel;
+    }
+
+    private void buildModel() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        while (getTableModel().getRowCount() > 0) {
+            getTableModel().removeRow(0);
+        }
+        Class cls = wrap.getClass();
+        ArrayList<Class> interfaces =
+                new ArrayList<Class>();
+        do {
+            ControlInterfaces cis = ((Class<? extends Wrap>) cls).getAnnotation(ControlInterfaces.class);
+            for (Class c : cis.value()) {
+                if (!interfaces.contains(c)) {
+                    interfaces.add(c);
+                }
+            }
+        } while (Wrap.class.isAssignableFrom((cls = cls.getSuperclass())));
+        Collections.sort(interfaces, new Comparator() {
+            public int compare(Object t, Object t1) {
+                return t.toString().compareTo(t1.toString());
+            }
+        });
+        for (Class<? extends ControlInterface> c : interfaces) {
+            String iName = c.getName();
+            try {
+                Object iInstance = wrap.as(c);
+                getTableModel().addRow(new Object[]{iName, iInstance.getClass().getName()});
+                for (Method m : c.getMethods()) {
+                    if (m.isAnnotationPresent(Property.class)) {
+                        String name = m.getAnnotation(Property.class).value();
+                        getTableModel().addRow(new Object[]{OFFSET + name, wrap.getProperty(name, c)});
+                    }
+                }
+            } catch (InterfaceException e) {
+                //do nothing
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/NodeDescriptor.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+public interface NodeDescriptor {
+    public String toString(Object obj);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/PropertiesPanel.form	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="400" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="300" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTable" name="jTable1">
+          <Properties>
+            <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="getTableModel()" type="code"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/PropertiesPanel.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import javax.swing.table.DefaultTableModel;
+import org.jemmy.control.Wrap;
+
+/**
+ *
+ * @author shura
+ */
+public class PropertiesPanel extends javax.swing.JPanel {
+
+    DefaultTableModel model;
+
+    /** Creates new form PropertiesPanel */
+    public PropertiesPanel() {
+        model = new DefaultTableModel();
+        model.addColumn("Property");
+        model.addColumn("Class");
+        model.addColumn("Value");
+        initComponents();
+    }
+
+    public DefaultTableModel getTableModel() {
+        return model;
+    }
+
+    public void setWrap(Wrap<?> control) {
+        while (getTableModel().getRowCount() > 0) {
+            getTableModel().removeRow(0);
+        }
+        if (control != null) {
+            HashMap<String, Object> props = control.getPropertiesQiuet();
+            Object val;
+            ArrayList<String> propNames = new ArrayList<String>(props.keySet());
+            Collections.sort(propNames);
+            for (String pk : propNames) {
+                val = props.get(pk);
+                if(val != null) {
+                    model.addRow(new Object[]{pk, val.getClass().getName(), val.toString()});
+                } else {
+                    model.addRow(new Object[]{pk, "null", "null"});
+                }
+            }
+        }
+        revalidate();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTable1 = new javax.swing.JTable();
+
+        jTable1.setModel(getTableModel());
+        jScrollPane1.setViewportView(jTable1);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTable jTable1;
+    // End of variables declaration//GEN-END:variables
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/ReflectionPanel.form	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,41 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="400" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jScrollPane1" alignment="0" pref="300" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTree" name="tree">
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/ReflectionPanel.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+
+/**
+ *
+ * @author shura
+ */
+public class ReflectionPanel extends javax.swing.JPanel {
+
+    DefaultTreeModel model;
+    /** Creates new form ReflectionPanel */
+    public ReflectionPanel() {
+        initComponents();
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode("");
+        model = new DefaultTreeModel(root);
+        tree.setModel(model);
+    }
+
+    public DefaultTreeModel getTreeModel() {
+        return model;
+    }
+
+    public void setControl(Class controlClass) {
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode();
+        Class cls =controlClass;
+        do {
+            root.add(getClassNode(cls));
+        } while((cls = cls.getSuperclass()) != null);
+        for(Class i : controlClass.getInterfaces()) {
+            root.add(getClassNode(i));
+        }
+        model.setRoot(root);
+        tree.setModel(model);
+        revalidate();
+    }
+
+    private DefaultMutableTreeNode getClassNode(Class cls) {
+        DefaultMutableTreeNode classNode = new DefaultMutableTreeNode(
+                (cls.isInterface() ? "Interface " : "Class ") +
+                cls.getName());
+        for(Method m : cls.getMethods()) {
+            StringBuffer signature = new StringBuffer(m.getReturnType().getName());
+            signature.append(" " + m.getName() + "(");
+            for(int i = 0; i < m.getParameterTypes().length; i++) {
+                signature.append(m.getParameterTypes()[i].getName());
+                if((i < m.getParameterTypes().length - 1)) {
+                    signature.append(",");
+                }
+            }
+            signature.append(")");
+            classNode.add(new DefaultMutableTreeNode(signature.toString()));
+        }
+        for(Field m : cls.getFields()) {
+            classNode.add(new DefaultMutableTreeNode(m.getType().getName() + " " + m.getName()));
+        }
+        return classNode;
+    }
+
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        tree = new javax.swing.JTree();
+
+        jScrollPane1.setViewportView(tree);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTree tree;
+    // End of variables declaration//GEN-END:variables
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/SearchDialog.form	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,111 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="modal" type="boolean" value="true"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="searchBtn" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="cancelBtn" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="useProp" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="searchTF" alignment="0" pref="263" max="32767" attributes="0"/>
+                          <Component id="propSearch" alignment="0" pref="263" max="32767" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="searchTF" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="useProp" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="propSearch" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="32767" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="cancelBtn" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="searchBtn" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Class name"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="searchTF">
+    </Component>
+    <Component class="javax.swing.JButton" name="cancelBtn">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Cancel"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelBtnActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="searchBtn">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Search"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchBtnActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JCheckBox" name="useProp">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Property value"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="usePropActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JTextField" name="propSearch">
+      <Properties>
+        <Property name="enabled" type="boolean" value="false"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/SearchDialog.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import javax.swing.JTextField;
+
+/**
+ *
+ * @author shura
+ */
+public class SearchDialog extends javax.swing.JDialog {
+    private boolean doSearch;
+
+    /** Creates new form SearchDialog */
+    public SearchDialog(java.awt.Frame parent) {
+        super(parent, true);
+        initComponents();
+        getRootPane().setDefaultButton(searchBtn);
+    }
+
+    public boolean isConfirmed() {
+        return doSearch;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        searchTF = new javax.swing.JTextField();
+        cancelBtn = new javax.swing.JButton();
+        searchBtn = new javax.swing.JButton();
+        useProp = new javax.swing.JCheckBox();
+        propSearch = new javax.swing.JTextField();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setModal(true);
+
+        jLabel1.setText("Class name");
+
+        cancelBtn.setText("Cancel");
+        cancelBtn.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                cancelBtnActionPerformed(evt);
+            }
+        });
+
+        searchBtn.setText("Search");
+        searchBtn.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                searchBtnActionPerformed(evt);
+            }
+        });
+
+        useProp.setText("Property value");
+        useProp.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                usePropActionPerformed(evt);
+            }
+        });
+
+        propSearch.setEnabled(false);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                        .addComponent(searchBtn)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(cancelBtn))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(useProp)
+                            .addComponent(jLabel1))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(searchTF, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
+                            .addComponent(propSearch, javax.swing.GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE))))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel1)
+                    .addComponent(searchTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(useProp)
+                    .addComponent(propSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(cancelBtn)
+                    .addComponent(searchBtn))
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed
+        doSearch = false;
+        setVisible(false);
+    }//GEN-LAST:event_cancelBtnActionPerformed
+
+    private void searchBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchBtnActionPerformed
+        doSearch = true;
+        setVisible(false);
+    }//GEN-LAST:event_searchBtnActionPerformed
+
+    private void usePropActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_usePropActionPerformed
+        propSearch.setEnabled(useProp.isSelected());
+        if(useProp.isSelected()) {
+            propSearch.requestFocus();
+        }
+    }//GEN-LAST:event_usePropActionPerformed
+
+    public String getClassNameFilter() {
+        return searchTF.getText();
+    }
+
+    public String getPropertyFilter() {
+        return useProp.isSelected() ? propSearch.getText() : null;
+    }
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton cancelBtn;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JTextField propSearch;
+    private javax.swing.JButton searchBtn;
+    private javax.swing.JTextField searchTF;
+    private javax.swing.JCheckBox useProp;
+    // End of variables declaration//GEN-END:variables
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/src/org/jemmy/browser/jemmy.properties	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,3 @@
+version.major=0
+version.minor=9
+version.mini=5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/test/TEST.ROOT	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,2 @@
+TestNG.dirs = .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/JemmyBrowser/test/org/jemmy/browser/PropPanelTest.java	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.jemmy.browser;
+
+import org.jemmy.Point;
+import org.jemmy.Rectangle;
+import org.jemmy.action.GetAction;
+import org.jemmy.control.Property;
+import org.jemmy.control.Wrap;
+import org.jemmy.env.Environment;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import javax.swing.JFrame;
+import javax.swing.table.TableModel;
+import java.awt.BorderLayout;
+
+import static org.testng.Assert.fail;
+
+
+/**
+ *
+ * @author shura
+ */
+public class PropPanelTest {
+
+    public PropPanelTest() {
+    }
+
+    static Wrap<? extends JFrame> frm;
+    static PropertiesPanel panel;
+    static TableModel table;
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        JFrame frame = new JFrame("test frame");
+        frame.setVisible(true);
+        frame.setSize(400, 600);
+        frame.getContentPane().setLayout(new BorderLayout());
+        panel = new PropertiesPanel();
+        frame.getContentPane().add(panel, BorderLayout.CENTER);
+        frm = new TestWrap(Environment.getEnvironment(), frame);
+        panel.setWrap(frm);
+        table = panel.model;
+    }
+    @DataProvider(name = "testcases")
+    public Object[][] testcases() {
+        return new Object[][] {
+                {"bounds", Rectangle.class, null},
+                {"control", JFrame.class, frm.getControl().toString()},
+                {"clickPoint", Point.class, null},
+                {"wrapper.class", Class.class, TestWrap.class.toString()},
+                {"getTitle", String.class, "test frame"},
+                {"control.class", Class.class, JFrame.class.toString()},
+                {"isShowing", Boolean.class, "true"}
+        };
+    }
+
+    @Test(dataProvider = "testcases")
+    public void checkTable(String name, Class cls, String expectedValue) {
+        for (int i = 0; i < table.getRowCount(); i++) {
+            if(table.getValueAt(i, 0).equals(name)) {
+                if(!table.getValueAt(i, 1).equals(cls.getName())) {
+                    fail("Wrong class for " + name + ": " + table.getValueAt(i, 1) + " (expected " + cls.getName() + ")");
+                }
+                if(expectedValue != null) {
+                    if(!table.getValueAt(i, 2).equals(expectedValue)) {
+                        fail("Wrong value for " + name + ": " + table.getValueAt(i, 2) + " (expected " + expectedValue + ")");
+                    }
+                }
+                return;
+            }
+        }
+        fail(name + " not found!");
+    }
+
+    public static class TestWrap<T extends JFrame> extends Wrap<T> {
+
+        public TestWrap(Environment env, T frame) {
+            super(env, frame);
+        }
+
+        @Override
+        public Rectangle getScreenBounds() {
+            return new Rectangle(
+                    getControl().getX(),
+                    getControl().getY(),
+                    getControl().getWidth(),
+                    getControl().getHeight());
+        }
+        @Property("getTitle")
+        public String getTitle() {
+            return new GetAction<String>() {
+
+                @Override
+                public void run(Object... parameters) throws Exception {
+                    setResult(getControl().getTitle());
+                }
+            }.dispatch(getEnvironment());
+        }
+        @Property("isShowing")
+        public boolean isShowing() {
+            return new GetAction<Boolean>() {
+
+                @Override
+                public void run(Object... parameters) throws Exception {
+                    setResult(getControl().isShowing());
+                }
+            }.dispatch(getEnvironment());
+        }
+    }
+}
--- a/core/make/jemmy-v3-ii/.idea/modules.xml	Wed Jan 03 08:05:06 2018 -0800
+++ b/core/make/jemmy-v3-ii/.idea/modules.xml	Tue Jan 09 11:03:57 2018 -0800
@@ -3,6 +3,7 @@
   <component name="ProjectModuleManager">
     <modules>
       <module fileurl="file://$PROJECT_DIR$/awt-input/awt-input.iml" filepath="$PROJECT_DIR$/awt-input/awt-input.iml" />
+      <module fileurl="file://$PROJECT_DIR$/browser/browser.iml" filepath="$PROJECT_DIR$/browser/browser.iml" />
       <module fileurl="file://$PROJECT_DIR$/core/core.iml" filepath="$PROJECT_DIR$/core/core.iml" />
     </modules>
   </component>
--- a/core/make/jemmy-v3-ii/awt-input/awt-input.iml	Wed Jan 03 08:05:06 2018 -0800
+++ b/core/make/jemmy-v3-ii/awt-input/awt-input.iml	Tue Jan 09 11:03:57 2018 -0800
@@ -8,9 +8,6 @@
     <content url="file://$MODULE_DIR$/../../../JemmyAWTInput/test">
       <sourceFolder url="file://$MODULE_DIR$/../../../JemmyAWTInput/test" isTestSource="true" />
     </content>
-    <content url="file://$MODULE_DIR$/../..">
-      <sourceFolder url="file://$MODULE_DIR$/../.." isTestSource="false" />
-    </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="module" module-name="core" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/make/jemmy-v3-ii/browser/browser.iml	Tue Jan 09 11:03:57 2018 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../../JemmyBrowser/src">
+      <sourceFolder url="file://$MODULE_DIR$/../../../JemmyBrowser/src" isTestSource="false" />
+    </content>
+    <content url="file://$MODULE_DIR$/../../../JemmyBrowser/test">
+      <sourceFolder url="file://$MODULE_DIR$/../../../JemmyBrowser/test" isTestSource="true" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="core" />
+    <orderEntry type="library" scope="TEST" name="testng" level="application" />
+  </component>
+</module>
\ No newline at end of file