diff --git a/community-tests/community-tests.iml b/community-tests/community-tests.iml
index 2eb0f6cc6f74..04445d253ad3 100644
--- a/community-tests/community-tests.iml
+++ b/community-tests/community-tests.iml
@@ -3,24 +3,15 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
@@ -30,14 +21,14 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -49,7 +40,11 @@
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/community-tests/src/META-INF/community-tests.xml b/community-tests/src/META-INF/community-tests.xml
new file mode 100644
index 000000000000..4ceadd7837e2
--- /dev/null
+++ b/community-tests/src/META-INF/community-tests.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/community-tests/src/com/intellij/tests/gui/JavaEEProjectTest.java b/community-tests/src/com/intellij/tests/gui/JavaEEProjectTest.java
index 2f2221c66dcc..9e7df1f9ddf0 100644
--- a/community-tests/src/com/intellij/tests/gui/JavaEEProjectTest.java
+++ b/community-tests/src/com/intellij/tests/gui/JavaEEProjectTest.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ProjectUtil;
+import com.intellij.tests.gui.fixtures.ActionLinkFixture;
import com.intellij.tests.gui.fixtures.ProjectViewFixture;
import com.intellij.tests.gui.fixtures.ToolWindowFixture;
import com.intellij.tests.gui.fixtures.newProjectWizard.NewProjectWizardFixture;
diff --git a/community-tests/src/com/intellij/tests/gui/JavaProjectTest.kt b/community-tests/src/com/intellij/tests/gui/JavaProjectTest.kt
index 2dce0ef14924..f3a23d3f5b80 100644
--- a/community-tests/src/com/intellij/tests/gui/JavaProjectTest.kt
+++ b/community-tests/src/com/intellij/tests/gui/JavaProjectTest.kt
@@ -15,15 +15,16 @@
*/
package com.intellij.tests.gui
+import com.intellij.tests.gui.fixtures.ActionLinkFixture
import com.intellij.tests.gui.fixtures.DialogFixtures.CreateDialogFixture
import com.intellij.tests.gui.fixtures.EditorFixture
import com.intellij.tests.gui.fixtures.JBPopupFixture
-import com.intellij.tests.gui.framework.GuiTestCase
-import com.intellij.tests.gui.framework.TestGroup
-import com.intellij.tests.gui.framework.createNewProject
+import com.intellij.tests.gui.framework.*
+import com.intellij.ui.components.JBList
import org.junit.Ignore
import org.junit.Test
import java.io.File
+import javax.swing.JTextField
import javax.swing.text.JTextComponent
/**
@@ -42,7 +43,8 @@ class JavaProjectTest: GuiTestCase() {
val newProjectWizard = findNewProjectWizard()
with(newProjectWizard){
setupJdk()
- selectProjectType("Java")
+// selectProjectType("Java")
+ clickListItem("Java", robot(), this.target())
selectFramework("JavaEE Persistence")
clickNext()
setProjectName(projectName);
diff --git a/community-tests/src/com/intellij/tests/gui/fixtures/ActionLinkFixture.java b/community-tests/src/com/intellij/tests/gui/fixtures/ActionLinkFixture.java
index 24bbda785a64..bc4643517ccb 100755
--- a/community-tests/src/com/intellij/tests/gui/fixtures/ActionLinkFixture.java
+++ b/community-tests/src/com/intellij/tests/gui/fixtures/ActionLinkFixture.java
@@ -33,6 +33,7 @@ import static com.intellij.util.containers.ContainerUtil.getFirstItem;
import static org.fest.swing.timing.Pause.pause;
public class ActionLinkFixture extends JComponentFixture {
+
@NotNull
public static ActionLinkFixture findByActionId(@NotNull final String actionId,
@NotNull final Robot robot,
@@ -67,6 +68,39 @@ public class ActionLinkFixture extends JComponentFixture actionLinkRef = new Ref();
+ pause(new Condition("Find ActionLink with name '" + actionName + "'") {
+ @Override
+ public boolean test() {
+ Collection found = robot.finder().findAll(container, new GenericTypeMatcher(ActionLink.class) {
+ @Override
+ protected boolean isMatching(@NotNull ActionLink actionLink) {
+ if (actionLink.isVisible()) {
+ return actionLink.getText().equals(actionName);
+ }
+ return false;
+ }
+ });
+ if (found.size() == 1) {
+ actionLinkRef.set(getFirstItem(found));
+ return true;
+ }
+ return false;
+ }
+ }, SHORT_TIMEOUT);
+
+ ActionLink actionLink = actionLinkRef.get();
+ if (actionLink == null) {
+ throw new ComponentLookupException("Failed to find ActionLink with name '" + actionName + "'");
+ }
+ return new ActionLinkFixture(robot, actionLink);
+ }
+
+
private ActionLinkFixture(@NotNull Robot robot, @NotNull ActionLink target) {
super(ActionLinkFixture.class, robot, target);
}
diff --git a/community-tests/src/com/intellij/tests/gui/framework/GuiTests.java b/community-tests/src/com/intellij/tests/gui/framework/GuiTests.java
index 0003c3479471..b5ee7c75f877 100644
--- a/community-tests/src/com/intellij/tests/gui/framework/GuiTests.java
+++ b/community-tests/src/com/intellij/tests/gui/framework/GuiTests.java
@@ -41,9 +41,7 @@ import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.popup.list.ListPopupModel;
import com.intellij.util.JdkBundle;
import com.intellij.util.ui.EdtInvocationManager;
-import org.fest.swing.core.BasicRobot;
-import org.fest.swing.core.ComponentFinder;
-import org.fest.swing.core.GenericTypeMatcher;
+import org.fest.swing.core.*;
import org.fest.swing.core.Robot;
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
@@ -609,6 +607,18 @@ public final class GuiTests {
}
}
+ @Nullable
+ public static JLabel findBoundedLabel(@NotNull Container container, @NotNull JTextField textField, @NotNull Robot robot) {
+ Collection labels = robot.finder().findAll(container, new GenericTypeMatcher(JLabel.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JLabel label) {
+ return label.getLabelFor().equals(textField);
+ }
+ });
+ if (labels != null && !labels.isEmpty()) return labels.iterator().next();
+ else return null;
+ }
+
@NotNull
public static JButton findButton(@NotNull ContainerFixture extends Container> container, @NotNull final String text, Robot robot) {
return robot.finder().find(container.target(), new GenericTypeMatcher(JButton.class) {
@@ -741,4 +751,6 @@ public final class GuiTests {
String homeSubPath = SystemInfo.isMac ? "/Contents/Home" : "";
return jdkBundle.getLocation().getAbsolutePath() + homeSubPath;
}
+
+
}
diff --git a/community-tests/src/com/intellij/tests/gui/framework/ScriptingAPI.kt b/community-tests/src/com/intellij/tests/gui/framework/ScriptingAPI.kt
index 96151752dcd9..292c099cc8b7 100644
--- a/community-tests/src/com/intellij/tests/gui/framework/ScriptingAPI.kt
+++ b/community-tests/src/com/intellij/tests/gui/framework/ScriptingAPI.kt
@@ -2,9 +2,12 @@ package com.intellij.tests.gui.framework
import com.intellij.openapi.ui.JBPopupMenu
import com.intellij.tests.gui.fixtures.WelcomeFrameFixture
+import com.intellij.ui.components.JBList
import org.fest.swing.core.Robot
+import org.fest.swing.fixture.JListFixture
import org.fest.swing.timing.Condition
import org.fest.swing.timing.Pause
+import java.awt.Container
/**
We presume that IDEA is already started, shows "Welcome dialog" and we could create a new project
@@ -22,4 +25,9 @@ fun pause(time: Long, root: Robot) {
}
}, time)
+}
+
+fun clickListItem(itemName: String, robot: Robot, parentContainer: Container) {
+ val listFixture = JListFixture(robot, robot.finder().findByType(parentContainer, JBList::class.java, true))
+ listFixture.clickItem(itemName)
}
\ No newline at end of file
diff --git a/community-tests/src/com/intellij/tests/gui/script/ScriptRecorder.kt b/community-tests/src/com/intellij/tests/gui/script/ScriptRecorder.kt
new file mode 100644
index 000000000000..dd9fc9eb4a33
--- /dev/null
+++ b/community-tests/src/com/intellij/tests/gui/script/ScriptRecorder.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.tests.gui.script
+
+import com.intellij.internal.inspector.UiDropperActionExtension
+import com.intellij.openapi.actionSystem.AnAction
+import java.awt.Component
+import javax.swing.*
+
+/**
+ * Created by jetbrains on 18/08/16.
+ */
+
+
+/**
+ * ScriptRecorder needs to create GUI Tests quickly. For recording UI actions like click, text entering, checkbox marking we using UI dropper.
+ */
+class ScriptRecorder() : AnAction(), UiDropperActionExtension {
+
+ override fun getAnAction(): com.intellij.openapi.actionSystem.AnAction? {
+ return this
+ }
+
+ var currentContextComponent: Component? = null
+ private var currentContext = Contexts()
+
+
+ override fun actionPerformed(e: com.intellij.openapi.actionSystem.AnActionEvent?) {
+ //get action type for script: click, enter text, mark checkbox
+ val component = e!!.getDataContext().getData("Component") as Component
+ checkContext(component)
+ clickCmp(component, e)
+ }
+
+ //registering custom actions for a UI Dropper by ctrl + alt + click
+ fun registerUiDropperAction() {
+ com.intellij.internal.inspector.UiDropperAction.setClickAction(this)
+ }
+
+ fun recordAction() {
+
+ }
+
+ fun clickCmp(cmp: Component, e: com.intellij.openapi.actionSystem.AnActionEvent) {
+ when (cmp) {
+ is JButton -> write(Templates.findAndClickButton(cmp.text))
+ is com.intellij.ui.components.labels.ActionLink -> write(Templates.clickActionLink(cmp.text))
+ is JTextField -> {
+ write(Templates.findJTextField())
+ }
+ is com.intellij.ui.components.JBList -> {
+ val itemName = e.dataContext.getData("ItemName") as String
+ if (isPopupList(cmp))
+ write(Templates.clickPopupItem(itemName))
+ else
+ write(Templates.clickListItem(itemName))
+ }
+ }
+ }
+
+ private fun isPopupList(cmp: Component) = cmp.javaClass.name.toLowerCase().contains("listpopup")
+
+ fun checkContext(cmp: Component) {
+ cmp as JComponent
+ if (isPopupList(cmp)) return //dont' change context for a popup menu
+ if (currentContextComponent != null && !cmp.rootPane.equals(currentContextComponent)) {
+ write(currentContext.closeContext())
+ }
+ if (currentContextComponent == null || !cmp.rootPane.equals(currentContextComponent)) {
+ currentContextComponent = cmp.rootPane
+ when (cmp.rootPane.parent) {
+ is JDialog -> {
+ if ((cmp.rootPane.parent as JDialog).title.equals(com.intellij.ide.IdeBundle.message("title.new.project")))
+ write(currentContext.projectWizardContextStart())
+ else
+ write(currentContext.dialogContextStart((cmp.rootPane.parent as JDialog).title))
+ }
+ is com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrame -> write(currentContext.welcomeFrameStart())
+ is JFrame -> println("is JFrame")
+ }
+
+ }
+ }
+
+ fun write(str: String) {
+ println(str)
+ }
+
+}
+
+//TEMPLATES
+private object Templates {
+ fun findDialog(name: String, title: String?) = "val ${name} = DialogFixture.find(robot(), \"${title}\")"
+ fun withDialog(name: String) = "with (${name}){"
+ fun findProjectWizard(name: String) = "val ${name} = findNewProjectWizard()"
+ fun withProjectWizard(name: String) = "with (${name}){"
+ fun findWelcomeFrame(name: String) = "val ${name} = findWelcomeFrame()"
+ fun withWelcomeFrame(name: String) = "with (${name}){"
+
+ fun findAndClickButton(text: String) = "GuiTests.findAndClickButton(this, \"${text}\")"
+ fun clickActionLink(text: String) = "ActionLinkFixture.findActionLinkByName(\"${text}\", robot(), this.target()).click()"
+
+ fun clickPopupItem(itemName: String) = "GuiTests.clickPopupMenuItem(\"${itemName}\", this.target(), robot())"
+ fun clickListItem(name: String) = "clickListItem(\"${name}\", robot(), this.target())"
+
+ fun findJTextField() = "val textField = myRobot.finder().findByType(JTextField::class.java)"
+ fun findJTextFieldByLabel(labelText: String) = "val textField = findTextField(\"${labelText}\").click()"
+}
+
+
+private class Contexts() {
+
+ enum class Type {DIALOG, WELCOME_FRAME, PROJECT_WIZARD, IDE_FRAME}
+
+ var dialogCount = 0
+ var currentContextType: Type? = null
+
+ fun dialogContextStart(title: String): String {
+ currentContextType = Type.DIALOG
+ val name = "dialog${dialogCount++}"
+ val findDialog = Templates.findDialog(name, title)
+ val withDialog = Templates.withDialog(name)
+ return findDialog + "\n" + withDialog
+ }
+
+ fun projectWizardContextStart(): String {
+ currentContextType = Type.PROJECT_WIZARD
+ val name = "projectWizard"
+ val findProjectWizard = Templates.findProjectWizard(name)
+ val withProjectWizard = Templates.withProjectWizard(name)
+ return findProjectWizard + "\n" + withProjectWizard
+ }
+
+ fun welcomeFrameStart(): String {
+ currentContextType = Type.WELCOME_FRAME
+ val name = "welcomeFrame"
+ val findWelcomeFrame = Templates.findWelcomeFrame(name)
+ var withWelcomeFrame = Templates.withWelcomeFrame(name)
+ return findWelcomeFrame + "\n" + withWelcomeFrame
+ }
+
+ fun closeContext() = "}"
+
+}
diff --git a/platform/platform-impl/src/com/intellij/internal/inspector/UiDropperAction.java b/platform/platform-impl/src/com/intellij/internal/inspector/UiDropperAction.java
index fe351d52c205..a4f549ed15da 100644
--- a/platform/platform-impl/src/com/intellij/internal/inspector/UiDropperAction.java
+++ b/platform/platform-impl/src/com/intellij/internal/inspector/UiDropperAction.java
@@ -23,27 +23,29 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.keymap.impl.keyGestures.GestureActionEvent;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.StripeTable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.IdeGlassPane;
+import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
+import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.Function;
import com.intellij.util.ObjectUtils;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.WeakKeyWeakValueHashMap;
import com.intellij.util.ui.*;
import com.intellij.util.ui.tree.TreeUtil;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -63,15 +65,16 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
-import javax.xml.crypto.Data;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.*;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.Vector;
import static java.awt.event.MouseEvent.BUTTON1;
import static java.awt.event.MouseEvent.MOUSE_CLICKED;
@@ -125,7 +128,7 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
NotificationType.INFORMATION);
}
}
-
+
private static class InspectorWindow extends JDialog {
private InspectorTable myInspectorTable;
private Component myComponent;
@@ -426,6 +429,14 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
setFont(UIUtil.getLabelFont());
}
+ public MyLabel(String text, JComponent glassPane, int width) {
+ super(text);
+ myText = text;
+ myGlasspane = glassPane;
+ setForeground(Gray._230);
+ setFont(new Font(UIUtil.getLabelFont().getName(), Font.PLAIN, 6));
+ }
+
public void dispose() {
if (myGlasspane != null) myGlasspane.remove(this);
}
@@ -1019,9 +1030,15 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
JRootPane rootPane = SwingUtilities.getRootPane(jbList);
JComponent glassPane = (JComponent)rootPane.getGlassPane();
+ if (!(glassPane instanceof IdeGlassPane)) rootPane.setGlassPane(new IdeGlassPaneImpl(rootPane));
myHighlightComponent = new HighlightComponent(new JBColor(JBColor.GREEN, JBColor.RED), glassPane, jbList);
- myLabel = new MyLabel("JBList Cell: " + elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane);
+ if (elementAt instanceof PopupFactoryImpl.ActionItem) {
+ myLabel = new MyLabel(elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane, cellBounds.width);
+ } else {
+ myLabel = new MyLabel("JBList Cell: " + elementAt.getClass().getName() + " (\"" + elementAt.toString() + "\")", glassPane);
+ }
+
Point jbListLocationOnRootPane = SwingUtilities.convertPoint(jbList, new Point(0, 0), jbList.getRootPane());
myHighlightComponent.setBounds(jbListLocationOnRootPane.x + cellBounds.x, jbListLocationOnRootPane.y + cellBounds.y, cellBounds.width, cellBounds.height);
@@ -1065,6 +1082,22 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
glassPane.repaint();
}
+ @Nullable
+ private static String getCellText(@NotNull JBList jbList, @NotNull Point pointOnList){
+ int index = jbList.locationToIndex(pointOnList);
+ Rectangle cellBounds = jbList.getCellBounds(index, index);
+ if (cellBounds.contains(pointOnList)) {
+ Object elementAt = jbList.getModel().getElementAt(index);
+ if (elementAt instanceof PopupFactoryImpl.ActionItem) {
+ return ((PopupFactoryImpl.ActionItem)elementAt).getText();
+ }
+ else {
+ return elementAt.toString();
+ }
+ }
+ return null;
+ }
+
private void cleanupHighlighting() {
if (myHighlightComponent != null) {
myHighlightComponent.dispose();
@@ -1166,7 +1199,11 @@ public class UiDropperAction extends ToggleAction implements DumbAware {
//user click
if (me.getClickCount() == 1 && me.getID() == MOUSE_CLICKED && me.getButton() == BUTTON1) {
if (clickAction != null) {
- DataContext dataContext = SimpleDataContext.getSimpleContext("Component", component);
+ Map dataMap = new HashMap<>();
+ dataMap.put("Component", component);
+ if (component instanceof JBList)
+ dataMap.put("ItemName", getCellText((JBList)component, mousePoint));
+ DataContext dataContext = SimpleDataContext.getSimpleContext(dataMap, null);
AnActionEvent event = AnActionEvent.createFromDataContext(UI_DROPPER_PLACE, null, dataContext);
clickAction.actionPerformed(event);
return;
diff --git a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
index 7b5ef05e85d4..3c8db98c5dd1 100644
--- a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
+++ b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml
@@ -100,6 +100,9 @@
+
+
+
diff --git a/platform/platform-resources/src/META-INF/PlatformPlugin.xml b/platform/platform-resources/src/META-INF/PlatformPlugin.xml
index fd5b7a1f99d7..14eff28ca9c6 100644
--- a/platform/platform-resources/src/META-INF/PlatformPlugin.xml
+++ b/platform/platform-resources/src/META-INF/PlatformPlugin.xml
@@ -13,6 +13,9 @@
+
+
+
diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml
index f5e91239caeb..fe061cae2744 100644
--- a/resources/src/idea/RichPlatformPlugin.xml
+++ b/resources/src/idea/RichPlatformPlugin.xml
@@ -396,6 +396,9 @@
+
+
+