testng, junit: provide multiselection configurations on test method level (IDEA-72406)
authorAnna Kozlova <anna.kozlova@jetbrains.com>
Tue, 24 Jan 2012 16:30:01 +0000 (20:30 +0400)
committerAnna Kozlova <anna.kozlova@jetbrains.com>
Tue, 24 Jan 2012 16:35:36 +0000 (20:35 +0400)
14 files changed:
platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java
platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
platform/testRunner/src/com/intellij/execution/testframework/ui/TestsOutputConsolePrinter.java
plugins/junit/src/com/intellij/execution/junit/AddToTestsPatternAction.java
plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java
plugins/junit/src/com/intellij/execution/junit/PatternConfigurationProducer.java
plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java
plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java
plugins/junit/src/com/intellij/execution/junit/TestsPattern.java
plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTestTreeView.java
plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGInClassConfigurationProducer.java
plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGPatternConfigurationProducer.java
plugins/testng/src/com/theoryinpractice/testng/ui/TestNGTestTreeView.java

index 028e5602166b39b87445858e52f118c1b38ce3e7..06958b5d78112dc515663674a1c95fbadc7e6996 100644 (file)
@@ -50,12 +50,12 @@ public class CompositePrintable implements Printable, Disposable {
     }
   }
 
-  public void invokeInAlarm(Runnable runnable) {
+  public static void invokeInAlarm(Runnable runnable) {
     invokeInAlarm(runnable, !ApplicationManager.getApplication().isDispatchThread() ||
                             ApplicationManager.getApplication().isUnitTestMode());
   }
 
-  public void invokeInAlarm(Runnable runnable, final boolean sync) {
+  public static void invokeInAlarm(Runnable runnable, final boolean sync) {
     if (sync) {
       runnable.run();
     } else {
index d9a7bcaa345ee04dac0f2a1ea7489cdc0b6de4e2..9e2fb6dd21d623597c7a46913bdbe285ee3632eb 100644 (file)
@@ -27,16 +27,14 @@ import com.intellij.openapi.Disposable;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.ide.CopyPasteManager;
 import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
 import com.intellij.ui.PopupHandler;
 import com.intellij.ui.TreeSpeedSearch;
 import com.intellij.ui.treeStructure.Tree;
 import com.intellij.util.EditSourceOnDoubleClickHandler;
-import com.intellij.util.Function;
 import com.intellij.util.containers.Convertor;
 import com.intellij.util.ui.tree.TreeUtil;
+import org.intellij.lang.annotations.JdkConstants;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -53,13 +51,15 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
 
   @Nullable
   public AbstractTestProxy getSelectedTest() {
+    TreePath[] paths = getSelectionPaths();
+    if (paths != null && paths.length > 1) return null;
     final TreePath selectionPath = getSelectionPath();
     return selectionPath != null ? getSelectedTest(selectionPath) : null;
   }
 
   public void attachToModel(final TestFrameworkRunningModel model) {
     setModel(new DefaultTreeModel(new DefaultMutableTreeNode(model.getRoot())));
-    getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+    getSelectionModel().setSelectionMode(getSelectionMode());
     myModel = model;
     Disposer.register(myModel, myModel.getRoot());
     Disposer.register(myModel, new Disposable() {
@@ -84,6 +84,20 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
     if (PlatformDataKeys.COPY_PROVIDER.is(dataId)) {
       return this;
     }
+
+    if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
+      TreePath[] paths = getSelectionPaths();
+      if (paths != null && paths.length > 1) {
+        final PsiElement[] els = new PsiElement[paths.length];
+        int i = 0;
+        for (TreePath path : paths) {
+          AbstractTestProxy test = getSelectedTest(path);
+          els[i++] = test != null ? (PsiElement)TestsUIUtil.getData(test, LangDataKeys.PSI_ELEMENT.getName(), myModel) : null;
+        }
+        return els;
+      }
+    }
+    
     final TreePath selectionPath = getSelectionPath();
     if (selectionPath == null) return null;
     final AbstractTestProxy testProxy = getSelectedTest(selectionPath);
@@ -120,4 +134,9 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
     PopupHandler.installPopupHandler(this, IdeActions.GROUP_TESTTREE_POPUP, ActionPlaces.TESTTREE_VIEW_POPUP);
     ViewAssertEqualsDiffAction.registerShortcut(this);
   }
+
+  @JdkConstants.TreeSelectionMode
+  protected int getSelectionMode() {
+    return TreeSelectionModel.SINGLE_TREE_SELECTION;
+  }
 }
\ No newline at end of file
index 68b3bb0573352da1b506667a0adc3270a9eb4e7c..c698014d912a78ce8dc2d498675996e5c4873adb 100644 (file)
@@ -89,17 +89,18 @@ public class TestsOutputConsolePrinter implements Printer, Disposable {
       myCurrentTest.setPrinter(null);
     }
     myMarkOffset = 0;
+    final Runnable clearRunnable = new Runnable() {
+      public void run() {
+        myConsole.clear();
+      }
+    };
     if (test == null) {
       myCurrentTest = null;
+      CompositePrintable.invokeInAlarm(clearRunnable);
       return;
     }
     myCurrentTest = test;
     myCurrentTest.setPrinter(this);
-    final Runnable clearRunnable = new Runnable() {
-      public void run() {
-        myConsole.clear();
-      }
-    };
     final Runnable scrollRunnable = new Runnable() {
       @Override
       public void run() {
@@ -107,9 +108,9 @@ public class TestsOutputConsolePrinter implements Printer, Disposable {
       }
     };
     final AbstractTestProxy currentProxyOrRoot = getCurrentProxyOrRoot();
-    currentProxyOrRoot.invokeInAlarm(clearRunnable);
+    CompositePrintable.invokeInAlarm(clearRunnable);
     currentProxyOrRoot.printOn(this);
-    currentProxyOrRoot.invokeInAlarm(scrollRunnable);
+    CompositePrintable.invokeInAlarm(scrollRunnable);
   }
 
   private AbstractTestProxy getCurrentProxyOrRoot() {
index 59ed8ff39042ee639b3ae199c06f8c286afa1bae..03bc8450a76416b25783e702d3b204c358fd5381 100644 (file)
@@ -27,8 +27,8 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.popup.JBPopupFactory;
 import com.intellij.openapi.ui.popup.PopupStep;
 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
-import com.intellij.psi.PsiClass;
 import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMember;
 import org.jetbrains.annotations.NotNull;
 
 import javax.swing.*;
@@ -41,21 +41,21 @@ public class AddToTestsPatternAction extends AnAction {
   public void actionPerformed(AnActionEvent e) {
     final DataContext dataContext = e.getDataContext();
     final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
-    final Set<PsiClass> classes = PatternConfigurationProducer.collectTestClasses(psiElements);
+    final Set<PsiMember> classes = PatternConfigurationProducer.collectTestMembers(psiElements);
 
     final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
     final List<JUnitConfiguration> patternConfigurations = collectPatternConfigurations(classes, project);
     if (patternConfigurations.size() == 1) {
       final JUnitConfiguration configuration = patternConfigurations.get(0);
-      for (PsiClass aClass : classes) {
-        configuration.getPersistentData().getPatterns().add(aClass.getQualifiedName());
+      for (PsiMember aClass : classes) {
+        configuration.getPersistentData().getPatterns().add(PatternConfigurationProducer.getQName(aClass));
       }
     } else {
       JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep<JUnitConfiguration>("Choose suite to add", patternConfigurations) {
         @Override
         public PopupStep onChosen(JUnitConfiguration configuration, boolean finalChoice) {
-          for (PsiClass aClass : classes) {
-            configuration.getPersistentData().getPatterns().add(aClass.getQualifiedName());
+          for (PsiMember aClass : classes) {
+            configuration.getPersistentData().getPatterns().add(PatternConfigurationProducer.getQName(aClass));
           }
           return FINAL_CHOICE;
         }
@@ -81,11 +81,11 @@ public class AddToTestsPatternAction extends AnAction {
     final DataContext dataContext = e.getDataContext();
     final PsiElement[] psiElements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
     if (psiElements != null) {
-      final Set<PsiClass> foundClasses = PatternConfigurationProducer.collectTestClasses(psiElements);
-      if (foundClasses.isEmpty()) return;
+      final Set<PsiMember> foundMembers = PatternConfigurationProducer.collectTestMembers(psiElements);
+      if (foundMembers.isEmpty()) return;
       final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
       if (project != null) {
-        final List<JUnitConfiguration> foundConfigurations = collectPatternConfigurations(foundClasses, project);
+        final List<JUnitConfiguration> foundConfigurations = collectPatternConfigurations(foundMembers, project);
         if (!foundConfigurations.isEmpty()) {
           presentation.setVisible(true);
           if (foundConfigurations.size() == 1) {
@@ -96,13 +96,13 @@ public class AddToTestsPatternAction extends AnAction {
     }
   }
 
-  private static List<JUnitConfiguration> collectPatternConfigurations(Set<PsiClass> foundClasses, Project project) {
+  private static List<JUnitConfiguration> collectPatternConfigurations(Set<PsiMember> foundClasses, Project project) {
     final RunConfiguration[] configurations = RunManager.getInstance(project).getConfigurations(JUnitConfigurationType.getInstance());
     final List<JUnitConfiguration> foundConfigurations = new ArrayList<JUnitConfiguration>();
     for (RunConfiguration configuration : configurations) {
       final JUnitConfiguration.Data data = ((JUnitConfiguration)configuration).getPersistentData();
       if (data.TEST_OBJECT == JUnitConfiguration.TEST_PATTERN) {
-        if (foundClasses.size() > 1 || !data.getPatterns().contains(foundClasses.iterator().next().getQualifiedName()) ) {
+        if (foundClasses.size() > 1 || !data.getPatterns().contains(PatternConfigurationProducer.getQName(foundClasses.iterator().next())) ) {
           foundConfigurations.add((JUnitConfiguration)configuration);
         }
       }
index 9330be77d79d8a804d4f3f696dd9d33ecff4fbac..7dcf4b2aec65c9fc8fc6cca19d12142b0d6166c2 100644 (file)
@@ -49,7 +49,7 @@ public abstract class JUnitConfigurationProducer extends JavaRuntimeConfiguratio
                                                                  @NotNull RunnerAndConfigurationSettings[] existingConfigurations,
                                                                  ConfigurationContext context) {
     final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
-    if (elements != null && PatternConfigurationProducer.collectTestClasses(elements).size() > 1) {
+    if (elements != null && PatternConfigurationProducer.collectTestMembers(elements).size() > 1) {
       return null;
     }
     final Module predefinedModule =
index a00cc22ec67c900f0e17d03c6a1bdd66a2bf310d..ec4ca58d31852780fbd677a99629a8d530e6167a 100644 (file)
@@ -51,38 +51,42 @@ public class PatternConfigurationProducer extends JUnitConfigurationProducer {
     return settings;
   }
 
-  static Set<PsiClass> collectTestClasses(PsiElement[] psiElements) {
-    final Set<PsiClass> foundClasses = new LinkedHashSet<PsiClass>();
+  static Set<PsiMember> collectTestMembers(PsiElement[] psiElements) {
+    final Set<PsiMember> foundMembers = new LinkedHashSet<PsiMember>();
     for (PsiElement psiElement : psiElements) {
       if (psiElement instanceof PsiClassOwner) {
         final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses();
         for (PsiClass aClass : classes) {
           if (JUnitUtil.isTestClass(aClass)) {
-            foundClasses.add(aClass);
+            foundMembers.add(aClass);
           }
         }
       } else if (psiElement instanceof PsiClass) {
         if (JUnitUtil.isTestClass((PsiClass)psiElement)) {
-          foundClasses.add((PsiClass)psiElement);
+          foundMembers.add((PsiClass)psiElement);
+        }
+      } else if (psiElement instanceof PsiMethod) {
+        if (JUnitUtil.getTestMethod(psiElement) != null) {
+          foundMembers.add((PsiMethod)psiElement);
         }
       }
     }
-    return foundClasses;
+    return foundMembers;
   }
 
   private static PsiElement[] collectPatternElements(ConfigurationContext context, LinkedHashSet<String> classes) {
     final DataContext dataContext = context.getDataContext();
     PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
     if (elements != null) {
-      for (PsiClass psiClass : collectTestClasses(elements)) {
-        classes.add(psiClass.getQualifiedName());
+      for (PsiMember psiClass : collectTestMembers(elements)) {
+        classes.add(getQName(psiClass));
       }
       return elements;
     } else {
       final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
       if (file instanceof PsiClassOwner) {
-        for (PsiClass psiClass : collectTestClasses(((PsiClassOwner)file).getClasses())) {
-          classes.add(psiClass.getQualifiedName());
+        for (PsiMember psiMember : collectTestMembers(((PsiClassOwner)file).getClasses())) {
+          classes.add(((PsiClass)psiMember).getQualifiedName());
         }
         return new PsiElement[]{file};
       }
@@ -90,6 +94,15 @@ public class PatternConfigurationProducer extends JUnitConfigurationProducer {
     return null;
   }
 
+  public static String getQName(PsiMember psiMember) {
+    if (psiMember instanceof PsiClass) {
+      return ((PsiClass)psiMember).getQualifiedName();
+    }
+    else {
+      return psiMember.getContainingClass().getQualifiedName() + "," + psiMember.getName();
+    }
+  }
+
   public PsiElement getSourceElement() {
     return myElements[0];
   }
index 906b8efd3479a8caf5c8d0df1f80d3d214766d46..b82776997dcf111c3bd602d74affe1fe204683a1 100644 (file)
 
 package com.intellij.execution.junit;
 
-import com.intellij.execution.*;
+import com.intellij.execution.JavaExecutionUtil;
+import com.intellij.execution.JavaRunConfigurationExtensionManager;
+import com.intellij.execution.Location;
+import com.intellij.execution.RunnerAndConfigurationSettings;
 import com.intellij.execution.actions.ConfigurationContext;
 import com.intellij.openapi.actionSystem.LangDataKeys;
 import com.intellij.openapi.module.Module;
@@ -33,7 +36,7 @@ public class TestClassConfigurationProducer extends JUnitConfigurationProducer {
     final Project project = location.getProject();
 
     final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
-    if (elements != null && PatternConfigurationProducer.collectTestClasses(elements).size() > 1) {
+    if (elements != null && PatternConfigurationProducer.collectTestMembers(elements).size() > 1) {
       return null;
     }
     myTestClass = JUnitUtil.getTestClass(location);
index ba311ff099e46f871fc01539ca22cff6ad7919d1..1683f893cadd6670ba5cf87f73c27f440f2289d5 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.execution.PsiLocation;
 import com.intellij.execution.RunnerAndConfigurationSettings;
 import com.intellij.execution.actions.ConfigurationContext;
 import com.intellij.execution.junit2.info.MethodLocation;
+import com.intellij.openapi.actionSystem.LangDataKeys;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiClass;
@@ -36,7 +37,10 @@ public class TestMethodConfigurationProducer extends JUnitConfigurationProducer
 
   protected RunnerAndConfigurationSettings createConfigurationByElement(final Location location, final ConfigurationContext context) {
     final Project project = location.getProject();
-
+    final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
+    if (elements != null && PatternConfigurationProducer.collectTestMembers(elements).size() > 1) {
+      return null;
+    }
     myMethodLocation = getTestMethod(location);
     if (myMethodLocation == null) return null;
     RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(project, context);
index 6263fcea49267f3092edc04eb48efbbffae62714..df090c198bf0db440e0c1e4e93e85eafee7827d8 100644 (file)
@@ -60,7 +60,7 @@ public class TestsPattern extends TestObject {
     final ArrayList<String> classNames = new ArrayList<String>();
     final Set<Module> modules = new HashSet<Module>();
     for (String className : data.getPatterns()) {
-      final PsiClass psiClass = JavaExecutionUtil.findMainClass(project, className, GlobalSearchScope.allScope(project));
+      final PsiClass psiClass = JavaExecutionUtil.findMainClass(project, className.contains(",") ? className.substring(0, className.indexOf(',')) : className, GlobalSearchScope.allScope(project));
       if (psiClass != null && JUnitUtil.isTestClass(psiClass)) {
         classNames.add(className);
         modules.add(ModuleUtil.findModuleForPsiElement(psiClass));
@@ -84,7 +84,7 @@ public class TestsPattern extends TestObject {
     addClassesListToJavaParameters(classNames, StringUtil.isEmpty(data.METHOD_NAME) ? FunctionUtil.<String>id() : new Function<String, String>() {
       @Override
       public String fun(String className) {
-        return className + "," + data.METHOD_NAME;
+        return className;
       }
     }, "", true, isJUnit4);
   }
index 334e578050870cfe0854b085aac999545a48dcd3..efc51cce4774607ada9cfd72bf38da5381788979 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.execution.testframework.TestTreeView;
 import org.jetbrains.annotations.NotNull;
 
 import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
 
 public class JUnitTestTreeView extends TestTreeView {
 
@@ -41,4 +42,9 @@ public class JUnitTestTreeView extends TestTreeView {
                                    final boolean hasFocus) {
     return Formatters.printTest(TestProxyClient.from(value));
   }
+
+  @Override
+  protected int getSelectionMode() {
+    return TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION;
+  }
 }
index 5f85cf25d57cedb23af0ab9f3ed8df372eddbd9b..d67e876a760165d3a6c2b9e8af09286655102c94 100644 (file)
@@ -362,8 +362,17 @@ public class SearchingForTestsTask extends Task.Backgroundable {
       }
     }
     else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
-      final String methodName = data.getMethodName();
-      for (final String className : data.getPatterns()) {
+      for (final String pattern : data.getPatterns()) {
+        final String className;
+        final String methodName;
+        if (pattern.contains(",")) {
+          methodName = StringUtil.getShortName(pattern, ',');
+          className = StringUtil.getPackageName(pattern, ',');
+        } else {
+          className = pattern;
+          methodName = null;
+        }
+        
         final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
           @Nullable
           @Override
index 67035b795bd6e35676facd60092a4dd8c2d29f9d..723b3a31e226269ef52a9816e324c91608c66029 100644 (file)
  */
 package com.theoryinpractice.testng.configuration;
 
-import com.intellij.execution.*;
+import com.intellij.execution.JavaRunConfigurationExtensionManager;
+import com.intellij.execution.Location;
+import com.intellij.execution.PsiLocation;
+import com.intellij.execution.RunnerAndConfigurationSettings;
 import com.intellij.execution.actions.ConfigurationContext;
 import com.intellij.execution.junit.InheritorChooser;
 import com.intellij.execution.junit2.info.MethodLocation;
@@ -45,7 +48,7 @@ public class TestNGInClassConfigurationProducer extends TestNGConfigurationProdu
   @Nullable
   protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext context) {
     final PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
-    if (elements != null && TestNGPatternConfigurationProducer.collectTestClasses(elements).size() > 1) {
+    if (elements != null && TestNGPatternConfigurationProducer.collectTestMembers(elements).size() > 1) {
       return null;
     }
 
index 9294974ccd79719b11b31bc3c149ce6437a65841..3f52715ee692e22f6f250d4ccb5782c7496940f4 100644 (file)
@@ -29,10 +29,7 @@ import com.intellij.openapi.actionSystem.DataContext;
 import com.intellij.openapi.actionSystem.LangDataKeys;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Comparing;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiClassOwner;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
+import com.intellij.psi.*;
 import com.theoryinpractice.testng.model.TestData;
 import com.theoryinpractice.testng.model.TestType;
 import com.theoryinpractice.testng.util.TestNGUtil;
@@ -66,38 +63,46 @@ public class TestNGPatternConfigurationProducer extends TestNGConfigurationProdu
     return settings;
   }
 
-  static Set<PsiClass> collectTestClasses(PsiElement[] psiElements) {
-    final Set<PsiClass> foundClasses = new LinkedHashSet<PsiClass>();
+  static Set<PsiMember> collectTestMembers(PsiElement[] psiElements) {
+    final Set<PsiMember> foundMembers = new LinkedHashSet<PsiMember>();
     for (PsiElement psiElement : psiElements) {
       if (psiElement instanceof PsiClassOwner) {
         final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses();
         for (PsiClass aClass : classes) {
           if (JUnitUtil.isTestClass(aClass)) {
-            foundClasses.add(aClass);
+            foundMembers.add(aClass);
           }
         }
       } else if (psiElement instanceof PsiClass) {
         if (TestNGUtil.hasTest((PsiClass)psiElement)) {
-          foundClasses.add((PsiClass)psiElement);
+          foundMembers.add((PsiClass)psiElement);
+        }
+      } else if (psiElement instanceof PsiMethod) {
+        if (TestNGUtil.hasTest((PsiModifierListOwner)psiElement)) {
+          foundMembers.add((PsiMember)psiElement);
         }
       }
     }
-    return foundClasses;
+    return foundMembers;
   }
 
   private static PsiElement[] collectPatternElements(ConfigurationContext context, LinkedHashSet<String> classes) {
     final DataContext dataContext = context.getDataContext();
     PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
     if (elements != null) {
-      for (PsiClass psiClass : collectTestClasses(elements)) {
-        classes.add(psiClass.getQualifiedName());
+      for (PsiMember psiMember : collectTestMembers(elements)) {
+        if (psiMember instanceof PsiClass) {
+          classes.add(((PsiClass)psiMember).getQualifiedName());
+        } else {
+          classes.add(psiMember.getContainingClass().getQualifiedName() + "," + psiMember.getName());
+        }
       }
       return elements;
     } else {
       final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
       if (file instanceof PsiClassOwner) {
-        for (PsiClass psiClass : collectTestClasses(((PsiClassOwner)file).getClasses())) {
-          classes.add(psiClass.getQualifiedName());
+        for (PsiMember psiMember : collectTestMembers(((PsiClassOwner)file).getClasses())) {
+          classes.add(((PsiClass)psiMember).getQualifiedName());
         }
         return new PsiElement[]{file};
       }
index 6c799a1c165c59b969d9f73cb683206fb7124d32..48f252d828ee033883fe6e607a82e24fe2b519be 100644 (file)
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.TreeCellRenderer;
 import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
 
 /**
  * @author Hani Suleiman Date: Aug 1, 2005 Time: 11:33:12 AM
@@ -53,4 +54,9 @@ public class TestNGTestTreeView extends TestTreeView {
     }
     return "";
   }
+
+  @Override
+  protected int getSelectionMode() {
+    return TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION;
+  }
 }
\ No newline at end of file