Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'testsrunner/org.eclipse.cdt.testsrunner')
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/.classpath7
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/.project34
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/.settings/org.eclipse.jdt.core.prefs82
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/META-INF/MANIFEST.MF37
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/about.html24
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/build.properties23
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/history_list.gifbin0 -> 225 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_auto.gifbin0 -> 338 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_horizontal.gifbin0 -> 354 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_vertical.gifbin0 -> 219 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/rerun.gifbin0 -> 580 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/scroll_lock.gifbin0 -> 588 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_next.gifbin0 -> 204 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_previous.gifbin0 -> 152 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/sort.gifbin0 -> 137 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/stop.gifbin0 -> 152 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/history_list.gifbin0 -> 586 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_auto.gifbin0 -> 358 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_horizontal.gifbin0 -> 374 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_vertical.gifbin0 -> 352 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/rerun.gifbin0 -> 590 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/scroll_lock.gifbin0 -> 626 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_next.gifbin0 -> 332 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_previous.gifbin0 -> 323 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_tests_hierarchy.gifbin0 -> 101 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/sort.gifbin0 -> 157 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/stop.gifbin0 -> 215 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/eview16/cppunit.gifbin0 -> 219 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/show_failed_only.gifbin0 -> 163 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_aborted.gifbin0 -> 374 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_failed.gifbin0 -> 374 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_notrun.gifbin0 -> 362 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_passed.gifbin0 -> 380 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_run.gifbin0 -> 594 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_skipped.gifbin0 -> 365 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_aborted.gifbin0 -> 376 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_failed.gifbin0 -> 376 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_notrun.gifbin0 -> 358 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_passed.gifbin0 -> 382 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_run.gifbin0 -> 589 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/aborted_counter.gifbin0 -> 82 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/failed_counter.gifbin0 -> 82 bytes
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/plugin.properties30
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/plugin.xml255
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/pom.xml17
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/schema/TestsRunner.exsd178
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/TestsRunnerPlugin.java239
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/CdiRunTestsLaunchDelegate.java26
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/DsfGdbRunTestsLaunchDelegate.java26
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ITestsLaunchConfigurationConstants.java36
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.java26
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.properties12
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ProcessWrapper.java115
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestingProcessFactory.java111
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProviderInfo.java167
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProvidersManager.java80
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ITestingSessionsManagerListener.java30
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.java28
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.properties14
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestCase.java102
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestItem.java56
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestLocation.java41
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestMessage.java57
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestModelManager.java480
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestSuite.java85
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSession.java280
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSessionsManager.java215
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/CTestingTab.java200
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/EmptyConfigurationTabGroup.java29
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.java29
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.properties15
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/CounterPanel.java147
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/DummyUISession.java85
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/MessagesViewer.java573
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressBar.java183
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressCountPanel.java87
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsPanel.java245
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsView.java366
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestPathUtils.java115
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestsHierarchyViewer.java554
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIUpdater.java517
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.java36
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.properties22
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.java77
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.properties63
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedMessagesAction.java65
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedTestsAction.java65
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/HistoryDropDownAction.java448
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessageLevelFilterAction.java58
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessagesOrderingAction.java42
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/OpenInEditorAction.java181
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RedebugSelectedAction.java36
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RelaunchSelectedAction.java96
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunAction.java50
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunSelectedAction.java36
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ScrollLockAction.java41
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFailedOnlyAction.java40
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFileNameOnlyAction.java38
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowNextFailureAction.java40
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowPreviousFailureAction.java40
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTestsInHierarchyAction.java40
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTimeAction.java37
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/StopAction.java46
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyCollapseAllAction.java37
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyExpandAllAction.java37
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ToggleOrientationAction.java60
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/BaseTestsLaunchDelegate.java255
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerConstants.java40
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProvider.java54
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProviderInfo.java68
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/IModelVisitor.java33
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestCase.java31
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestItem.java95
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestLocation.java35
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestMessage.java72
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelAccessor.java52
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelUpdater.java94
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestSuite.java22
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSession.java135
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSessionListener.java66
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.java30
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.properties16
-rw-r--r--testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/TestingException.java28
123 files changed, 8915 insertions, 0 deletions
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/.classpath b/testsrunner/org.eclipse.cdt.testsrunner/.classpath
new file mode 100644
index 0000000000..deb673668e
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/.project b/testsrunner/org.eclipse.cdt.testsrunner/.project
new file mode 100644
index 0000000000..e4270dc3e9
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.testsrunner</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/.settings/org.eclipse.jdt.core.prefs b/testsrunner/org.eclipse.cdt.testsrunner/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..0e860bfc27
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,82 @@
+#Mon Apr 16 13:01:24 EEST 2012
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/META-INF/MANIFEST.MF b/testsrunner/org.eclipse.cdt.testsrunner/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..b7d79fc37d
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/META-INF/MANIFEST.MF
@@ -0,0 +1,37 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.cdt.testsrunner;singleton:=true
+Bundle-Version: 7.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime;bundle-version="3.5.0",
+ org.eclipse.cdt.core;bundle-version="5.1.0",
+ org.eclipse.core.resources;bundle-version="3.5.0",
+ org.eclipse.debug.ui;bundle-version="3.5.0",
+ org.eclipse.cdt.debug.core;bundle-version="6.0.0",
+ org.eclipse.cdt.debug.ui,
+ org.eclipse.cdt.ui,
+ org.eclipse.cdt.dsf.gdb.ui,
+ org.eclipse.cdt.dsf.gdb
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Import-Package: org.eclipse.cdt.dsf.gdb.launching,
+ org.eclipse.cdt.internal.ui.viewsupport,
+ org.eclipse.cdt.launch,
+ org.eclipse.cdt.launch.internal.ui,
+ org.eclipse.cdt.launch.ui,
+ org.eclipse.core.filesystem,
+ org.eclipse.jface.text,
+ org.eclipse.ui.ide,
+ org.eclipse.ui.texteditor
+Export-Package: org.eclipse.cdt.testsrunner.internal,
+ org.eclipse.cdt.testsrunner.internal.launcher,
+ org.eclipse.cdt.testsrunner.internal.model,
+ org.eclipse.cdt.testsrunner.internal.ui.launcher,
+ org.eclipse.cdt.testsrunner.internal.ui.view,
+ org.eclipse.cdt.testsrunner.internal.ui.view.actions,
+ org.eclipse.cdt.testsrunner.launcher,
+ org.eclipse.cdt.testsrunner.model
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/about.html b/testsrunner/org.eclipse.cdt.testsrunner/about.html
new file mode 100644
index 0000000000..d7c511887d
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/about.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>About</title></head>
+
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 22, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html> \ No newline at end of file
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/build.properties b/testsrunner/org.eclipse.cdt.testsrunner/build.properties
new file mode 100644
index 0000000000..bc8bffa769
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/build.properties
@@ -0,0 +1,23 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+
+bin.includes = plugin.xml,\
+ plugin.properties,\
+ icons/,\
+ about.html,\
+ .,\
+ META-INF/
+javadoc.packages = org.eclipse.cdt.launch.ui.*,\
+ org.eclipse.cdt.launch.sourcelookup*,\
+ org.eclipse.cdt.launch.*
+source.. = src/
+src.includes = about.html,\
+ schema/
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/history_list.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/history_list.gif
new file mode 100644
index 0000000000..131063ce97
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/history_list.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_auto.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_auto.gif
new file mode 100644
index 0000000000..1b93aaca76
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_auto.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_horizontal.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_horizontal.gif
new file mode 100644
index 0000000000..ce1a29cab8
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_horizontal.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_vertical.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_vertical.gif
new file mode 100644
index 0000000000..5bffca21bc
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/orientation_vertical.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/rerun.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/rerun.gif
new file mode 100644
index 0000000000..bfadfaa089
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/rerun.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/scroll_lock.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/scroll_lock.gif
new file mode 100644
index 0000000000..b776478935
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/scroll_lock.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_next.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_next.gif
new file mode 100644
index 0000000000..388ef91e0c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_next.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_previous.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_previous.gif
new file mode 100644
index 0000000000..c00fe058da
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/show_previous.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/sort.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/sort.gif
new file mode 100644
index 0000000000..a0245485d5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/sort.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/stop.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/stop.gif
new file mode 100644
index 0000000000..4f3dcba276
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/dlcl16/stop.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/history_list.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/history_list.gif
new file mode 100644
index 0000000000..364c0e70b1
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/history_list.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_auto.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_auto.gif
new file mode 100644
index 0000000000..45469ad67c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_auto.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_horizontal.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_horizontal.gif
new file mode 100644
index 0000000000..d590470446
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_horizontal.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_vertical.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_vertical.gif
new file mode 100644
index 0000000000..dee0cbca02
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/orientation_vertical.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/rerun.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/rerun.gif
new file mode 100644
index 0000000000..afb6fa934c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/rerun.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/scroll_lock.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/scroll_lock.gif
new file mode 100644
index 0000000000..68fd6cf39c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/scroll_lock.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_next.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_next.gif
new file mode 100644
index 0000000000..072b184457
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_next.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_previous.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_previous.gif
new file mode 100644
index 0000000000..07164754e5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_previous.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_tests_hierarchy.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_tests_hierarchy.gif
new file mode 100644
index 0000000000..234486172c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/show_tests_hierarchy.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/sort.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/sort.gif
new file mode 100644
index 0000000000..7d27529b64
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/sort.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/stop.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/stop.gif
new file mode 100644
index 0000000000..dc47edf069
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/elcl16/stop.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/eview16/cppunit.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/eview16/cppunit.gif
new file mode 100644
index 0000000000..883170d6d3
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/eview16/cppunit.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/show_failed_only.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/show_failed_only.gif
new file mode 100644
index 0000000000..c182d04d3f
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/show_failed_only.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_aborted.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_aborted.gif
new file mode 100644
index 0000000000..f866a2e1b2
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_aborted.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_failed.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_failed.gif
new file mode 100644
index 0000000000..de59bac205
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_failed.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_notrun.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_notrun.gif
new file mode 100644
index 0000000000..8f73ccb15b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_notrun.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_passed.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_passed.gif
new file mode 100644
index 0000000000..f824bd8c01
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_passed.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_run.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_run.gif
new file mode 100644
index 0000000000..ad88296bc7
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_run.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_skipped.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_skipped.gif
new file mode 100644
index 0000000000..e1465e3d54
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/test_skipped.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_aborted.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_aborted.gif
new file mode 100644
index 0000000000..7cd107cdc8
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_aborted.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_failed.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_failed.gif
new file mode 100644
index 0000000000..d247a8fef5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_failed.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_notrun.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_notrun.gif
new file mode 100644
index 0000000000..5198579fd6
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_notrun.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_passed.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_passed.gif
new file mode 100644
index 0000000000..e3db1eb3c8
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_passed.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_run.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_run.gif
new file mode 100644
index 0000000000..0db16d92b5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/obj16/tsuite_run.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/aborted_counter.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/aborted_counter.gif
new file mode 100644
index 0000000000..8f12861d51
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/aborted_counter.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/failed_counter.gif b/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/failed_counter.gif
new file mode 100644
index 0000000000..c112416d5a
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/icons/ovr16/failed_counter.gif
Binary files differ
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/plugin.properties b/testsrunner/org.eclipse.cdt.testsrunner/plugin.properties
new file mode 100644
index 0000000000..d968486593
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/plugin.properties
@@ -0,0 +1,30 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+pluginName=C/C++ Development Tools Tests Running Support
+providerName=Eclipse CDT
+
+MainLaunchTab.name=Main
+ArgumentsLaunchTab.name=Arguments
+CTestingLaunchTab.name=C/C++ Testing
+EnvironmentLaunchTab.name=Environment
+DebuggerLaunchTab.name=Debugger
+SourceLookupLaunchTab.name=Source
+CommonLaunchTab.name=Common
+RefreshLaunchTab.name=Refresh
+
+ResultsView.name=C/C++ Unit
+
+CPPUnitLaunchConfigurationType.name=C/C++ Unit
+
+CPPUnitLaunch.name=Standard C/C++ Tests Launcher
+CPPUnitLaunch.description=Run C/C++ tests optionally under control of the standard debugger.
+CPPUnitLaunchDSF.name=GDB (DSF) C/C++ Tests Launcher
+CPPUnitLaunchDSF.description=Run C/C++ Tests under control of GDB debugger integrated using the Debugger Services Framework (DSF).
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/plugin.xml b/testsrunner/org.eclipse.cdt.testsrunner/plugin.xml
new file mode 100644
index 0000000000..13d2905911
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/plugin.xml
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+ <extension-point id="TestsRunner" name="Provides additional tests runner" schema="schema/TestsRunner.exsd"/>
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ category="org.eclipse.cdt.ui.views"
+ class="org.eclipse.cdt.testsrunner.internal.ui.view.ResultsView"
+ icon="$nl$/icons/eview16/cppunit.gif"
+ id="org.eclipse.cdt.testsrunner.resultsview"
+ name="%ResultsView.name"
+ restorable="true">
+ </view>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.launchConfigurationTypes">
+ <launchConfigurationType
+ id="org.eclipse.cdt.testsrunner.launch.CTestsRunner"
+ name="%CPPUnitLaunchConfigurationType.name"
+ public="true">
+ </launchConfigurationType>
+ </extension>
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+ <launchConfigurationTabGroup
+ class="org.eclipse.cdt.testsrunner.internal.ui.launcher.EmptyConfigurationTabGroup"
+ id="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ type="org.eclipse.cdt.testsrunner.launch.CTestsRunner">
+ <launchMode mode="run"/>
+ </launchConfigurationTabGroup>
+ <launchConfigurationTabGroup
+ class="org.eclipse.cdt.testsrunner.internal.ui.launcher.EmptyConfigurationTabGroup"
+ id="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ type="org.eclipse.cdt.testsrunner.launch.CTestsRunner">
+ <launchMode mode="debug"/>
+ </launchConfigurationTabGroup>
+ </extension>
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+ <launchConfigurationTypeImage
+ configTypeID="org.eclipse.cdt.testsrunner.launch.CTestsRunner"
+ icon="$nl$/icons/eview16/cppunit.gif"
+ id="org.eclipse.cdt.testsrunner.launch.CTestsRunner.image">
+ </launchConfigurationTypeImage>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.core.launchDelegates">
+ <launchDelegate
+ id="org.eclipse.cdt.testsrunner.launch.runTests"
+ type="org.eclipse.cdt.testsrunner.launch.CTestsRunner"
+ delegate="org.eclipse.cdt.testsrunner.internal.launcher.CdiRunTestsLaunchDelegate"
+ modes="run,debug"
+ name="%CPPUnitLaunch.name"
+ delegateDescription="%CPPUnitLaunch.description"
+ sourceLocatorId="org.eclipse.cdt.debug.core.sourceLocator"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer">
+ </launchDelegate>
+ <launchDelegate
+ id="org.eclipse.cdt.testsrunner.launch.dsf.runTests"
+ type="org.eclipse.cdt.testsrunner.launch.CTestsRunner"
+ delegate="org.eclipse.cdt.testsrunner.internal.launcher.DsfGdbRunTestsLaunchDelegate"
+ modes="debug"
+ name="%CPPUnitLaunchDSF.name"
+ delegateDescription="%CPPUnitLaunchDSF.description"
+ sourceLocatorId="org.eclipse.cdt.debug.core.sourceLocator"
+ sourcePathComputerId="org.eclipse.cdt.debug.core.sourcePathComputer">
+ </launchDelegate>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabs">
+ <!-- Tests run tabs-->
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.mainTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%MainLaunchTab.name"
+ class="org.eclipse.cdt.launch.ui.CMainTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.argumentsTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%ArgumentsLaunchTab.name"
+ class="org.eclipse.cdt.launch.ui.CArgumentsTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.mainTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.testingTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%CTestingLaunchTab.name"
+ class="org.eclipse.cdt.testsrunner.internal.ui.launcher.CTestingTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.argumentsTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.environmentTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%EnvironmentLaunchTab.name"
+ class="org.eclipse.debug.ui.EnvironmentTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.testsrunner.testingTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.sourceLookupTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%SourceLookupLaunchTab.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.environmentTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.launch.commonTab"
+ group="org.eclipse.cdt.testsrunner.launch.runTestsTabGroup"
+ name="%CommonLaunchTab.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.debug.ui.sourceLookupTab"/>
+ </tab>
+
+ <!-- Tests debug (CDI) tabs-->
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.mainTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%MainLaunchTab.name"
+ class="org.eclipse.cdt.launch.ui.CMainTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.argumentsTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%ArgumentsLaunchTab.name"
+ class="org.eclipse.cdt.launch.ui.CArgumentsTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.mainTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.testingTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%CTestingLaunchTab.name"
+ class="org.eclipse.cdt.testsrunner.internal.ui.launcher.CTestingTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.argumentsTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.environmentTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%EnvironmentLaunchTab.name"
+ class="org.eclipse.debug.ui.EnvironmentTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.testsrunner.testingTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.debuggerTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%DebuggerLaunchTab.name"
+ class="org.eclipse.cdt.launch.ui.ApplicationCDebuggerTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.debug.ui.environmentTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.sourceLookupTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%SourceLookupLaunchTab.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.cdt.cdi.launch.debuggerTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.refreshTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%RefreshLaunchTab.name"
+ class="org.eclipse.debug.ui.RefreshTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests" />
+ <placement after="org.eclipse.debug.ui.sourceLookupTab" />
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.debug.commonTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%CommonLaunchTab.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.runTests"/>
+ <placement after="org.eclipse.debug.ui.refreshTab"/>
+ </tab>
+
+ <!-- Tests debug (DSF) tabs-->
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.mainTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%MainLaunchTab.name"
+ class="org.eclipse.cdt.dsf.gdb.internal.ui.launching.CMainTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.argumentsTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%ArgumentsLaunchTab.name"
+ class="org.eclipse.cdt.dsf.gdb.internal.ui.launching.CArgumentsTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.cdt.dsf.gdb.launch.mainTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.testingTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%CTestingLaunchTab.name"
+ class="org.eclipse.cdt.testsrunner.internal.ui.launcher.CTestingTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.cdt.dsf.gdb.launch.argumentsTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.environmentTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%EnvironmentLaunchTab.name"
+ class="org.eclipse.debug.ui.EnvironmentTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.cdt.testsrunner.testingTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.debuggerTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%DebuggerLaunchTab.name"
+ class="org.eclipse.cdt.dsf.gdb.internal.ui.launching.LocalApplicationCDebuggerTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.debug.ui.environmentTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.sourceLookupTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%SourceLookupLaunchTab.name"
+ class="org.eclipse.debug.ui.sourcelookup.SourceLookupTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.cdt.dsf.gdb.launch.debuggerTab"/>
+ </tab>
+ <tab
+ id="org.eclipse.cdt.testsrunner.dsf.gdb.commonTab"
+ group="org.eclipse.cdt.testsrunner.launch.debugTestsLaunchTabGroup"
+ name="%CommonLaunchTab.name"
+ class="org.eclipse.debug.ui.CommonTab">
+ <associatedDelegate delegate="org.eclipse.cdt.testsrunner.launch.dsf.runTests"/>
+ <placement after="org.eclipse.debug.ui.sourceLookupTab"/>
+ </tab>
+
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.core.processFactories">
+ <processFactory
+ class="org.eclipse.cdt.testsrunner.internal.launcher.TestingProcessFactory"
+ id="org.eclipse.cdt.testsrunner.TestingProcessFactory">
+ </processFactory>
+ </extension>
+
+</plugin>
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/pom.xml b/testsrunner/org.eclipse.cdt.testsrunner/pom.xml
new file mode 100644
index 0000000000..f3961df242
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/pom.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.cdt</groupId>
+ <artifactId>cdt-parent</artifactId>
+ <version>8.1.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <version>7.0.0-SNAPSHOT</version>
+ <artifactId>org.eclipse.cdt.testsrunner</artifactId>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/schema/TestsRunner.exsd b/testsrunner/org.eclipse.cdt.testsrunner/schema/TestsRunner.exsd
new file mode 100644
index 0000000000..ca160a18d0
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/schema/TestsRunner.exsd
@@ -0,0 +1,178 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.cdt.testsrunner" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.cdt.testsrunner" id="TestsRunnerProvider" name="Tests Runner Provider"/>
+ </appInfo>
+ <documentation>
+ Defines an extestion point for the Tests Runner provider plug-in.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appInfo>
+ <meta.element />
+ </appInfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="runner"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="runner">
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="1">
+ <element ref="features"/>
+ </sequence>
+ <attribute name="name" type="string" use="required">
+ <annotation>
+ <documentation>
+ Name of the tests runner that will be shown to user.
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ Class implementing test runner functionality (org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProvider)
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.cdt.testsrunner.launcher.ITestsRunner"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="description" type="string">
+ <annotation>
+ <documentation>
+ Short description of the tests runner that will be shown to user
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ Internal unique name of the tests runner
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="features">
+ <complexType>
+ <attribute name="multipleTestFilter" type="boolean">
+ <annotation>
+ <documentation>
+ Should be True if Tests Runner can generate a multiple tests filter for single test module launch. In this case rerun of multiple tests or test suites will be available and a few test items may be passed to configureLaunchParameters(). It is False by default.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="testingTimeMeasurement" type="boolean">
+ <annotation>
+ <documentation>
+ Defines whether tests execution time are provided by testing framework. Otherwise turns on time measurement in Tests Runner Core. It is less accurate, but useful if testing framework does not provide time measurement.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="dataStream">
+ <annotation>
+ <documentation>
+ Defines what stream (output or error) should be used to read the data from the testing process. Output is used by default.
+ </documentation>
+ </annotation>
+ <simpleType>
+ <restriction base="string">
+ <enumeration value="error">
+ </enumeration>
+ <enumeration value="output">
+ </enumeration>
+ </restriction>
+ </simpleType>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiinfo"/>
+ </appInfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2011 Anton Gorenkov.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/TestsRunnerPlugin.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/TestsRunnerPlugin.java
new file mode 100644
index 0000000000..0e5ee47fbb
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/TestsRunnerPlugin.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal;
+
+import java.net.URL;
+import java.util.HashSet;
+
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProvidersManager;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerConstants;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchDelegate;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TestsRunnerPlugin extends AbstractUIPlugin {
+
+ /** The plug-in ID. */
+ private static final String PLUGIN_ID = "org.eclipse.cdt.testsrunner"; //$NON-NLS-1$
+
+ /** The path to the plugin icons */
+ private static final IPath ICONS_PATH = new Path("$nl$/icons"); //$NON-NLS-1$
+
+ /** Plug-in instance. */
+ private static TestsRunnerPlugin plugin;
+
+ private TestsRunnerProvidersManager testsRunnerProvidersManager = new TestsRunnerProvidersManager();
+ private TestingSessionsManager testingSessionsManager = new TestingSessionsManager(testsRunnerProvidersManager);
+
+
+ public TestsRunnerPlugin() {
+ super();
+ plugin = this;
+ }
+
+ /**
+ * Returns the Tests Runner Plug-in instance
+ *
+ * @return the plug-in instance
+ */
+ public static TestsRunnerPlugin getDefault() {
+ return plugin;
+ }
+
+ /** Convenience method which returns the unique identifier of this plug-in. */
+ public static String getUniqueIdentifier() {
+ return PLUGIN_ID;
+ }
+
+ /**
+ * Logs the specified status with this plug-in's log.
+ *
+ * @param status status to log
+ */
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+ /**
+ * Logs an internal error with the specified message.
+ *
+ * @param message the error message to log
+ */
+ public static void logErrorMessage(String message) {
+ log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, message, null));
+ }
+
+ /**
+ * Logs an internal error with the specified throwable
+ *
+ * @param e the exception to be logged
+ */
+ public static void log(Throwable e) {
+ log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, e.getMessage(), e));
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+
+ setDefaultLaunchDelegates();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ }
+
+ /**
+ * Access the plugin's Testing Sessions Manager instance.
+ *
+ * @return sessions manager
+ */
+ public TestingSessionsManager getTestingSessionsManager() {
+ return testingSessionsManager;
+ }
+
+ /**
+ * Access the plugin's Test Runners manager instance.
+ *
+ * @return tests runners manager
+ */
+ public TestsRunnerProvidersManager getTestsRunnerProvidersManager() {
+ return testsRunnerProvidersManager;
+ }
+
+ /**
+ * Returns the descriptor for image with <code>relativePath</code> path.
+ *
+ * @param relativePath path relative to <code>ICONS_PATH</code>
+ * @return image descriptor
+ */
+ static public ImageDescriptor getImageDescriptor(String relativePath) {
+ return getDefault().getImageDescriptorImpl(relativePath);
+ }
+
+ /**
+ * Returns the descriptor for image with <code>relativePath</code> path.
+ *
+ * @param relativePath path relative to <code>ICONS_PATH</code>
+ * @return image descriptor
+ */
+ private ImageDescriptor getImageDescriptorImpl(String relativePath) {
+ IPath path = ICONS_PATH.append(relativePath);
+ return createImageDescriptor(getDefault().getBundle(), path, true);
+ }
+
+ /**
+ * Returns the image with the specified path.
+ *
+ * @param path path
+ * @return image image
+ */
+ public static Image createAutoImage(String path) {
+ return getDefault().createAutoImageImpl(path);
+ }
+
+ /**
+ * Returns the image with the specified path.
+ *
+ * @param path path
+ * @return image image
+ */
+ private Image createAutoImageImpl(String path) {
+ Image image = getImageRegistry().get(path);
+ if (image == null) {
+ image = getImageDescriptor(path).createImage();
+ getImageRegistry().put(path, image);
+ }
+ return image;
+ }
+
+ /**
+ * Creates an image descriptor for the given path in a bundle. The path can
+ * contain variables like $NL$. If no image could be found,
+ * <code>useMissingImageDescriptor</code> decides if either the 'missing
+ * image descriptor' is returned or <code>null</code>.
+ *
+ * @param bundle a bundle
+ * @param path path in the bundle
+ * @param useMissingImageDescriptor if <code>true</code>, returns the shared
+ * image descriptor for a missing image. Otherwise, returns
+ * <code>null</code> if the image could not be found
+ * @return an {@link ImageDescriptor}, or <code>null</code> iff there's no
+ * image at the given location and <code>useMissingImageDescriptor</code> is
+ * <code>true</code>
+ */
+ private ImageDescriptor createImageDescriptor(Bundle bundle, IPath path, boolean useMissingImageDescriptor) {
+ URL url = FileLocator.find(bundle, path, null);
+ if (url != null) {
+ return ImageDescriptor.createFromURL(url);
+ }
+ if (useMissingImageDescriptor) {
+ return ImageDescriptor.getMissingImageDescriptor();
+ }
+ return null;
+ }
+
+ /**
+ * Setup the launch delegate with id <code>delegateId</code> as default for
+ * launch configuration type <code>cfgType</code> for <code>mode</code>
+ * launch mode.
+ *
+ * @param cfgType launch configuration type
+ * @param delegateId unique identifier of the launch delegate
+ * @param mode launch mode
+ */
+ private void setDefaultLaunchDelegate(ILaunchConfigurationType cfgType, String delegateId, String mode) {
+ HashSet<String> modes = new HashSet<String>();
+ modes.add(mode);
+ try {
+ if (cfgType.getPreferredDelegate(modes) == null) {
+ ILaunchDelegate[] delegates = cfgType.getDelegates(modes);
+ for (ILaunchDelegate delegate : delegates) {
+ if (delegateId.equals(delegate.getId())) {
+ cfgType.setPreferredDelegate(modes, delegate);
+ break;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ log(e);
+ }
+ }
+
+ /**
+ * Sets up the default launch delegates for the Tests Runner's launch configuration type.
+ */
+ private void setDefaultLaunchDelegates() {
+ ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType configurationType = launchMgr.getLaunchConfigurationType(ITestsRunnerConstants.LAUNCH_CONFIGURATION_TYPE_ID);
+
+ setDefaultLaunchDelegate(configurationType, ITestsRunnerConstants.PREFERRED_DEBUG_TESTS_LAUNCH_DELEGATE, ILaunchManager.DEBUG_MODE);
+ setDefaultLaunchDelegate(configurationType, ITestsRunnerConstants.PREFERRED_RUN_TESTS_LAUNCH_DELEGATE, ILaunchManager.RUN_MODE);
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/CdiRunTestsLaunchDelegate.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/CdiRunTestsLaunchDelegate.java
new file mode 100644
index 0000000000..c0bef98204
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/CdiRunTestsLaunchDelegate.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import org.eclipse.cdt.testsrunner.launcher.BaseTestsLaunchDelegate;
+
+
+/**
+ * Launch delegate implementation that redirects its queries to CDI.
+ */
+public class CdiRunTestsLaunchDelegate extends BaseTestsLaunchDelegate {
+
+ @Override
+ public String getPreferredDelegateId() {
+ return "org.eclipse.cdt.cdi.launch.localCLaunch"; //$NON-NLS-1$
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/DsfGdbRunTestsLaunchDelegate.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/DsfGdbRunTestsLaunchDelegate.java
new file mode 100644
index 0000000000..7f68f38d04
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/DsfGdbRunTestsLaunchDelegate.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import org.eclipse.cdt.testsrunner.launcher.BaseTestsLaunchDelegate;
+
+
+/**
+ * Launch delegate implementation that redirects its queries to DSF.
+ */
+public class DsfGdbRunTestsLaunchDelegate extends BaseTestsLaunchDelegate {
+
+ @Override
+ public String getPreferredDelegateId() {
+ return "org.eclipse.cdt.dsf.gdb.launch.localCLaunch"; //$NON-NLS-1$
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ITestsLaunchConfigurationConstants.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ITestsLaunchConfigurationConstants.java
new file mode 100644
index 0000000000..fa08017b1b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ITestsLaunchConfigurationConstants.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+/**
+ * Constants used for attributes in CDT Unit Testing Support launch
+ * configurations.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface ITestsLaunchConfigurationConstants {
+
+ public static final String CDT_TESTS_LAUNCH_ID = "org.eclipse.cdt.testsrunner.launch"; //$NON-NLS-1$
+
+ /**
+ * Launch configuration attribute key. The value is a string specifying
+ * tests runner string unique identifier
+ */
+ public static final String ATTR_TESTS_RUNNER = CDT_TESTS_LAUNCH_ID + ".TESTS_RUNNER"; //$NON-NLS-1$
+
+ /**
+ * Launch configuration attribute key. The value is a string list specifying
+ * tests paths to run
+ */
+ public static final String ATTR_TESTS_FILTER = CDT_TESTS_LAUNCH_ID + ".TESTS_FILTER"; //$NON-NLS-1$
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.java
new file mode 100644
index 0000000000..2b66e11909
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import org.eclipse.osgi.util.NLS;
+
+public class LauncherMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.internal.launcher.LauncherMessages"; //$NON-NLS-1$
+ public static String BaseTestsLaunchDelegate_invalid_tests_runner;
+ public static String BaseTestsLaunchDelegate_tests_runner_load_failed;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, LauncherMessages.class);
+ }
+
+ private LauncherMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.properties
new file mode 100644
index 0000000000..2208efc2bc
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/LauncherMessages.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+BaseTestsLaunchDelegate_invalid_tests_runner=Tests Runner is not specified or invalid
+BaseTestsLaunchDelegate_tests_runner_load_failed=Tests Runner cannot be instantiated
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ProcessWrapper.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ProcessWrapper.java
new file mode 100644
index 0000000000..5a99ec4bd2
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/ProcessWrapper.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Wraps the underline process and prevent accessing to its output or error stream.
+ * This wrapping is necessary to prevent handling the test module output by Console
+ * because we want to handle it here.
+ *
+ */
+class ProcessWrapper extends Process {
+
+ /** The real underlying process. */
+ private Process wrappedProcess;
+
+ /** The flag shows whether input stream should be replaced with empty dummy. */
+ private boolean hideInputStream;
+
+ /** The flag shows whether error stream should be replaced with empty dummy. */
+ private boolean hideErrorStream;
+
+
+ /** Buffer for empty dummy stream. */
+ private byte buffer[] = new byte[0];
+
+ /** Empty dummy stream. */
+ private InputStream emptyInputStream = new ByteArrayInputStream(buffer);
+
+ /**
+ * The synchronization event: before it happens <code>waitFor()</code> will
+ * not be called on underlying process object. See also the comments in
+ * <code>waitFor()</code>.
+ */
+ private Object waitForSync = new Object();
+
+ /**
+ * Flag that shows that process output was not processed yet so the IO
+ * streams could not be closed yet.
+ */
+ private boolean streamsClosingIsAllowed = false;
+
+
+ /**
+ * The constructor
+ *
+ * @param wrappedProcess underlying process
+ * @param hideInputStream process input stream should be hidden
+ * @param hideErrorStream process error stream should be hidden
+ */
+ public ProcessWrapper(Process wrappedProcess, boolean hideInputStream, boolean hideErrorStream) {
+ this.wrappedProcess = wrappedProcess;
+ this.hideInputStream = hideInputStream;
+ this.hideErrorStream = hideErrorStream;
+ }
+
+ @Override
+ public void destroy() {
+ wrappedProcess.destroy();
+ }
+
+ @Override
+ public int exitValue() {
+ return wrappedProcess.exitValue();
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return hideErrorStream ? emptyInputStream : wrappedProcess.getErrorStream();
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return hideInputStream ? emptyInputStream : wrappedProcess.getInputStream();
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return wrappedProcess.getOutputStream();
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ // NOTE: implementation of waitFor() in Spawner will close streams after process is terminated,
+ // so we should wait with this operation until we process all stream data
+ synchronized (waitForSync) {
+ if (!streamsClosingIsAllowed) {
+ waitForSync.wait();
+ }
+ }
+ return wrappedProcess.waitFor();
+ }
+
+ /**
+ * Sets up the flag the allows IO streams closing.
+ */
+ public void allowStreamsClosing() {
+ synchronized (waitForSync) {
+ streamsClosingIsAllowed = true;
+ waitForSync.notifyAll();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestingProcessFactory.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestingProcessFactory.java
new file mode 100644
index 0000000000..ce498d5bf2
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestingProcessFactory.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
+import org.eclipse.cdt.dsf.gdb.launching.GDBProcess;
+import org.eclipse.cdt.dsf.gdb.launching.InferiorRuntimeProcess;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSession;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProviderInfo;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.IProcessFactory;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.RuntimeProcess;
+
+/**
+ * Custom testing process factory allows to handle the output stream of the
+ * testing process and prevent it from output to Console.
+ */
+public class TestingProcessFactory implements IProcessFactory {
+
+ /**
+ * Runs data processing for the testing process and close IO stream when it
+ * is done.
+ */
+ private class TestingSessionRunner implements Runnable {
+
+ private TestingSession testingSession;
+ private InputStream iStream;
+ private ProcessWrapper processWrapper;
+
+ TestingSessionRunner(TestingSession testingSession, InputStream iStream, ProcessWrapper processWrapper) {
+ this.testingSession = testingSession;
+ this.iStream = iStream;
+ this.processWrapper = processWrapper;
+ }
+
+ @Override
+ public void run() {
+ try {
+ testingSession.run(iStream);
+ }
+ finally {
+ // Streams should be closed anyway to avoid testing process hang up
+ processWrapper.allowStreamsClosing();
+ }
+ }
+ }
+
+ /**
+ * Creates a wrapper for the specified process to handle its input or error
+ * stream.
+ *
+ * @param launch launch
+ * @param process process to wrap
+ * @return wrapped process
+ * @throws CoreException
+ */
+ private Process wrapProcess(ILaunch launch, Process process) throws CoreException {
+ TestingSession testingSession = TestsRunnerPlugin.getDefault().getTestingSessionsManager().newSession(launch);
+ ITestsRunnerProviderInfo testsRunnerProvider = testingSession.getTestsRunnerProviderInfo();
+ InputStream iStream =
+ testsRunnerProvider.isOutputStreamRequired() ? process.getInputStream() :
+ testsRunnerProvider.isErrorStreamRequired() ? process.getErrorStream() : null;
+ ProcessWrapper processWrapper = new ProcessWrapper(process, testsRunnerProvider.isOutputStreamRequired(), testsRunnerProvider.isErrorStreamRequired());
+ Thread t = new Thread(new TestingSessionRunner(testingSession, iStream, processWrapper));
+ t.start();
+ return processWrapper;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public IProcess newProcess(ILaunch launch, Process process, String label, Map attributes) {
+
+ try {
+ // Mimic the behavior of DSF GDBProcessFactory.
+ if (attributes != null) {
+ Object processTypeCreationAttrValue = attributes.get(IGdbDebugConstants.PROCESS_TYPE_CREATION_ATTR);
+ if (IGdbDebugConstants.GDB_PROCESS_CREATION_VALUE.equals(processTypeCreationAttrValue)) {
+ return new GDBProcess(launch, process, label, attributes);
+ }
+
+ if (IGdbDebugConstants.INFERIOR_PROCESS_CREATION_VALUE.equals(processTypeCreationAttrValue)) {
+ return new InferiorRuntimeProcess(launch, wrapProcess(launch, process), label, attributes);
+ }
+
+ // Probably, it is CDI creating a new inferior process
+ } else {
+ return new RuntimeProcess(launch, wrapProcess(launch, process), label, attributes);
+ }
+
+ } catch (CoreException e) {
+ TestsRunnerPlugin.log(e);
+ }
+
+ return null;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProviderInfo.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProviderInfo.java
new file mode 100644
index 0000000000..5f5927b3c9
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProviderInfo.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProvider;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProviderInfo;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * Provides access to the information about the Tests Runner provider plug-in
+ * (id, name, description, supported features set). Also provides the access to
+ * <code>ITestsRunnerProvider</code> interface (the main interface of Tests Runner
+ * provider plug-in).
+ */
+public class TestsRunnerProviderInfo implements ITestsRunnerProviderInfo {
+
+ private static final String TESTS_RUNNER_FEATURES_ELEMENT = "features"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_FEATURE_MULTIPLE_TEST_FILTER_ATTRIBUTE = "multipleTestFilter"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_FEATURE_TESTING_TIME_MEASUREMENT_ATTRIBUTE = "testingTimeMeasurement"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_FEATURE_DATA_STREAM_ATTRIBUTE = "dataStream"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_ID_ATTRIBUTE = "id"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$
+ private static final String TESTS_RUNNER_ERROR_STREAM_VALUE = "error"; //$NON-NLS-1$
+
+ /** Configuration element of the Tests Runner provider plug-ins extension point. */
+ private IConfigurationElement element;
+
+ /**
+ * The constructor.
+ *
+ * @param element configuration element of the Tests Runner provider plug-ins extension point
+ */
+ public TestsRunnerProviderInfo(IConfigurationElement element) {
+ this.element = element;
+ }
+
+ @Override
+ public String getName() {
+ return element.getAttribute(TESTS_RUNNER_NAME_ATTRIBUTE);
+ }
+
+ @Override
+ public String getId() {
+ return element.getAttribute(TESTS_RUNNER_ID_ATTRIBUTE);
+ }
+
+ @Override
+ public String getDescription() {
+ String result = element.getAttribute(TESTS_RUNNER_DESCRIPTION_ATTRIBUTE);
+ return result == null ? "" : result; //$NON-NLS-1$
+ }
+
+ /**
+ * Instantiates Tests Runner provider plug-in and return its main interface.
+ *
+ * @note Instantiated Tests Runner provider plug-in objects are not cached
+ * and are instantiated as much times as
+ * <code>instantiateTestsRunnerProvider()</code> is called.
+ *
+ * @return Tests Runner provider plug-in main interface
+ */
+ public ITestsRunnerProvider instantiateTestsRunnerProvider() {
+ try {
+ Object object = element.createExecutableExtension(TESTS_RUNNER_CLASS_ATTRIBUTE);
+ if (object instanceof ITestsRunnerProvider) {
+ return (ITestsRunnerProvider)object;
+ }
+ } catch (CoreException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ return null;
+ }
+
+ /**
+ * Provides an access to the 'features' node of Tests Runner provider
+ * plug-in configuration element.
+ *
+ * @return 'features' configuration element
+ */
+ private IConfigurationElement getFeatures() {
+ IConfigurationElement[] featuresElements = element.getChildren(TESTS_RUNNER_FEATURES_ELEMENT);
+ if (featuresElements.length == 1) {
+ return featuresElements[0];
+ }
+ return null;
+ }
+
+ /**
+ * Provides an access to the value of the feature with specified name.
+ *
+ * @param featureName
+ * @return feature value or null if there is no features described or there
+ * is no feature with such name
+ */
+ private String getFeatureAttributeValue(String featureName) {
+ IConfigurationElement features = getFeatures();
+ if (features != null) {
+ return features.getAttribute(featureName);
+ }
+ return null;
+ }
+
+ /**
+ * Provides an access to the boolean value of the feature with the specified
+ * name. If the feature with such name cannot be accessed or it contains
+ * invalid boolean value, the default value will be returned.
+ *
+ * @param featureName
+ * @param defaultValue
+ * @return feature value or null if there is no features described or there
+ * is no feature with such name
+ */
+ private boolean getBooleanFeatureValue(String featureName, boolean defaultValue) {
+ String attrValue = getFeatureAttributeValue(featureName);
+ if (attrValue != null) {
+ return Boolean.parseBoolean(attrValue);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public boolean isAllowedMultipleTestFilter() {
+ return getBooleanFeatureValue(TESTS_RUNNER_FEATURE_MULTIPLE_TEST_FILTER_ATTRIBUTE, false);
+ }
+
+ /**
+ * Returns whether test execution time measurement should be performed by
+ * the Tests Runner Plug-in.
+ *
+ * @note It should be used only if testing framework does not provide
+ * execution time measurement, cause measurement by Tests Runner Plug-in is
+ * not very precise (it also takes into account output processing & internal
+ * model building time).
+ *
+ * @return whether testing time measurement should be done by Tests Runner
+ * Plug-in
+ */
+ public boolean isAllowedTestingTimeMeasurement() {
+ return getBooleanFeatureValue(TESTS_RUNNER_FEATURE_TESTING_TIME_MEASUREMENT_ATTRIBUTE, false);
+ }
+
+ @Override
+ public boolean isOutputStreamRequired() {
+ return !isErrorStreamRequired();
+ }
+
+ @Override
+ public boolean isErrorStreamRequired() {
+ String attrValue = getFeatureAttributeValue(TESTS_RUNNER_FEATURE_DATA_STREAM_ATTRIBUTE);
+ if (attrValue != null) {
+ return attrValue.equals(TESTS_RUNNER_ERROR_STREAM_VALUE);
+ }
+ return false;
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProvidersManager.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProvidersManager.java
new file mode 100644
index 0000000000..39f216ab35
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/launcher/TestsRunnerProvidersManager.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.launcher;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+/**
+ * Collects the data from the Tests Runner provider plug-in extension points and
+ * provides the convenient access to it.
+ */
+public class TestsRunnerProvidersManager {
+
+ /** Tests Runner Plug-ins extension point ID. */
+ private static final String TESTS_RUNNER_EXTENSION_POINT_ID = "org.eclipse.cdt.testsrunner.TestsRunner"; //$NON-NLS-1$
+
+ /** Tests Runner Plug-ins information collection. */
+ private TestsRunnerProviderInfo[] testsRunnerProviders = null;
+
+
+ /**
+ * Provides access to information about all registered Tests Runner
+ * Plug-ins.
+ *
+ * @return array of tests runner plug-ins descriptors
+ */
+ public TestsRunnerProviderInfo[] getTestsRunnersProviderInfo() {
+ if (testsRunnerProviders == null) {
+ // Initialize tests runners info
+ List<TestsRunnerProviderInfo> testsRunnerProvidersList = new ArrayList<TestsRunnerProviderInfo>();
+ for (IConfigurationElement element : Platform.getExtensionRegistry().getConfigurationElementsFor(TESTS_RUNNER_EXTENSION_POINT_ID)) {
+ testsRunnerProvidersList.add(new TestsRunnerProviderInfo(element));
+ }
+ testsRunnerProviders = testsRunnerProvidersList.toArray(new TestsRunnerProviderInfo[testsRunnerProvidersList.size()]);
+ }
+ return testsRunnerProviders;
+ }
+
+ /**
+ * Provides access to information about Tests Runner Plug-in referred in the
+ * specified launch configuration.
+ *
+ * @return tests runner plug-in descriptor
+ */
+ public TestsRunnerProviderInfo getTestsRunnerProviderInfo(ILaunchConfiguration launchConf) throws CoreException {
+ String testsRunnerId = launchConf.getAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_RUNNER, (String)null);
+ return getTestsRunnerProviderInfo(testsRunnerId);
+ }
+
+ /**
+ * Provides access to information about Tests Runner Plug-in with the
+ * specified ID.
+ *
+ * @return tests runner plug-in descriptor
+ */
+ private TestsRunnerProviderInfo getTestsRunnerProviderInfo(String testsRunnerProviderId) {
+ if (testsRunnerProviderId != null) {
+ for (TestsRunnerProviderInfo testsRunnerProvider : getTestsRunnersProviderInfo()) {
+ if (testsRunnerProvider.getId().equals(testsRunnerProviderId)) {
+ return testsRunnerProvider;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ITestingSessionsManagerListener.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ITestingSessionsManagerListener.java
new file mode 100644
index 0000000000..578ed7b2f0
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ITestingSessionsManagerListener.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+
+/**
+ * Testing sessions manager listener is notified of testing sessions management.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestingSessionsManagerListener {
+
+ /**
+ * Notifies the listener that the specified testing session was activated.
+ *
+ * @param testingSession the activated testing session
+ */
+ void sessionActivated(ITestingSession testingSession);
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.java
new file mode 100644
index 0000000000..b690f1cfa3
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ModelMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.internal.model.ModelMessages"; //$NON-NLS-1$
+ public static String TestingSession_finished_status;
+ public static String TestingSession_name_format;
+ public static String TestingSession_starting_status;
+ public static String TestingSession_stopped_status;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, ModelMessages.class);
+ }
+
+ private ModelMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.properties
new file mode 100644
index 0000000000..c57df6a158
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/ModelMessages.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+TestingSession_name_format={0} ({1})
+TestingSession_finished_status=Finished after {0} seconds
+TestingSession_starting_status=Starting...
+TestingSession_stopped_status=Testing was stopped by user
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestCase.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestCase.java
new file mode 100644
index 0000000000..84e9db50d1
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestCase.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+
+/**
+ * Represents the test case (test) of the test hierarchy.
+ */
+public class TestCase extends TestItem implements ITestCase {
+
+ /** Test case status (failed, passed, ...). */
+ private Status status;
+
+ /** Test case execution time. */
+ private int testingTime;
+
+ /**
+ * The messages that were generated by testing framework during test
+ * running.
+ */
+ private List<TestMessage> testMessages = new ArrayList<TestMessage>();
+
+
+ public TestCase(String name, TestSuite parent) {
+ super(name, parent);
+ reset();
+ }
+
+ @Override
+ public Status getStatus() {
+ return status;
+ }
+
+ @Override
+ public int getTestingTime() {
+ return testingTime;
+ }
+
+ @Override
+ public TestMessage[] getTestMessages() {
+ return testMessages.toArray(new TestMessage[testMessages.size()]);
+ }
+
+ @Override
+ public void visit(IModelVisitor visitor) {
+ visitor.visit(this);
+ for (TestMessage message : testMessages) {
+ message.visit(visitor);
+ }
+ visitor.leave(this);
+ }
+
+ /**
+ * Resets the test case to the default state.
+ */
+ public void reset() {
+ status = Status.Skipped;
+ testingTime = 0;
+ testMessages.clear();
+ }
+
+ /**
+ * Modifies the status of the test case.
+ *
+ * @param status new test status
+ */
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ /**
+ * Modifies the execution time of the test case.
+ *
+ * @param testingTime new test execution time
+ */
+ public void setTestingTime(int testingTime) {
+ this.testingTime = testingTime;
+ }
+
+ /**
+ * Adds a new test message to the test case.
+ *
+ * @param testMessage message
+ */
+ public void addTestMessage(TestMessage testMessage) {
+ testMessages.add(testMessage);
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestItem.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestItem.java
new file mode 100644
index 0000000000..55c775fda5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestItem.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+
+/**
+ * Common implementation for the structural item of test hierarchy (test suite
+ * or test case).
+ */
+public abstract class TestItem implements ITestItem {
+
+ /** Test item has no children by default. */
+ private static final ITestItem[] NO_CHILDREN = new ITestItem[0];
+
+ /** Test item name. */
+ private final String name;
+
+ /** Item parent test suite. May be <code>null</code> for root test suite. */
+ private TestSuite parent;
+
+
+ public TestItem(String name, TestSuite parent) {
+ this.name = name;
+ this.parent = parent;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public TestSuite getParent() {
+ return parent;
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return false;
+ }
+
+ @Override
+ public ITestItem[] getChildren() {
+ return NO_CHILDREN;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestLocation.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestLocation.java
new file mode 100644
index 0000000000..afe8bfaae5
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestLocation.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import org.eclipse.cdt.testsrunner.model.ITestLocation;
+
+/**
+ * Represents the location of the test object.
+ */
+public class TestLocation implements ITestLocation {
+
+ /** Stores the file name in which testing object is located. */
+ private String file;
+
+ /** Stores the line number on which testing object is located. */
+ private int line;
+
+
+ public TestLocation(String file, int line) {
+ this.file = file;
+ this.line = line;
+ }
+
+ @Override
+ public String getFile() {
+ return file;
+ }
+
+ @Override
+ public int getLine() {
+ return line;
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestMessage.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestMessage.java
new file mode 100644
index 0000000000..4a5402f48f
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestMessage.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+
+/**
+ * Represents the message that was produced during the testing process.
+ */
+public class TestMessage implements ITestMessage {
+
+ /** Test message location. */
+ private TestLocation location;
+
+ /** Test message level */
+ private Level level;
+
+ /** Test message text */
+ private String text;
+
+
+ public TestMessage(TestLocation location, Level level, String text) {
+ this.location = location;
+ this.level = level;
+ this.text = text;
+ }
+
+ @Override
+ public TestLocation getLocation() {
+ return location;
+ }
+
+ @Override
+ public Level getLevel() {
+ return level;
+ }
+
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ @Override
+ public void visit(IModelVisitor visitor) {
+ visitor.visit(this);
+ visitor.leave(this);
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestModelManager.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestModelManager.java
new file mode 100644
index 0000000000..0db8d5af98
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestModelManager.java
@@ -0,0 +1,480 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+import org.eclipse.cdt.testsrunner.model.ITestModelAccessor;
+import org.eclipse.cdt.testsrunner.model.ITestModelUpdater;
+import org.eclipse.cdt.testsrunner.model.ITestingSessionListener;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestItem.Status;
+import org.eclipse.cdt.testsrunner.model.ITestMessage.Level;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+
+/**
+ * Manages the testing model (creates, fill and update it) and notifies the
+ * listeners about updates.
+ */
+public class TestModelManager implements ITestModelUpdater, ITestModelAccessor {
+
+ /**
+ * Name of the root test suite.
+ *
+ * @note Root test suite is invisible (only its children are visible), so
+ * the name is not important.
+ */
+ public static final String ROOT_TEST_SUITE_NAME = "<root>"; //$NON-NLS-1$
+
+ /** Stack of the currently entered (and not existed) test suites. */
+ private Stack<TestSuite> testSuitesStack = new Stack<TestSuite>();
+
+ /**
+ * Currently running test case. There are no nested test cases, so the
+ * collection is not necessary.
+ */
+ private TestCase currentTestCase = null;
+
+ /**
+ * The mapping of test suite object to the index on which it was inserted to
+ * the parent.
+ *
+ * @note Test suites presence in this map means that test suite was visited
+ * during the testing process (not visited test suites are removed when
+ * testing is finished cause they are considered as renamed or removed).
+ * @note Test suite insert position is important for insertion algorithm.
+ */
+ private Map<TestItem, Integer> testSuitesIndex = new HashMap<TestItem, Integer>();
+
+ /** Listeners collection. */
+ private List<ITestingSessionListener> listeners = new ArrayList<ITestingSessionListener>();
+
+ /** Flag stores whether test execution time should be measured for the session. */
+ private boolean timeMeasurement = false;
+
+ /** Stores the test case start time or 0 there is no currently running test case. */
+ private long testCaseStartTime = 0;
+
+ /** Instance of the insertion algorithm for test suites. */
+ private TestSuiteInserter testSuiteInserter = new TestSuiteInserter();
+
+ /** Instance of the insertion algorithm for test cases. */
+ private TestCaseInserter testCaseInserter = new TestCaseInserter();
+
+
+ /**
+ * Builds current tests hierarchy from the other one (copies only necessary
+ * information).
+ */
+ private class HierarchyCopier implements IModelVisitor {
+
+ @Override
+ public void visit(ITestSuite testSuite) {
+ // Do not copy root test suite
+ if (testSuite.getParent() != null) {
+ enterTestSuite(testSuite.getName());
+ }
+ }
+
+ @Override
+ public void leave(ITestSuite testSuite) {
+ // Do not copy root test suite
+ if (testSuite.getParent() != null) {
+ exitTestSuite();
+ }
+ }
+
+ @Override
+ public void visit(ITestCase testCase) {
+ enterTestCase(testCase.getName());
+ setTestStatus(TestCase.Status.NotRun);
+ }
+
+ @Override
+ public void leave(ITestCase testCase) {
+ exitTestCase();
+ }
+
+ @Override
+ public void visit(ITestMessage testMessage) {}
+ @Override
+ public void leave(ITestMessage testMessage) {}
+ }
+
+
+ /**
+ * Utility class: generalization of insertion algorithm for test suites and
+ * test cases.
+ *
+ * <p>
+ * The algorithm tries to find the place where the new item should be
+ * inserted at. If the item with such name does not exist in the current top
+ * most test suite, it should be inserted at the current position. If it
+ * already exists (at the next or previous position) then it should be moved
+ * from there to the current one.
+ * </p>
+ *
+ * @param <E> test item type (test suite or test case)
+ */
+ private abstract class TestItemInserter<E extends TestItem> {
+
+ /**
+ * Check whether item has the required type (test suite for suites inserter and
+ * test case for cases one).
+ *
+ * @param item test item to check
+ * @return whether item has the required type
+ */
+ protected abstract boolean isRequiredTestItemType(TestItem item);
+
+ /**
+ * Creates a new item type with the specified name and parent (test
+ * suite for suites inserter and test case for cases one).
+ *
+ * @param name name of the new test item
+ * @param parent parent for the new test item
+ * @return new test item
+ */
+ protected abstract E createTestItem(String name, TestSuite parent);
+
+ /**
+ * Save new test item in the tracking structures (suite in stack, case
+ * in current variable). Additional operations (e.g. listeners
+ * notification about item entering) can be done too.
+ *
+ * @param item new test item
+ */
+ protected abstract void addNewTestItem(E item);
+
+
+ /**
+ * Returns the casted test item if it matches by name and type or
+ * <code>null</code> if it doesn't.
+ *
+ * @param item test item to check
+ * @param name test item name
+ * @return casted test item or null
+ */
+ @SuppressWarnings("unchecked")
+ private E checkTestItem(TestItem item, String name) {
+ return (isRequiredTestItemType(item) && item.getName().equals(name)) ? (E)item : null;
+ }
+
+ /**
+ * Returns the last insert index for the specified test suite. Returns 0
+ * if test suite was not inserted yet.
+ *
+ * @param testSuite test suite to look up
+ * @return insert index or 0
+ */
+ private int getLastInsertIndex(TestSuite testSuite) {
+ Integer intLastInsertIndex = testSuitesIndex.get(testSuite);
+ return intLastInsertIndex != null ? intLastInsertIndex : 0;
+ }
+
+ /**
+ * Notifies the listeners about children update of the specified test
+ * suite.
+ *
+ * @param suite updated test suite
+ */
+ private void notifyAboutChildrenUpdate(ITestSuite suite) {
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.childrenUpdate(suite);
+ }
+ }
+
+ /**
+ * Inserts the test item by the name.
+ *
+ * @param name test item name
+ */
+ public void insert(String name) {
+ TestSuite currTestSuite = testSuitesStack.peek();
+ int lastInsertIndex = getLastInsertIndex(currTestSuite);
+ List<TestItem> children = currTestSuite.getChildrenList();
+ E newTestItem = null;
+
+ // Optimization: Check whether we already pointing to the test suite with required name
+ try {
+ newTestItem = checkTestItem(children.get(lastInsertIndex), name);
+ } catch (IndexOutOfBoundsException e) {}
+ if (newTestItem != null) {
+ testSuitesIndex.put(currTestSuite, lastInsertIndex+1);
+ }
+
+ // Check whether the suite with required name was later in the hierarchy
+ if (newTestItem == null) {
+ for (int childIndex = lastInsertIndex; childIndex < children.size(); childIndex++) {
+ newTestItem = checkTestItem(children.get(childIndex), name);
+ if (newTestItem != null) {
+ testSuitesIndex.put(currTestSuite, childIndex);
+ break;
+ }
+ }
+ }
+
+ // Search in previous
+ if (newTestItem == null) {
+ for (int childIndex = 0; childIndex < lastInsertIndex; childIndex++) {
+ newTestItem = checkTestItem(children.get(childIndex), name);
+ if (newTestItem != null) {
+ children.add(lastInsertIndex, children.remove(childIndex));
+ notifyAboutChildrenUpdate(currTestSuite);
+ break;
+ }
+ }
+ }
+
+ // Add new
+ if (newTestItem == null) {
+ newTestItem = createTestItem(name, currTestSuite);
+ children.add(lastInsertIndex, newTestItem);
+ testSuitesIndex.put(currTestSuite, lastInsertIndex+1);
+ notifyAboutChildrenUpdate(currTestSuite);
+ }
+ if (!testSuitesIndex.containsKey(newTestItem)) {
+ testSuitesIndex.put(newTestItem, 0);
+ }
+ addNewTestItem(newTestItem);
+ }
+
+ }
+
+
+ /**
+ * Utility class: insertion algorithm specialization for test suites.
+ */
+ private class TestSuiteInserter extends TestItemInserter<TestSuite> {
+
+ @Override
+ protected boolean isRequiredTestItemType(TestItem item) {
+ return (item instanceof TestSuite);
+ }
+
+ @Override
+ protected TestSuite createTestItem(String name, TestSuite parent) {
+ return new TestSuite(name, parent);
+ }
+
+ @Override
+ protected void addNewTestItem(TestSuite testSuite) {
+ testSuitesStack.push(testSuite);
+
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.enterTestSuite(testSuite);
+ }
+ }
+ }
+
+
+ /**
+ * Utility class: insertion algorithm specialization for test cases.
+ */
+ private class TestCaseInserter extends TestItemInserter<TestCase> {
+
+ @Override
+ protected boolean isRequiredTestItemType(TestItem item) {
+ return (item instanceof TestCase);
+ }
+
+ @Override
+ protected TestCase createTestItem(String name, TestSuite parent) {
+ return new TestCase(name, parent);
+ }
+
+ @Override
+ protected void addNewTestItem(TestCase testCase) {
+ currentTestCase = testCase;
+ testCase.setStatus(ITestItem.Status.Skipped);
+
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.enterTestCase(testCase);
+ }
+ }
+ }
+
+
+ public TestModelManager(ITestSuite previousTestsHierarchy, boolean timeMeasurement) {
+ testSuitesStack.push(new TestSuite(ROOT_TEST_SUITE_NAME, null));
+ if (previousTestsHierarchy != null) {
+ // Copy tests hierarchy
+ this.timeMeasurement = false;
+ previousTestsHierarchy.visit(new HierarchyCopier());
+ }
+ this.timeMeasurement = timeMeasurement;
+ this.testSuitesIndex.clear();
+ }
+
+ /**
+ * Notifies the listeners that testing was started.
+ */
+ public void testingStarted() {
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.testingStarted();
+ }
+ }
+
+ /**
+ * Removes not visited test items and notifies the listeners that testing
+ * was finished.
+ */
+ public void testingFinished() {
+ // Remove all NotRun-tests and not used test suites (probably they were removed from test module)
+ getRootSuite().visit(new IModelVisitor() {
+
+ @Override
+ public void visit(ITestSuite testSuite) {
+ List<TestItem> suiteChildren = ((TestSuite)testSuite).getChildrenList();
+ for (Iterator<TestItem> it = suiteChildren.iterator(); it.hasNext();) {
+ TestItem item = it.next();
+ if ((item instanceof ITestSuite && !testSuitesIndex.containsKey(item)) ||
+ (item instanceof ITestCase && item.getStatus() == ITestItem.Status.NotRun)) {
+ it.remove();
+ }
+ }
+ }
+
+ @Override
+ public void visit(ITestMessage testMessage) {}
+ @Override
+ public void visit(ITestCase testCase) {}
+ @Override
+ public void leave(ITestSuite testSuite) {}
+ @Override
+ public void leave(ITestCase testCase) {}
+ @Override
+ public void leave(ITestMessage testMessage) {}
+ });
+ testSuitesIndex.clear();
+
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.testingFinished();
+ }
+ }
+
+ @Override
+ public void enterTestSuite(String name) {
+ testSuiteInserter.insert(name);
+ }
+
+ @Override
+ public void exitTestSuite() {
+ exitTestCase();
+ TestSuite testSuite = testSuitesStack.pop();
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.exitTestSuite(testSuite);
+ }
+ }
+
+ @Override
+ public void enterTestCase(String name) {
+ testCaseInserter.insert(name);
+ if (timeMeasurement) {
+ testCaseStartTime = System.currentTimeMillis();
+ }
+ }
+
+
+ @Override
+ public void setTestStatus(Status status) {
+ currentTestCase.setStatus(status);
+ }
+
+ @Override
+ public void setTestingTime(int testingTime) {
+ currentTestCase.setTestingTime(testingTime);
+ }
+
+ @Override
+ public void exitTestCase() {
+ if (currentTestCase != null) {
+ // Set test execution time (if time measurement is turned on)
+ if (timeMeasurement) {
+ int testingTime = (int)(System.currentTimeMillis()-testCaseStartTime);
+ currentTestCase.setTestingTime(currentTestCase.getTestingTime()+testingTime);
+ testCaseStartTime = 0;
+ }
+ TestCase testCase = currentTestCase;
+ currentTestCase = null;
+ // Notify listeners
+ for (ITestingSessionListener listener : getListenersCopy()) {
+ listener.exitTestCase(testCase);
+ }
+ }
+ }
+
+ @Override
+ public void addTestMessage(String file, int line, Level level, String text) {
+ TestLocation location = (file == null || file.isEmpty() || line <= 0) ? null : new TestLocation(file, line);
+ currentTestCase.addTestMessage(new TestMessage(location, level, text));
+ }
+
+ @Override
+ public ITestSuite currentTestSuite() {
+ return testSuitesStack.peek();
+ }
+
+
+ @Override
+ public ITestCase currentTestCase() {
+ return currentTestCase;
+ }
+
+ @Override
+ public boolean isCurrentlyRunning(ITestItem item) {
+ return (item == currentTestCase && item != null) || testSuitesStack.contains(item);
+ }
+
+ @Override
+ public TestSuite getRootSuite() {
+ return testSuitesStack.firstElement();
+ }
+
+ @Override
+ public void addChangesListener(ITestingSessionListener listener) {
+ synchronized (listeners) {
+ listeners.add(listener);
+ }
+ }
+
+ @Override
+ public void removeChangesListener(ITestingSessionListener listener) {
+ synchronized (listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Copies listeners before notifying them to avoid dead-locks.
+ *
+ * @return listeners collection copy
+ */
+ private ITestingSessionListener[] getListenersCopy() {
+ synchronized (listeners) {
+ return listeners.toArray(new ITestingSessionListener[listeners.size()]);
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestSuite.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestSuite.java
new file mode 100644
index 0000000000..188f814270
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestSuite.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+
+/**
+ * Represents the test suite of the tests hierarchy.
+ */
+public class TestSuite extends TestItem implements ITestSuite {
+
+ /**
+ * Stores child test suites and test cases.
+ *
+ * @note Children order is important.
+ */
+ private List<TestItem> children = new ArrayList<TestItem>();
+
+
+ public TestSuite(String name, TestSuite parent) {
+ super(name, parent);
+ }
+
+ @Override
+ public Status getStatus() {
+ Status result = Status.NotRun;
+ for (TestItem testItem : children) {
+ Status childStatus = testItem.getStatus();
+ if (result.compareTo(childStatus) < 0) {
+ result = childStatus;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public int getTestingTime() {
+ int result = 0;
+ for (TestItem testItem : children) {
+ result += testItem.getTestingTime();
+ }
+ return result;
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+ @Override
+ public TestItem[] getChildren() {
+ return children.toArray(new TestItem[children.size()]);
+ }
+
+ @Override
+ public void visit(IModelVisitor visitor) {
+ visitor.visit(this);
+ for (TestItem testItem : children) {
+ testItem.visit(visitor);
+ }
+ visitor.leave(this);
+ }
+
+ /**
+ * Returns list of children for the test suite.
+ *
+ * @return children list
+ */
+ public List<TestItem> getChildrenList() {
+ return children;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSession.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSession.java
new file mode 100644
index 0000000000..f706fa302b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSession.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.EnumMap;
+import java.util.Map;
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProviderInfo;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProvider;
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestItem.Status;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+import org.eclipse.cdt.testsrunner.model.ITestModelAccessor;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.cdt.testsrunner.model.ITestingSessionListener;
+import org.eclipse.cdt.testsrunner.model.TestingException;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+
+/**
+ * Stores the information about tests running.
+ */
+public class TestingSession implements ITestingSession {
+
+ /** Launch object the is connected to the tests running. */
+ private ILaunch launch;
+
+ /** Information about used Tests Runner provider plug-in. */
+ private TestsRunnerProviderInfo testsRunnerProviderInfo;
+
+ /** Main interface to Tests Runner provider plug-in. */
+ private ITestsRunnerProvider testsRunnerProvider;
+
+ /**
+ * Test Model manager that is used to fill and update the model for the
+ * session.
+ */
+ private TestModelManager modelManager;
+
+ /**
+ * Total tests counter. It is -1 by default, that means that total tests
+ * count is not available.
+ *
+ * @see getTotalCounter()
+ */
+ private int totalCounter = -1;
+
+ /** Already finished tests counter. */
+ private int currentCounter = 0;
+
+ /**
+ * Test counters map by test status. They are used to quickly provide simple
+ * statistics without model scanning.
+ *
+ */
+ private Map<ITestItem.Status, Integer> statusCounters = new EnumMap<ITestItem.Status, Integer>(ITestItem.Status.class);
+
+ /**
+ * The flag stores whether the testing session contains errors at the
+ * moment.
+ *
+ * @see hasErrors()
+ */
+ private boolean hasErrors = false;
+
+ /**
+ * The flag stores whether the testing session was stopped by user.
+ *
+ * @see wasStopped()
+ */
+ private boolean wasStopped = false;
+
+ /**
+ * The flag stores whether the testing session has been finished (with or
+ * without errors).
+ */
+ private boolean finished = false;
+
+ /** Stores current status of the testing session. */
+ private String statusMessage = ModelMessages.TestingSession_starting_status;
+
+ /** Stores the time when the testing session was created. */
+ private long startTime;
+
+
+ /**
+ * Counts the number of the test cases in tests hierarchy.
+ */
+ private class TestCasesCounter implements IModelVisitor {
+
+ public int result = 0;
+
+ @Override
+ public void visit(ITestCase testCase) {
+ ++result;
+ }
+
+ @Override
+ public void visit(ITestSuite testSuite) {}
+ @Override
+ public void visit(ITestMessage testMessage) {}
+ @Override
+ public void leave(ITestSuite testSuite) {}
+ @Override
+ public void leave(ITestCase testCase) {}
+ @Override
+ public void leave(ITestMessage testMessage) {}
+ }
+
+
+ /**
+ * The constructor.
+ *
+ * @param launch connected launch object
+ * @param testsRunnerProviderInfo the information about the tests runner
+ * @param previousSession is used to determine total tests count & for tests
+ * hierarchy reusing if it is considered as similar
+ */
+ public TestingSession(ILaunch launch, TestsRunnerProviderInfo testsRunnerProviderInfo, TestingSession previousSession) {
+ this.launch = launch;
+ this.testsRunnerProviderInfo = testsRunnerProviderInfo;
+ this.testsRunnerProvider = testsRunnerProviderInfo.instantiateTestsRunnerProvider();
+ this.startTime = System.currentTimeMillis();
+ // Calculate approximate tests count by the previous similar testing session (if available)
+ if (previousSession != null) {
+ TestCasesCounter testCasesCounter = new TestCasesCounter();
+ previousSession.getModelAccessor().getRootSuite().visit(testCasesCounter);
+ totalCounter = testCasesCounter.result;
+ }
+ ITestSuite rootTestSuite = previousSession != null ? previousSession.getModelAccessor().getRootSuite() : null;
+ this.modelManager = new TestModelManager(rootTestSuite, testsRunnerProviderInfo.isAllowedTestingTimeMeasurement());
+ this.modelManager.addChangesListener(new ITestingSessionListener() {
+
+ @Override
+ public void testingStarted() {}
+
+ @Override
+ public void testingFinished() {
+ // This is necessary if totalCounter was -1 (tests count was unknown)
+ // or if tests count was estimated not accurately
+ totalCounter = currentCounter;
+ }
+
+ @Override
+ public void exitTestSuite(ITestSuite testSuite) {}
+
+ @Override
+ public void exitTestCase(ITestCase testCase) {
+ // Update testing session info (counters, flags)
+ Status testStatus = testCase.getStatus();
+ statusCounters.put(testStatus, getCount(testStatus)+1);
+ ++currentCounter;
+ if (testStatus.isError())
+ hasErrors = true;
+ }
+
+ @Override
+ public void enterTestSuite(ITestSuite testSuite) {}
+
+ @Override
+ public void enterTestCase(ITestCase testCase) {}
+
+ @Override
+ public void childrenUpdate(ITestSuite parent) {}
+ });
+ }
+
+ /**
+ * Starts the processing of the test module output.
+ *
+ * @param inputStream test module output stream
+ */
+ public void run(InputStream inputStream) {
+ modelManager.testingStarted();
+ try {
+ testsRunnerProvider.run(modelManager, inputStream);
+ // If testing session was stopped, the status is set in stop()
+ if (!wasStopped()) {
+ double testingTime = getModelAccessor().getRootSuite().getTestingTime();
+ statusMessage = MessageFormat.format(ModelMessages.TestingSession_finished_status, testingTime/1000.0);
+ }
+ } catch (TestingException e) {
+ // If testing session was stopped, the status is set in stop()
+ if (!wasStopped()) {
+ statusMessage = e.getLocalizedMessage();
+ hasErrors = true;
+ }
+ }
+ finished = true;
+ modelManager.testingFinished();
+ }
+
+ @Override
+ public int getCurrentCounter() {
+ return currentCounter;
+ }
+
+ @Override
+ public int getTotalCounter() {
+ return totalCounter;
+ }
+
+ @Override
+ public int getCount(ITestItem.Status status) {
+ Integer counterValue = statusCounters.get(status);
+ return (counterValue == null) ? 0 : counterValue;
+ }
+
+ @Override
+ public boolean hasErrors() {
+ return hasErrors;
+ }
+
+ @Override
+ public boolean wasStopped() {
+ return wasStopped;
+ }
+
+ @Override
+ public boolean isFinished() {
+ return finished;
+ }
+
+ @Override
+ public ITestModelAccessor getModelAccessor() {
+ return modelManager;
+ }
+
+ @Override
+ public ILaunch getLaunch() {
+ return launch;
+ }
+
+ @Override
+ public TestsRunnerProviderInfo getTestsRunnerProviderInfo() {
+ return testsRunnerProviderInfo;
+ }
+
+ @Override
+ public String getStatusMessage() {
+ return statusMessage;
+ }
+
+ @Override
+ public String getName() {
+ String launchConfName = launch.getLaunchConfiguration().getName();
+ String startTimeStr = DateFormat.getDateTimeInstance().format(new Date(startTime));
+ return MessageFormat.format(ModelMessages.TestingSession_name_format, launchConfName, startTimeStr);
+ }
+
+ @Override
+ public void stop() {
+ if (!launch.isTerminated() && launch.canTerminate()) {
+ try {
+ launch.terminate();
+ wasStopped = true;
+ statusMessage = ModelMessages.TestingSession_stopped_status;
+ } catch (DebugException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSessionsManager.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSessionsManager.java
new file mode 100644
index 0000000000..66bf252c6b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/model/TestingSessionsManager.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.model;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProvidersManager;
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProviderInfo;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+/**
+ * Manages all the testing sessions (creates, activates, stores history).
+ */
+public class TestingSessionsManager {
+
+ /** Tests Runners Plug-ins Manager. */
+ private TestsRunnerProvidersManager testsRunnersManager;
+
+ /** Testing sessions history list (the first is the newest). */
+ private LinkedList<TestingSession> sessions = new LinkedList<TestingSession>();
+
+ /** Currently active testing session. */
+ private TestingSession activeSession;
+
+ /** Listeners collection. */
+ private List<ITestingSessionsManagerListener> listeners = new ArrayList<ITestingSessionsManagerListener>();
+
+ /** The size limit of the testing sessions history. */
+ private int historySizeLimit = 10;
+
+ public TestingSessionsManager(TestsRunnerProvidersManager testsRunnersManager) {
+ this.testsRunnersManager = testsRunnersManager;
+ }
+
+ /**
+ * Tries to find the last testing session for the specified launch
+ * configuration and Tests Runner provide plug-in.
+ *
+ * <p>
+ * Usually testing frameworks do not provide the information about tests
+ * hierarchy and total tests count before the testing is finished. So we try
+ * to reuse them from one the previous testing sessions that meets the
+ * requirements:
+ * <ul>
+ * <li>it should be for the same launch configuration;
+ * <li>it should be completed (finished and not stopped);
+ * <li>it should has the same tests runner;
+ * </ul>
+ * This function tries to find a such session.
+ * </p>
+ *
+ * @param launchConfiguration required launch configuration
+ * @param testsRunnerProviderInfo required Tests Runner provide plug-in
+ * @return testing session or null if not found
+ */
+ private TestingSession findActualPreviousSession(ILaunchConfiguration launchConfiguration, TestsRunnerProviderInfo testsRunnerProviderInfo) {
+ String testsRunnerName = testsRunnerProviderInfo.getName();
+ for (TestingSession session : sessions) {
+ // Find the latest testing session that matches the next requirements:
+ // - it should be for the same launch configuration (should have the same parameters)
+ // - should be already terminated (to have complete tests hierarchy structure)
+ // - should not be stopped by user (the same as terminated)
+ // - should have the same tests runner
+ if (session != null) {
+ if (launchConfiguration.equals(session.getLaunch().getLaunchConfiguration())
+ && session.isFinished()
+ && !session.wasStopped()
+ && session.getTestsRunnerProviderInfo().getName().equals(testsRunnerName)) {
+ return session;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new testing session for the specified launch.
+ *
+ * @param launch launch
+ * @return new testing session
+ */
+ public TestingSession newSession(ILaunch launch) throws CoreException {
+ TestsRunnerProviderInfo testsRunnerProviderInfo = testsRunnersManager.getTestsRunnerProviderInfo(launch.getLaunchConfiguration());
+ TestingSession previousSession = findActualPreviousSession(launch.getLaunchConfiguration(), testsRunnerProviderInfo);
+ TestingSession newTestingSession = new TestingSession(launch, testsRunnerProviderInfo, previousSession);
+ sessions.addFirst(newTestingSession);
+ setActiveSession(newTestingSession);
+ truncateHistory();
+ return newTestingSession;
+ }
+
+ /**
+ * Returns the testing sessions history (the first is the newest).
+ *
+ * @return testing sessions list
+ */
+ public List<? extends ITestingSession> getSessions() {
+ return sessions;
+ }
+
+ /**
+ * Rewrites the testing sessions history with the specified list. Truncates
+ * the history if necessary.
+ *
+ * @return testing sessions list
+ */
+ public void setSessions(List<ITestingSession> newSessions) {
+ sessions.clear();
+ for (ITestingSession newSession : newSessions) {
+ sessions.add((TestingSession) newSession);
+ }
+ truncateHistory();
+ }
+
+ /**
+ * Returns the testing sessions history size.
+ *
+ * @return history size
+ */
+ public int getSessionsCount() {
+ return sessions.size();
+ }
+
+ /**
+ * Accesses the currently active testing session.
+ *
+ * @return testing session
+ */
+ public ITestingSession getActiveSession() {
+ return activeSession;
+ }
+
+ /**
+ * Sets the new active testing session.
+ *
+ * @param newActiveSession testing session
+ */
+ public void setActiveSession(ITestingSession newActiveSession) {
+ if (activeSession != newActiveSession) {
+ activeSession = (TestingSession) newActiveSession;
+ // Notify listeners
+ for (ITestingSessionsManagerListener listener : listeners) {
+ listener.sessionActivated(activeSession);
+ }
+ }
+ }
+
+ /**
+ * Adds the given listener to this registered listeners collection.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener to add
+ */
+ public void addListener(ITestingSessionsManagerListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from registered listeners collection.
+ * Has no effect if the listener is not already registered.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeListener(ITestingSessionsManagerListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Returns the size limit of the testing sessions history.
+ *
+ * @return history size limit
+ */
+ public int getHistorySizeLimit() {
+ return historySizeLimit;
+ }
+
+ /**
+ * Sets the size limit of the testing sessions history.
+ *
+ * @param historySizeLimit new history size limit
+ */
+ public void setHistorySizeLimit(int historySizeLimit) {
+ this.historySizeLimit = historySizeLimit;
+ truncateHistory();
+ }
+
+ /**
+ * Truncates the history list if it is longer than size limit.
+ */
+ private void truncateHistory() {
+ // The most frequently this method will be used to remove one element, so removeAll() is unnecessary here
+ while (sessions.size() > historySizeLimit) {
+ sessions.removeLast();
+ }
+ // Handle the case when active testing session was removed from history due to truncation
+ if (!sessions.contains(activeSession)) {
+ ITestingSession newActiveSession = sessions.isEmpty() ? null : sessions.getFirst();
+ setActiveSession(newActiveSession);
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/CTestingTab.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/CTestingTab.java
new file mode 100644
index 0000000000..bb1d058a4e
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/CTestingTab.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.launcher;
+
+import org.eclipse.cdt.launch.ui.CLaunchConfigurationTab;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.launcher.ITestsLaunchConfigurationConstants;
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProviderInfo;
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProviderInfo;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+
+/**
+ * A launch configuration tab that displays and edits different testing options
+ * (e.g. Tests Runner provider plug-in).
+ * <p>
+ * This class may be instantiated. This class is not intended to be subclassed.
+ * </p>
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class CTestingTab extends CLaunchConfigurationTab {
+
+ /**
+ * Tab identifier used for ordering of tabs added using the
+ * <code>org.eclipse.debug.ui.launchConfigurationTabs</code>
+ * extension point.
+ */
+ private static final String TAB_ID = "org.eclipse.cdt.testsrunner.testingTab"; //$NON-NLS-1$
+
+ private static final String TESTING_PROCESS_FACTORY_ID = "org.eclipse.cdt.testsrunner.TestingProcessFactory"; //$NON-NLS-1$
+
+ /** Shows the list of available Tests Runner provider plug-ins. */
+ private Combo testsRunnerProviderCombo;
+
+ /** Shows the description for the currently selected Tests Runner provider plug-in. */
+ private Label testsRunnerProviderDescriptionLabel;
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite pageComposite = new Composite(parent, SWT.NONE);
+ GridLayout pageCompositeLayout = new GridLayout(2, false);
+ pageCompositeLayout.horizontalSpacing = 40;
+ pageComposite.setLayout(pageCompositeLayout);
+
+ // Create a tests runner selector
+ new Label(pageComposite, SWT.NONE).setText(UILauncherMessages.CTestingTab_tests_runner_label);
+ testsRunnerProviderCombo = new Combo(pageComposite, SWT.READ_ONLY | SWT.DROP_DOWN);
+ testsRunnerProviderCombo.add(UILauncherMessages.CTestingTab_tests_runner_is_not_set);
+ testsRunnerProviderCombo.setData("0", null); //$NON-NLS-1$
+
+ // Add all the tests runners
+ for (TestsRunnerProviderInfo testsRunnerProviderInfo : TestsRunnerPlugin.getDefault().getTestsRunnerProvidersManager().getTestsRunnersProviderInfo()) {
+ testsRunnerProviderCombo.setData(Integer.toString(testsRunnerProviderCombo.getItemCount()), testsRunnerProviderInfo);
+ testsRunnerProviderCombo.add(testsRunnerProviderInfo.getName());
+ }
+
+ testsRunnerProviderCombo.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ testsRunnerProviderDescriptionLabel.setText(getCurrentTestsRunnerDescription());
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ // Create a tests runner description label
+ testsRunnerProviderDescriptionLabel = new Label(pageComposite, SWT.WRAP);
+ GridData testsRunnerProviderLabelGD = new GridData(GridData.FILL_BOTH);
+ testsRunnerProviderLabelGD.horizontalSpan = 2;
+ testsRunnerProviderLabelGD.horizontalAlignment = GridData.FILL;
+ testsRunnerProviderDescriptionLabel.setLayoutData(testsRunnerProviderLabelGD);
+
+ GridData pageCompositeGD = new GridData(GridData.FILL_BOTH);
+ pageCompositeGD.horizontalAlignment = GridData.FILL;
+ pageCompositeGD.grabExcessHorizontalSpace = true;
+ pageComposite.setLayoutData(pageCompositeGD);
+ setControl(pageComposite);
+ }
+
+ /**
+ * Returns the information for the currently selected Tests Runner provider
+ * plug-in.
+ *
+ * @return Tests Runner provide plug-in information
+ */
+ private ITestsRunnerProviderInfo getCurrentTestsRunnerProviderInfo() {
+ return getTestsRunnerProviderInfo(testsRunnerProviderCombo.getSelectionIndex());
+ }
+
+ /**
+ * Returns the information for the Tests Runner provide plug-in specified by
+ * index.
+ *
+ * @param comboIndex index in combo widget
+ * @return Tests Runner provide plug-in information
+ */
+ private ITestsRunnerProviderInfo getTestsRunnerProviderInfo(int comboIndex) {
+ return (ITestsRunnerProviderInfo)testsRunnerProviderCombo.getData(Integer.toString(comboIndex));
+ }
+
+ /**
+ * Returns the description for the currently selected Tests Runner provide
+ * plug-in.
+ *
+ * @return the description
+ */
+ private String getCurrentTestsRunnerDescription() {
+ ITestsRunnerProviderInfo testsRunnerProvider = getCurrentTestsRunnerProviderInfo();
+ if (testsRunnerProvider != null) {
+ return testsRunnerProvider.getDescription();
+ } else {
+ return UILauncherMessages.CTestingTab_no_tests_runner_label;
+ }
+ }
+
+ @Override
+ public boolean isValid(ILaunchConfiguration config) {
+ return getCurrentTestsRunnerProviderInfo() != null;
+ }
+
+ @Override
+ public void setDefaults(ILaunchConfigurationWorkingCopy config) {
+ config.setAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_RUNNER, (String) null);
+ config.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, TESTING_PROCESS_FACTORY_ID);
+ }
+
+ @Override
+ public void initializeFrom(ILaunchConfiguration configuration) {
+ try {
+ String testsRunnerId = configuration.getAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_RUNNER, (String) null);
+ int comboIndex = 0;
+ for (int i = 1; i < testsRunnerProviderCombo.getItemCount(); i++) {
+ if (getTestsRunnerProviderInfo(i).getId().equals(testsRunnerId)) {
+ comboIndex = i;
+ break;
+ }
+ }
+ testsRunnerProviderCombo.select(comboIndex);
+
+ } catch (CoreException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ }
+
+ @Override
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ ITestsRunnerProviderInfo testsRunnerProvider = getCurrentTestsRunnerProviderInfo();
+ String testsRunnerProviderId = testsRunnerProvider != null ? testsRunnerProvider.getId() : null;
+ configuration.setAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_RUNNER, testsRunnerProviderId);
+ configuration.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, TESTING_PROCESS_FACTORY_ID);
+ }
+
+ @Override
+ public String getId() {
+ return TAB_ID;
+ }
+
+ @Override
+ public String getName() {
+ return UILauncherMessages.CTestingTab_tab_name;
+ }
+
+ @Override
+ public String getErrorMessage() {
+ String m = super.getErrorMessage();
+ if (m == null) {
+ if (getCurrentTestsRunnerProviderInfo() == null) {
+ return UILauncherMessages.CTestingTab_no_tests_runner_error;
+ }
+ }
+ return m;
+ }
+
+ @Override
+ public Image getImage() {
+ return TestsRunnerPlugin.createAutoImage("obj16/test_notrun.gif"); //$NON-NLS-1$
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/EmptyConfigurationTabGroup.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/EmptyConfigurationTabGroup.java
new file mode 100644
index 0000000000..77a9d44cd2
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/EmptyConfigurationTabGroup.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.launcher;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+
+
+/**
+ * Represents an empty tab group. Actual tabs are added via the
+ * <code>org.eclipse.debug.ui.launchConfigurationTabs</code> extension point.
+ */
+public class EmptyConfigurationTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+ @Override
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+ setTabs(new ILaunchConfigurationTab[0]);
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.java
new file mode 100644
index 0000000000..8e75b59f54
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.launcher;
+
+import org.eclipse.osgi.util.NLS;
+
+public class UILauncherMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.internal.ui.launcher.UILauncherMessages"; //$NON-NLS-1$
+ public static String CTestingTab_no_tests_runner_error;
+ public static String CTestingTab_no_tests_runner_label;
+ public static String CTestingTab_tab_name;
+ public static String CTestingTab_tests_runner_is_not_set;
+ public static String CTestingTab_tests_runner_label;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, UILauncherMessages.class);
+ }
+
+ private UILauncherMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.properties
new file mode 100644
index 0000000000..752755e5f7
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/launcher/UILauncherMessages.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+CTestingTab_no_tests_runner_error=Tests runner is not selected
+CTestingTab_no_tests_runner_label=Select a tests runner...
+CTestingTab_tab_name=C/C++ Testing
+CTestingTab_tests_runner_is_not_set=<not set>
+CTestingTab_tests_runner_label=Tests Runner
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/CounterPanel.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/CounterPanel.java
new file mode 100644
index 0000000000..4f3f8d910e
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/CounterPanel.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import java.text.MessageFormat;
+
+
+/**
+ * Shows a simple tests count statics information (run/error/failed).
+ */
+public class CounterPanel extends Composite {
+
+ /** Testing session to show statistics for. */
+ private ITestingSession testingSession;
+
+ /** Widget showing the failed tests count. */
+ private Label failedCounterLabel;
+
+ /** Widget showing the error tests count. */
+ private Label abortedCounterLabel;
+
+ /** Widget showing the run tests count. */
+ private Label currentCounterLabel;
+
+ /**
+ * Shows whether there were skipped tests. It is used to force layout of the
+ * counter widgets after skipped tests are appeared.
+ */
+ private boolean hasSkipped;
+
+ private final Image errorIcon = TestsRunnerPlugin.createAutoImage("ovr16/failed_counter.gif"); //$NON-NLS-1$
+ private final Image failureIcon = TestsRunnerPlugin.createAutoImage("ovr16/aborted_counter.gif"); //$NON-NLS-1$
+
+
+ public CounterPanel(Composite parent, ITestingSession testingSession) {
+ super(parent, SWT.WRAP);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 9;
+ gridLayout.makeColumnsEqualWidth = false;
+ gridLayout.marginWidth = 0;
+ setLayout(gridLayout);
+
+ currentCounterLabel = createLabel(UIViewMessages.CounterPanel_tests_run, null);
+ abortedCounterLabel = createLabel(UIViewMessages.CounterPanel_tests_erred, errorIcon);
+ failedCounterLabel = createLabel(UIViewMessages.CounterPanel_tests_failed, failureIcon);
+ setTestingSession(testingSession);
+ }
+
+ /**
+ * Creates counter label widget.
+ *
+ * @param name widget text prefix
+ * @param image widget image or <code>null</code>
+ * @return created label
+ */
+ private Label createLabel(String name, Image image) {
+ Label label = new Label(this, SWT.NONE);
+ if (image != null) {
+ image.setBackground(label.getBackground());
+ label.setImage(image);
+ }
+ label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+
+ label = new Label(this, SWT.NONE);
+ label.setText(name);
+ label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+
+ Label value = new Label(this, SWT.READ_ONLY);
+ value.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_BEGINNING));
+ return value;
+ }
+
+ /**
+ * Sets the testing session to show information about.
+ *
+ * @param testingSession testing session (null is not acceptable)
+ */
+ public void setTestingSession(ITestingSession testingSession) {
+ this.testingSession = testingSession;
+ this.hasSkipped = testingSession.getCount(ITestItem.Status.Skipped) != 0;
+ updateInfoFromSession();
+ }
+
+ /**
+ * Updates the information on the panel from the currently set testing
+ * session.
+ */
+ public void updateInfoFromSession() {
+ setFailedCounter(testingSession.getCount(ITestItem.Status.Failed));
+ setAbortedCounter(testingSession.getCount(ITestItem.Status.Aborted));
+ setCurrentCounter(testingSession.getCurrentCounter(), testingSession.getCount(ITestItem.Status.Skipped));
+ redraw();
+ }
+
+ /**
+ * Sets a new value for the failed tests counter.
+ *
+ * @param newValue new counter value
+ */
+ private void setFailedCounter(int newValue) {
+ failedCounterLabel.setText(Integer.toString(newValue));
+ }
+
+ /**
+ * Sets a new value for the error tests counter.
+ *
+ * @param newValue new counter value
+ */
+ private void setAbortedCounter(int newValue) {
+ abortedCounterLabel.setText(Integer.toString(newValue));
+ }
+
+ /**
+ * Sets a new value for the run tests counter.
+ *
+ * @param currentValue new counter value
+ * @param skippedValue skipped tests counter
+ */
+ private void setCurrentCounter(int currentValue, int skippedValue) {
+ if (!hasSkipped && skippedValue != 0) {
+ layout();
+ }
+ String runString = (skippedValue == 0)
+ ? Integer.toString(currentValue)
+ : MessageFormat.format(UIViewMessages.CounterPanel_tests_skipped, currentValue, skippedValue);
+ currentCounterLabel.setText(runString);
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/DummyUISession.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/DummyUISession.java
new file mode 100644
index 0000000000..9787a5bb5b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/DummyUISession.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProviderInfo;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestModelAccessor;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.debug.core.ILaunch;
+
+/**
+ * Represents a simple testing session which is used for UI when there is no
+ * "real" testing sessions to show (e.g. when there was no launched testing
+ * session or when all of them were cleared).
+ */
+public class DummyUISession implements ITestingSession {
+
+ @Override
+ public int getCurrentCounter() {
+ return 0;
+ }
+
+ @Override
+ public int getTotalCounter() {
+ return 0;
+ }
+
+ @Override
+ public int getCount(ITestItem.Status status) {
+ return 0;
+ }
+
+ @Override
+ public boolean hasErrors() {
+ return false;
+ }
+
+ @Override
+ public boolean wasStopped() {
+ return false;
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public ITestModelAccessor getModelAccessor() {
+ return null;
+ }
+
+ @Override
+ public ILaunch getLaunch() {
+ return null;
+ }
+
+ @Override
+ public ITestsRunnerProviderInfo getTestsRunnerProviderInfo() {
+ return null;
+ }
+
+ @Override
+ public String getStatusMessage() {
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public String getName() {
+ return "<dummy>"; //$NON-NLS-1$
+ }
+
+ @Override
+ public void stop() {
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/MessagesViewer.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/MessagesViewer.java
new file mode 100644
index 0000000000..db0aa21e9b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/MessagesViewer.java
@@ -0,0 +1,573 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.CopySelectedMessagesAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.OpenInEditorAction;
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestLocation;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+import org.eclipse.cdt.testsrunner.model.ITestMessage.Level;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.IOpenListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+
+
+/**
+ * Shows the messages for the currently selected items in tests hierarchy (test
+ * suites or test cases).
+ */
+public class MessagesViewer {
+
+ /**
+ * Enumeration of all possible message filter actions by level.
+ */
+ public enum LevelFilter {
+ Info(ISharedImages.IMG_OBJS_INFO_TSK, ITestMessage.Level.Info, ITestMessage.Level.Message),
+ Warning(ISharedImages.IMG_OBJS_WARN_TSK, ITestMessage.Level.Warning),
+ Error(ISharedImages.IMG_OBJS_ERROR_TSK, ITestMessage.Level.Error, ITestMessage.Level.FatalError, ITestMessage.Level.Exception);
+
+ private String imageId;
+ private ITestMessage.Level [] includedLevels;
+
+ LevelFilter(String imageId, ITestMessage.Level... includedLevels) {
+ this.imageId = imageId;
+ this.includedLevels = includedLevels;
+ }
+
+ /**
+ * The shared image ID corresponding to the message level filter action.
+ *
+ * @return shared image ID
+ */
+ public String getImageId() {
+ return imageId;
+ }
+
+ /**
+ * The message levels that should be shown if current message level
+ * filter action is set.
+ *
+ * @return array of message levels
+ */
+ public ITestMessage.Level [] getLevels() {
+ return includedLevels;
+ }
+
+ /**
+ * Checks whether the specified message level should be shown if current
+ * message level filter action is set.
+ *
+ * @param messageLevel message level to search
+ * @return <code>true</code> if found
+ */
+ public boolean isIncluded(ITestMessage.Level messageLevel) {
+ for (ITestMessage.Level currLevel : includedLevels) {
+ if (currLevel.equals(messageLevel)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * The content provider for the test messages viewer.
+ */
+ private class MessagesContentProvider implements IStructuredContentProvider {
+
+ /**
+ * Utility class: recursively collects all the messages of the specified
+ * test item.
+ */
+ class MessagesCollector implements IModelVisitor {
+
+ /** Collected test messages. */
+ Collection<ITestMessage> collectedTestMessages;
+
+ /**
+ * Specifies whether gathering should be done. It is used to skip
+ * the messages of the passed tests if they should not be shown.
+ */
+ boolean collect = true;
+
+ MessagesCollector(Collection<ITestMessage> testMessages) {
+ this.collectedTestMessages = testMessages;
+ }
+
+ @Override
+ public void visit(ITestMessage testMessage) {
+ if (collect) {
+ collectedTestMessages.add(testMessage);
+ }
+ }
+
+ @Override
+ public void visit(ITestCase testCase) {
+ collect = !showFailedOnly || testCase.getStatus().isError();
+ }
+
+ @Override
+ public void visit(ITestSuite testSuite) {}
+
+ @Override
+ public void leave(ITestSuite testSuite) {}
+
+ @Override
+ public void leave(ITestCase testCase) {}
+
+ @Override
+ public void leave(ITestMessage testMessage) {}
+ }
+
+ /** Test messages to show in the viewer. */
+ ITestMessage[] testMessages;
+
+ @Override
+ public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+ if (newInput != null) {
+ collectMessages((ITestItem[]) newInput);
+ } else {
+ testMessages = new ITestMessage[0];
+ }
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public Object[] getElements(Object parent) {
+ return testMessages;
+ }
+
+ /**
+ * Creates a messages set with a custom comparator. It is used for the
+ * ordered messages showing.
+ *
+ * @return set to store the test messages
+ */
+ private TreeSet<ITestMessage> createMessagesSet() {
+ return new TreeSet<ITestMessage>(new Comparator<ITestMessage>() {
+
+ @Override
+ public int compare(ITestMessage message1, ITestMessage message2) {
+ // Compare messages by location
+ ITestLocation location1 = message1.getLocation();
+ ITestLocation location2 = message2.getLocation();
+
+ if (location1 != null && location2 != null) {
+ // Compare by file name
+ String file1 = location1.getFile();
+ String file2 = location2.getFile();
+ int fileResult = file1.compareTo(file2);
+ if (fileResult != 0) {
+ return fileResult;
+ } else {
+ // Compare by line number
+ int line1 = location1.getLine();
+ int line2 = location2.getLine();
+ if (line1 < line2) {
+ return -1;
+
+ } else if (line1 > line2) {
+ return 1;
+ }
+ }
+
+ } else if (location1 == null && location2 != null) {
+ return -1;
+
+ } else if (location1 != null && location2 == null) {
+ return 1;
+ }
+
+ // Compare by message text
+ String text1 = message1.getText();
+ String text2 = message2.getText();
+ return text1.compareTo(text2);
+ }
+ });
+ }
+
+ /**
+ * Creates a list to store the test messages. It is used for the
+ * unordered messages showing.
+ *
+ * @return list to store the test messages
+ */
+ private ArrayList<ITestMessage> createMessagesList() {
+ return new ArrayList<ITestMessage>();
+ }
+
+ /**
+ * Creates a collection to store the test messages depending on whether
+ * ordering is required.
+ *
+ * @return collection to store the test messages
+ */
+ private Collection<ITestMessage> createMessagesCollection() {
+ return orderingMode ? createMessagesSet() : createMessagesList();
+ }
+
+ /**
+ * Run messages collecting for the specified test items.
+ *
+ * @param testItems test items array
+ */
+ private void collectMessages(ITestItem[] testItems) {
+ Collection<ITestMessage> testMessagesCollection = createMessagesCollection();
+ for (ITestItem testItem : testItems) {
+ testItem.visit(new MessagesCollector(testMessagesCollection));
+ }
+ testMessages = testMessagesCollection.toArray(new ITestMessage[testMessagesCollection.size()]);
+ }
+ }
+
+ /**
+ * The label provider for the test messages viewer.
+ */
+ private class MessagesLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ /**
+ * Returns the full (file path) or short (file name only) file path view
+ * depending on the filter set.
+ *
+ * @param location test object location
+ * @return file path
+ */
+ private String getLocationFile(ITestLocation location) {
+ String filePath = location.getFile();
+ if (showFileNameOnly) {
+ return new File(filePath).getName();
+ } else {
+ return filePath;
+ }
+ }
+
+ @Override
+ public String getColumnText(Object obj, int index) {
+ ITestMessage message = (ITestMessage)obj;
+ ITestLocation location = message.getLocation();
+ String locationString = ""; //$NON-NLS-1$
+ if (location != null) {
+ locationString = MessageFormat.format(
+ UIViewMessages.MessagesViewer_location_format,
+ new Object[] { getLocationFile(location), location.getLine() }
+ );
+ }
+ return MessageFormat.format(UIViewMessages.MessagesViewer_message_format,
+ locationString, message.getLevel(), message.getText()
+ );
+ }
+
+ @Override
+ public Image getColumnImage(Object obj, int index) {
+ return getImage(obj);
+ }
+
+ @Override
+ public Image getImage(Object obj) {
+ Level level = ((ITestMessage)obj).getLevel();
+ String imageId = ISharedImages.IMG_OBJ_ELEMENT;
+ for (LevelFilter levelFilter : LevelFilter.values()) {
+ if (levelFilter.isIncluded(level)) {
+ imageId = levelFilter.getImageId();
+ break;
+ }
+ }
+ return PlatformUI.getWorkbench().getSharedImages().getImage(imageId);
+ }
+ }
+
+ /**
+ * Filters the required test messages by level.
+ */
+ private class MessageLevelFilter extends ViewerFilter {
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ return acceptedMessageLevels.contains(((ITestMessage)element).getLevel());
+ }
+ }
+
+
+ /** Main widget. */
+ private TableViewer tableViewer;
+
+ private IViewSite viewSite;
+
+ // Context menu actions
+ private OpenInEditorAction openInEditorAction;
+ private Action copyAction;
+
+ /** Specifies whether only messages for failed tests should be shown. */
+ private boolean showFailedOnly = false;
+
+ /**
+ * Specifies whether only file names should be shown (instead of full file
+ * paths).
+ */
+ private boolean showFileNameOnly = false;
+
+ /** The set of message level to show the messages with. */
+ private Set<ITestMessage.Level> acceptedMessageLevels = new HashSet<ITestMessage.Level>();
+
+ /** Specifies whether test messages ordering is on or off. */
+ private boolean orderingMode = false;
+
+
+ public MessagesViewer(Composite parent,
+ TestingSessionsManager sessionsManager, IWorkbench workbench,
+ IViewSite viewSite, Clipboard clipboard) {
+ this.viewSite = viewSite;
+ tableViewer = new TableViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
+ tableViewer.setLabelProvider(new MessagesLabelProvider());
+ tableViewer.setContentProvider(new MessagesContentProvider());
+ tableViewer.addFilter(new MessageLevelFilter());
+ initContextMenu(viewSite, sessionsManager, workbench, clipboard);
+ tableViewer.addOpenListener(new IOpenListener() {
+ @Override
+ public void open(OpenEvent event) {
+ openInEditorAction.run();
+ }
+ });
+ }
+
+ /**
+ * Initializes the viewer context menu.
+ *
+ * @param viewSite view
+ * @param sessionsManager testing sessions manager
+ * @param workbench workbench
+ * @param clipboard clipboard
+ */
+ private void initContextMenu(IViewSite viewSite,
+ TestingSessionsManager sessionsManager, IWorkbench workbench,
+ Clipboard clipboard) {
+ openInEditorAction = new OpenInEditorAction(tableViewer, sessionsManager, workbench);
+ copyAction = new CopySelectedMessagesAction(tableViewer, clipboard);
+
+ MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+ menuMgr.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager) {
+ handleMenuAboutToShow(manager);
+ }
+ });
+ viewSite.registerContextMenu(menuMgr, tableViewer);
+ Menu menu = menuMgr.createContextMenu(tableViewer.getTable());
+ tableViewer.getTable().setMenu(menu);
+
+ menuMgr.add(openInEditorAction);
+ menuMgr.add(copyAction);
+ configureCopy();
+ }
+
+ /**
+ * Configures the view copy action which should be run on CTRL+C. We have to
+ * track widget focus to select the actual action because we have a few
+ * widgets that should provide copy action (at least tests hierarchy viewer
+ * and messages viewer).
+ */
+ private void configureCopy() {
+ getTableViewer().getTable().addFocusListener(new FocusListener() {
+ IAction viewCopyHandler;
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (viewCopyHandler != null) {
+ switchTo(viewCopyHandler);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ switchTo(copyAction);
+ }
+
+ private void switchTo(IAction copyAction) {
+ IActionBars actionBars = viewSite.getActionBars();
+ viewCopyHandler = actionBars.getGlobalActionHandler(ActionFactory.COPY.getId());
+ actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
+ actionBars.updateActionBars();
+ }
+ });
+ }
+
+ /**
+ * Handles the context menu showing.
+ *
+ * @param manager context menu manager
+ */
+ private void handleMenuAboutToShow(IMenuManager manager) {
+ ISelection selection = tableViewer.getSelection();
+ openInEditorAction.setEnabled(!selection.isEmpty());
+ copyAction.setEnabled(!selection.isEmpty());
+ }
+
+ /**
+ * Provides access to the main widget of the messages viewer.
+ *
+ * @return main widget of the messages viewer
+ */
+ public TableViewer getTableViewer() {
+ return tableViewer;
+ }
+
+ /**
+ * Sets the test items for which the messages should be shown.
+ *
+ * @param testItems test items array
+ */
+ public void showItemsMessages(ITestItem[] testItems) {
+ tableViewer.setInput(testItems);
+ }
+
+ /**
+ * Forces the messages recollecting. It is used after message filters
+ * change.
+ */
+ private void forceRecollectMessages() {
+ // NOTE: Set input again makes content provider to recollect messages (with filters applied)
+ tableViewer.setInput(tableViewer.getInput());
+ }
+
+ /**
+ * Returns whether the messages only for the failed tests should be shown.
+ *
+ * @return filter state
+ */
+ public boolean getShowFailedOnly() {
+ return showFailedOnly;
+ }
+
+ /**
+ * Sets whether the messages only for the failed tests should be shown.
+ *
+ * @param showFailedOnly new filter state
+ */
+ public void setShowFailedOnly(boolean showFailedOnly) {
+ if (this.showFailedOnly != showFailedOnly) {
+ this.showFailedOnly = showFailedOnly;
+ forceRecollectMessages();
+ }
+ }
+
+ /**
+ * Returns whether short or long view for file paths should be shown.
+ *
+ * @return filter state
+ */
+ public boolean getShowFileNameOnly() {
+ return showFileNameOnly;
+ }
+
+ /**
+ * Sets whether short or long view for file paths should be shown.
+ *
+ * @param showFileNameOnly new filter state
+ */
+ public void setShowFileNameOnly(boolean showFileNameOnly) {
+ if (this.showFileNameOnly != showFileNameOnly) {
+ this.showFileNameOnly = showFileNameOnly;
+ forceRecollectMessages();
+ }
+ }
+
+ /**
+ * Returns whether test messages should be ordered by location.
+ *
+ * @return messages ordering state
+ */
+ public boolean getOrderingMode() {
+ return orderingMode;
+ }
+
+ /**
+ * Sets whether test messages should be ordered by location.
+ *
+ * @param orderingMode new messages ordering state
+ */
+ public void setOrderingMode(boolean orderingMode) {
+ if (this.orderingMode != orderingMode) {
+ this.orderingMode = orderingMode;
+ forceRecollectMessages();
+ }
+ }
+
+ /**
+ * Adds the filter message level filters by the message filter action level.
+ *
+ * @param levelFilter message filter action level
+ * @param refresh specifies whether viewer should be refreshed after filter
+ * update (small optimization: avoid many updates on initialization)
+ */
+ public void addLevelFilter(LevelFilter levelFilter, boolean refresh) {
+ for (ITestMessage.Level level : levelFilter.getLevels()) {
+ acceptedMessageLevels.add(level);
+ }
+ if (refresh) {
+ tableViewer.refresh();
+ }
+ }
+
+ /**
+ * Removed the filter message level filters by the message filter action
+ * level.
+ *
+ * @param levelFilter message filter action level
+ */
+ public void removeLevelFilter(LevelFilter levelFilter) {
+ for (ITestMessage.Level level : levelFilter.getLevels()) {
+ acceptedMessageLevels.remove(level);
+ }
+ tableViewer.refresh();
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressBar.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressBar.java
new file mode 100644
index 0000000000..dc1c004420
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressBar.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A progress bar with a red/green indication for testing success or failure.
+ */
+public class ProgressBar extends Canvas {
+
+ /** Default bar width */
+ private static final int DEFAULT_WIDTH = 160;
+
+ /** Default bar height */
+ private static final int DEFAULT_HEIGHT = 18;
+
+ /** Testing session to show progress bar for. */
+ private ITestingSession testingSession;
+
+ /** Current bar width. */
+ private int colorBarWidth;
+
+ /** The bar color when everything is OK (no tests failed and no testing errors). */
+ private Color okColor;
+
+ /** The bar color when there are tests failed and or testing errors. */
+ private Color failureColor;
+
+ /** The bar color when the testing session was stopped by user. */
+ private Color stoppedColor;
+
+
+ public ProgressBar(Composite parent, ITestingSession testingSession) {
+ super(parent, SWT.NONE);
+
+ addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ updateInfoFromSession();
+ }
+ });
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ paint(e);
+ }
+ });
+
+ // Manage progress bar colors
+ Display display = parent.getDisplay();
+ failureColor = new Color(display, 159, 63, 63);
+ okColor = new Color(display, 95, 191, 95);
+ stoppedColor = new Color(display, 120, 120, 120);
+ addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ failureColor.dispose();
+ okColor.dispose();
+ stoppedColor.dispose();
+ }
+ });
+ setTestingSession(testingSession);
+ }
+
+ /**
+ * Sets the testing session to show information about.
+ *
+ * @param testingSession testing session (null is not acceptable)
+ */
+ public void setTestingSession(ITestingSession testingSession) {
+ this.testingSession = testingSession;
+ updateInfoFromSession();
+ }
+
+ /**
+ * Updates the progress from the currently set testing session.
+ */
+ public void updateInfoFromSession() {
+ recalculateColorBarWidth();
+ redraw();
+ }
+
+ /**
+ * Sets the color of the progress bar depending on the testing session.
+ *
+ * @param gc gc
+ */
+ private void setStatusColor(GC gc) {
+ if (testingSession.wasStopped())
+ gc.setBackground(stoppedColor);
+ else if (testingSession.hasErrors())
+ gc.setBackground(failureColor);
+ else
+ gc.setBackground(okColor);
+ }
+
+ /**
+ * Calculate the width of the progress rectangle in a widget.
+ *
+ * @note If total tests count is known it is used to determine width of the
+ * progress rectangle. If it isn't the width of progress rectangle is set to
+ * the half of a widget.
+ */
+ private void recalculateColorBarWidth() {
+ Rectangle r = getClientArea();
+ int newColorBarWidth;
+ if (testingSession.getTotalCounter() > 0) {
+ newColorBarWidth = testingSession.getCurrentCounter()*(r.width-2)/testingSession.getTotalCounter();
+ } else {
+ newColorBarWidth = testingSession.getCurrentCounter() > 0 ? (r.width-2)/2 : (testingSession.isFinished() ? r.width-2 : 0);
+ }
+ colorBarWidth = Math.max(0, newColorBarWidth);
+ }
+
+ /**
+ * Draws the widget border
+ */
+ private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright) {
+ gc.setForeground(topleft);
+ gc.drawLine(x, y, x+w-1, y);
+ gc.drawLine(x, y, x, y+h-1);
+
+ gc.setForeground(bottomright);
+ gc.drawLine(x+w, y, x+w, y+h);
+ gc.drawLine(x, y+h, x+w, y+h);
+ }
+
+ /**
+ * Handles paint event and redraws the widget if necessary.
+ *
+ * @param event paint event
+ */
+ private void paint(PaintEvent event) {
+ GC gc = event.gc;
+ Display disp = getDisplay();
+
+ Rectangle rect = getClientArea();
+ gc.fillRectangle(rect);
+ drawBevelRect(gc, rect.x, rect.y, rect.width-1, rect.height-1,
+ disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW),
+ disp.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
+
+ setStatusColor(gc);
+ colorBarWidth = Math.min(rect.width-2, colorBarWidth);
+ gc.fillRectangle(1, 1, colorBarWidth, rect.height-2);
+ }
+
+ @Override
+ public Point computeSize(int wHint, int hHint, boolean changed) {
+ checkWidget();
+ Point size = new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ if (wHint != SWT.DEFAULT) {
+ size.x = wHint;
+ }
+ if (hHint != SWT.DEFAULT) {
+ size.y = hHint;
+ }
+ return size;
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressCountPanel.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressCountPanel.java
new file mode 100644
index 0000000000..eb8e65cb4a
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ProgressCountPanel.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A statistics panel that compounds counter panel and red/green progress bar.
+ * Depending on orientation it may layout them vertically or horizontally.
+ */
+public class ProgressCountPanel extends Composite {
+
+ /** Child widget: counter panel. */
+ private CounterPanel counterPanel;
+
+ /** Child widget: red/green progress bar */
+ private ProgressBar progressBar;
+
+ /**
+ * Dummy session is used when there is no "real" testing sessions to show
+ * (e.g. when there was no launched testing session or when all of them were
+ * cleared).
+ */
+ private DummyUISession dummyUISession = new DummyUISession();
+
+
+ public ProgressCountPanel(Composite parent, ResultsView.Orientation currOrientation) {
+ super(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ setLayout(layout);
+ setPanelOrientation(currOrientation);
+
+ counterPanel = new CounterPanel(this, dummyUISession);
+ counterPanel.setLayoutData(
+ new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
+ progressBar = new ProgressBar(this, dummyUISession);
+ progressBar.setLayoutData(
+ new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
+
+ // Data for parent (view's) layout
+ setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
+ }
+
+ /**
+ * Sets the testing session to show information about.
+ *
+ * @param testingSession testing session or null to set default empty
+ * session
+ */
+ public void setTestingSession(ITestingSession testingSession) {
+ ITestingSession newSession = (testingSession != null) ? testingSession : dummyUISession;
+ counterPanel.setTestingSession(newSession);
+ progressBar.setTestingSession(newSession);
+ }
+
+ /**
+ * Updates the information on the panel from the currently set testing
+ * session.
+ */
+ public void updateInfoFromSession() {
+ counterPanel.updateInfoFromSession();
+ progressBar.updateInfoFromSession();
+ }
+
+ /**
+ * Sets the widget orientation.
+ *
+ * @param orientation new widget orientation (vertical or horizontal; auto
+ * is not supported)
+ */
+ public void setPanelOrientation(ResultsView.Orientation orientation) {
+ ((GridLayout)getLayout()).numColumns = (orientation == ResultsView.Orientation.Horizontal) ? 2 : 1;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsPanel.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsPanel.java
new file mode 100644
index 0000000000..50c8d94c8b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsPanel.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.internal.ui.view.MessagesViewer.LevelFilter;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.MessageLevelFilterAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.MessagesOrderingAction;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.ViewForm;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbench;
+
+/**
+ * The main widget of testing results view. It compounds tests hierarchy and
+ * messages viewer. Depending on orientation it may layout them vertically or
+ * horizontally.
+ */
+public class ResultsPanel {
+
+ /** Parent for the child widgets (messages & tests hierarchy viewer). */
+ private SashForm sashForm;
+
+ /** Child widget: messages viewer. */
+ private MessagesViewer messagesViewer;
+
+ /** Child widget: tests hierarchy viewer. */
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+ // Persistence tags
+ static final String TAG_WEIGHT0 = "weight0"; //$NON-NLS-1$
+ static final String TAG_WEIGHT1 = "weight1"; //$NON-NLS-1$
+ static final String TAG_MESSAGES_ORDERING_ACTION = "messagesOrderingAction"; //$NON-NLS-1$
+ static final String TAG_ERROR_FILTER_ACTION = "errorFilterAction"; //$NON-NLS-1$
+ static final String TAG_WARNING_FILTER_ACTION = "warningFilterAction"; //$NON-NLS-1$
+ static final String TAG_INFO_FILTER_ACTION = "infoFilterAction"; //$NON-NLS-1$
+
+ // Messages Viewer actions
+ Action messagesOrderingAction;
+ Action errorFilterAction;
+ Action warningFilterAction;
+ Action infoFilterAction;
+
+
+ public ResultsPanel(Composite parent, TestingSessionsManager sessionsManager, IWorkbench workbench, IViewSite site, Clipboard clipboard) {
+ sashForm = new SashForm(parent, SWT.VERTICAL);
+
+ // Configure tests hierarchy viewer
+ ViewForm top = new ViewForm(sashForm, SWT.NONE);
+ Composite empty = new Composite(top, SWT.NONE);
+ empty.setLayout(new Layout() {
+ @Override
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ return new Point(1, 1); // (0, 0) does not work with super-intelligent ViewForm
+ }
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {}
+ });
+ top.setTopLeft(empty); // makes ViewForm draw the horizontal separator line ...
+ testsHierarchyViewer = new TestsHierarchyViewer(top, site, clipboard);
+ top.setContent(testsHierarchyViewer.getTreeViewer().getControl());
+
+ // Configure test messages viewer
+ ViewForm bottom = new ViewForm(sashForm, SWT.NONE);
+ messagesViewer = new MessagesViewer(bottom, sessionsManager, workbench, site, clipboard);
+ Composite topLeftPanel = new Composite(bottom, SWT.NONE);
+ RowLayout topLeftPanelLayout = new RowLayout(SWT.HORIZONTAL);
+ topLeftPanelLayout.spacing = 0;
+ topLeftPanelLayout.center = true;
+ topLeftPanelLayout.marginBottom = topLeftPanelLayout.marginLeft = topLeftPanelLayout.marginRight = topLeftPanelLayout.marginTop = 0;
+ topLeftPanel.setLayout(topLeftPanelLayout);
+ ToolBar leftMessagesToolBar = new ToolBar(topLeftPanel, SWT.FLAT | SWT.WRAP);
+ ToolBarManager leftMessagesToolBarManager = new ToolBarManager(leftMessagesToolBar);
+ messagesOrderingAction = new MessagesOrderingAction(messagesViewer);
+ leftMessagesToolBarManager.add(messagesOrderingAction);
+ leftMessagesToolBarManager.update(true);
+ CLabel label = new CLabel(topLeftPanel, SWT.NONE);
+ label.setText(UIViewMessages.MessagesPanel_label);
+ bottom.setTopLeft(topLeftPanel);
+ ToolBar rightMessagesToolBar = new ToolBar(bottom, SWT.FLAT | SWT.WRAP);
+ ToolBarManager rightMessagesToolBarManager = new ToolBarManager(rightMessagesToolBar);
+ errorFilterAction = new MessageLevelFilterAction(messagesViewer, LevelFilter.Error, true);
+ warningFilterAction = new MessageLevelFilterAction(messagesViewer, LevelFilter.Warning, true);
+ infoFilterAction = new MessageLevelFilterAction(messagesViewer, LevelFilter.Info, false);
+ rightMessagesToolBarManager.add(errorFilterAction);
+ rightMessagesToolBarManager.add(warningFilterAction);
+ rightMessagesToolBarManager.add(infoFilterAction);
+ rightMessagesToolBarManager.update(true);
+ bottom.setTopCenter(rightMessagesToolBar);
+ bottom.setContent(messagesViewer.getTableViewer().getControl());
+
+ sashForm.setWeights(new int[]{50, 50});
+
+ testsHierarchyViewer.getTreeViewer().addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ handleTestItemSelected();
+ }
+ });
+
+ // Initialize default value
+ setShowFailedOnly(false);
+
+ // Data for parent (view's) layout
+ sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
+ }
+
+ /**
+ * Provides access to the tests hierarchy viewer.
+ *
+ * @return tests hierarchy viewer
+ */
+ public TestsHierarchyViewer getTestsHierarchyViewer() {
+ return testsHierarchyViewer;
+ }
+
+ /**
+ * Provides access to the messages viewer.
+ *
+ * @return messages viewer
+ */
+ public MessagesViewer getMessagesViewer() {
+ return messagesViewer;
+ }
+
+ /**
+ * Handles selection change in tests hierarchy viewer and updates the
+ * content of the messages viewer to show the messages for the selected
+ * items.
+ */
+ private void handleTestItemSelected() {
+ IStructuredSelection selection = (IStructuredSelection)testsHierarchyViewer.getTreeViewer().getSelection();
+ ITestItem[] testItems = new ITestItem[selection.size()];
+ int index = 0;
+ for (Iterator<?> it = selection.iterator(); it.hasNext();) {
+ testItems[index] = (ITestItem)it.next();
+ ++index;
+ }
+ messagesViewer.showItemsMessages(testItems);
+ }
+
+ /**
+ * Sets the widget orientation.
+ *
+ * @param orientation new widget orientation (vertical or horizontal; auto
+ * is not supported)
+ */
+ public void setPanelOrientation(ResultsView.Orientation orientation) {
+ sashForm.setOrientation(orientation == ResultsView.Orientation.Horizontal ? SWT.HORIZONTAL : SWT.VERTICAL);
+ }
+
+ /**
+ * Returns whether only failed tests (and messages for them) should be
+ * shown.
+ *
+ * @return filter state
+ */
+ public boolean getShowFailedOnly() {
+ return messagesViewer.getShowFailedOnly();
+ }
+
+ /**
+ * Sets whether only failed tests (and messages for them) should be shown.
+ *
+ * @param showFailedOnly new filter state
+ */
+ public void setShowFailedOnly(boolean showFailedOnly) {
+ testsHierarchyViewer.setShowFailedOnly(showFailedOnly);
+ messagesViewer.setShowFailedOnly(showFailedOnly);
+ }
+
+ /**
+ * Restores the value of the checkable action.
+ *
+ * @param memento previously saved state to restore the action value from
+ * @param key tag name that is used to restore the value
+ * @param action action to restore
+ */
+ private void restoreActionChecked(IMemento memento, String key, Action action) {
+ Boolean checked = memento.getBoolean(key);
+ if (checked != null) {
+ action.setChecked(checked);
+ action.run();
+ }
+ }
+
+ /**
+ * Restores the state of the widget.
+ *
+ * @param memento previously saved state
+ */
+ public void restoreState(IMemento memento) {
+ Integer weight0 = memento.getInteger(TAG_WEIGHT0);
+ Integer weight1 = memento.getInteger(TAG_WEIGHT1);
+ if (weight0 != null && weight1 != null) {
+ sashForm.setWeights(new int[] {weight0, weight1});
+ }
+ restoreActionChecked(memento, TAG_MESSAGES_ORDERING_ACTION, messagesOrderingAction);
+ restoreActionChecked(memento, TAG_ERROR_FILTER_ACTION, errorFilterAction);
+ restoreActionChecked(memento, TAG_WARNING_FILTER_ACTION, warningFilterAction);
+ restoreActionChecked(memento, TAG_INFO_FILTER_ACTION, infoFilterAction);
+ }
+
+ /**
+ * Saves the state of the widget.
+ *
+ * @param memento where to save the state
+ */
+ public void saveState(IMemento memento) {
+ int[] weights = sashForm.getWeights();
+ memento.putInteger(TAG_WEIGHT0, weights[0]);
+ memento.putInteger(TAG_WEIGHT1, weights[1]);
+ memento.putBoolean(TAG_MESSAGES_ORDERING_ACTION, messagesOrderingAction.isChecked());
+ memento.putBoolean(TAG_ERROR_FILTER_ACTION, errorFilterAction.isChecked());
+ memento.putBoolean(TAG_WARNING_FILTER_ACTION, warningFilterAction.isChecked());
+ memento.putBoolean(TAG_INFO_FILTER_ACTION, infoFilterAction.isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsView.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsView.java
new file mode 100644
index 0000000000..585cf84e80
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/ResultsView.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.HistoryDropDownAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.RerunAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ScrollLockAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowFailedOnlyAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowFileNameOnlyAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowNextFailureAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowPreviousFailureAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowTestsInHierarchyAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ShowTimeAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.StopAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.ToggleOrientationAction;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * Represents a view part showing the testing results (count statistics,
+ * red/green bar, tests hierarchy and test messages).
+ */
+public class ResultsView extends ViewPart {
+
+ /**
+ * Represents view orientation
+ *
+ * @note <code>Auto</code> state may be not acceptable for some methods (see
+ * their comments for details).
+ */
+ public enum Orientation {
+ Horizontal,
+ Vertical,
+ Auto,
+ }
+
+ /** View parent. */
+ private Composite parent;
+
+ /** Child widget: statistics viewer. */
+ private ProgressCountPanel progressCountPanel;
+
+ /** Tests hierarchy and message viewer. */
+ private ResultsPanel resultsPanel;
+
+ /** User interface updater instance. */
+ private UIUpdater uiUpdater;
+
+ /** The reference to the testing sessions manager instance. */
+ private TestingSessionsManager sessionsManager;
+
+ /** Shows whether the results view was disposed. */
+ private boolean isDisposed = false;
+
+ // Toolbar & view menu actions
+ private Action nextAction;
+ private Action previousAction;
+ private Action rerunAction;
+ private Action stopAction;
+ private ToggleOrientationAction[] toggleOrientationActions;
+ private Action historyAction;
+ private Action showFailedOnly;
+ private Action showTestsInHierarchyAction;
+ private Action showTimeAction;
+ private Action scrollLockAction;
+ private Action showFileNameOnlyAction;
+
+ /**
+ * The current orientation preference (Horizontal, Vertical, Auto).
+ */
+ private Orientation orientation = Orientation.Auto;
+
+ /**
+ * The current view orientation (Horizontal or Vertical).
+ */
+ private Orientation currentOrientation;
+
+ /**
+ * Previously saved state. It is used to store the same state if the view
+ * was not opened.
+ */
+ private IMemento memento;
+
+ // Persistence tags
+ static final String TAG_ORIENTATION = "orientation"; //$NON-NLS-1$
+ static final String TAG_SHOW_FAILED_ONLY = "showFailedOnly"; //$NON-NLS-1$
+ static final String TAG_SHOW_TESTS_IN_HIERARCHY = "showTestsInHierarchy"; //$NON-NLS-1$
+ static final String TAG_SHOW_TIME = "showTime"; //$NON-NLS-1$
+ static final String TAG_SCROLL_LOCK = "scrollLock"; //$NON-NLS-1$
+ static final String TAG_SHOW_FILE_NAME_ONLY_ACTION = "showFileNameOnly"; //$NON-NLS-1$
+ static final String TAG_HISTORY_SIZE = "history_size"; //$NON-NLS-1$
+
+
+ @Override
+ public void createPartControl(Composite parent) {
+ sessionsManager = TestsRunnerPlugin.getDefault().getTestingSessionsManager();
+ IWorkbench workbench = TestsRunnerPlugin.getDefault().getWorkbench();
+ Clipboard clipboard = new Clipboard(parent.getDisplay());
+
+ this.parent = parent;
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.marginWidth = 0;
+ gridLayout.marginHeight = 0;
+ parent.setLayout(gridLayout);
+ currentOrientation = getActualOrientation();
+
+ progressCountPanel = new ProgressCountPanel(parent, currentOrientation);
+ resultsPanel = new ResultsPanel(parent, sessionsManager, workbench, getViewSite(), clipboard);
+ uiUpdater = new UIUpdater(this, resultsPanel.getTestsHierarchyViewer(), progressCountPanel, sessionsManager);
+ configureActionsBars();
+
+ parent.addControlListener(new ControlListener() {
+ @Override
+ public void controlMoved(ControlEvent e) {
+ }
+ @Override
+ public void controlResized(ControlEvent e) {
+ computeOrientation();
+ }
+ });
+
+ restoreState(memento);
+ uiUpdater.reapplyActiveSession();
+ }
+
+ @Override
+ public void setFocus() {
+ resultsPanel.getTestsHierarchyViewer().getTreeViewer().getControl().setFocus();
+ }
+
+ /**
+ * Configures the view tool bar and menu.
+ */
+ private void configureActionsBars() {
+ IActionBars actionBars = getViewSite().getActionBars();
+
+ // Create common action
+ toggleOrientationActions = new ToggleOrientationAction[] {
+ new ToggleOrientationAction(this, Orientation.Vertical),
+ new ToggleOrientationAction(this, Orientation.Horizontal),
+ new ToggleOrientationAction(this, Orientation.Auto),
+ };
+
+ nextAction = new ShowNextFailureAction(resultsPanel.getTestsHierarchyViewer());
+ nextAction.setEnabled(false);
+ actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), nextAction);
+
+ previousAction = new ShowPreviousFailureAction(resultsPanel.getTestsHierarchyViewer());
+ previousAction.setEnabled(false);
+ actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), previousAction);
+
+ showFailedOnly = new ShowFailedOnlyAction(resultsPanel);
+ showTestsInHierarchyAction = new ShowTestsInHierarchyAction(resultsPanel.getTestsHierarchyViewer());
+ showTimeAction = new ShowTimeAction(resultsPanel.getTestsHierarchyViewer());
+ scrollLockAction = new ScrollLockAction(uiUpdater);
+ showFileNameOnlyAction = new ShowFileNameOnlyAction(resultsPanel.getMessagesViewer());
+ rerunAction = new RerunAction(sessionsManager);
+ rerunAction.setEnabled(false);
+ stopAction = new StopAction(sessionsManager);
+ stopAction.setEnabled(false);
+
+ historyAction = new HistoryDropDownAction(sessionsManager, parent.getShell());
+
+ // Configure toolbar
+ IToolBarManager toolBar = actionBars.getToolBarManager();
+ toolBar.add(nextAction);
+ toolBar.add(previousAction);
+ toolBar.add(showFailedOnly);
+ toolBar.add(scrollLockAction);
+ toolBar.add(new Separator());
+ toolBar.add(rerunAction);
+ toolBar.add(stopAction);
+ toolBar.add(historyAction);
+
+ // Configure view menu
+ IMenuManager viewMenu = actionBars.getMenuManager();
+ viewMenu.add(showTestsInHierarchyAction);
+ viewMenu.add(showTimeAction);
+ viewMenu.add(new Separator());
+ MenuManager layoutSubMenu = new MenuManager(UIViewMessages.ResultsView_layout_menu_text);
+ for (int i = 0; i < toggleOrientationActions.length; ++i) {
+ layoutSubMenu.add(toggleOrientationActions[i]);
+ }
+ viewMenu.add(layoutSubMenu);
+ viewMenu.add(new Separator());
+ viewMenu.add(showFailedOnly);
+ viewMenu.add(showFileNameOnlyAction);
+ }
+
+ @Override
+ public void dispose() {
+ isDisposed = true;
+ if (uiUpdater != null) {
+ uiUpdater.dispose();
+ }
+ }
+
+ /**
+ * Changes the view orientation
+ *
+ * @param orientation new view orientation (Horizontal, Vertical, Auto)
+ */
+ public void setOrientation(Orientation orientation) {
+ this.orientation = orientation;
+ computeOrientation();
+ }
+
+ /**
+ * Checks whether actual orientation is changed and changes orientation of
+ * the child widgets.
+ */
+ private void computeOrientation() {
+ Orientation newActualOrientation = getActualOrientation();
+ if (newActualOrientation != currentOrientation) {
+ currentOrientation = newActualOrientation;
+ progressCountPanel.setPanelOrientation(currentOrientation);
+ resultsPanel.setPanelOrientation(currentOrientation);
+ for (int i = 0; i < toggleOrientationActions.length; ++i) {
+ toggleOrientationActions[i].setChecked(orientation == toggleOrientationActions[i].getOrientation());
+ }
+ parent.layout();
+ }
+ }
+
+ /**
+ * Recalculates actual view orientation depending on the specified by user
+ * orientation value and current view size.
+ *
+ * @param orientation by user specified orientation
+ * @return actual orientation
+ */
+ private Orientation getActualOrientation() {
+ switch (orientation) {
+ case Horizontal:
+ case Vertical:
+ return orientation;
+ case Auto:
+ Point size = parent.getSize();
+ return (size.x > size.y) ? Orientation.Horizontal : Orientation.Vertical;
+ }
+ return null;
+ }
+
+ /**
+ * Updates view actions state from the active session.
+ */
+ public void updateActionsFromSession() {
+ ITestingSession session = sessionsManager.getActiveSession();
+ boolean hasErrors = session != null && session.hasErrors();
+ previousAction.setEnabled(hasErrors);
+ nextAction.setEnabled(hasErrors);
+ rerunAction.setEnabled(session != null && session.isFinished());
+ stopAction.setEnabled(session != null && !session.isFinished());
+ }
+
+ /**
+ * Changes the view caption.
+ *
+ * @param message new view caption
+ */
+ public void setCaption(String message) {
+ setContentDescription(message);
+ }
+
+ @Override
+ public void init(IViewSite site, IMemento memento) throws PartInitException {
+ super.init(site, memento);
+ this.memento = memento;
+ }
+
+ /**
+ * Restores the value of the checkable action.
+ *
+ * @param memento previously saved state to restore the action value from
+ * @param key tag name that is used to restore the value
+ * @param action action to restore
+ */
+ private void restoreActionChecked(IMemento memento, String key, Action action) {
+ Boolean checked = memento.getBoolean(key);
+ if (checked != null) {
+ action.setChecked(checked);
+ action.run();
+ }
+ }
+
+ /**
+ * Restores the state of the view.
+ *
+ * @param memento previously saved state
+ */
+ private void restoreState(IMemento memento) {
+ if (memento != null) {
+ Integer orientationIndex = memento.getInteger(TAG_ORIENTATION);
+ if (orientationIndex != null) {
+ setOrientation(Orientation.values()[orientationIndex]);
+ }
+ resultsPanel.restoreState(memento);
+ restoreActionChecked(memento, TAG_SHOW_FAILED_ONLY, showFailedOnly);
+ restoreActionChecked(memento, TAG_SHOW_TESTS_IN_HIERARCHY, showTestsInHierarchyAction);
+ restoreActionChecked(memento, TAG_SHOW_TIME, showTimeAction);
+ restoreActionChecked(memento, TAG_SCROLL_LOCK, scrollLockAction);
+ restoreActionChecked(memento, TAG_SHOW_FILE_NAME_ONLY_ACTION, showFileNameOnlyAction);
+ Integer historySize = memento.getInteger(TAG_HISTORY_SIZE);
+ if (historySize != null) {
+ sessionsManager.setHistorySizeLimit(historySize);
+ }
+ }
+ }
+
+ @Override
+ public void saveState(IMemento memento) {
+ //Keep the old state;
+ if (parent == null) {
+ if (this.memento != null) {
+ memento.putMemento(this.memento);
+ }
+ return;
+ }
+
+ memento.putInteger(TAG_ORIENTATION, orientation.ordinal());
+ resultsPanel.saveState(memento);
+ memento.putBoolean(TAG_SHOW_FAILED_ONLY, showFailedOnly.isChecked());
+ memento.putBoolean(TAG_SHOW_TESTS_IN_HIERARCHY, showTestsInHierarchyAction.isChecked());
+ memento.putBoolean(TAG_SHOW_TIME, showTimeAction.isChecked());
+ memento.putBoolean(TAG_SCROLL_LOCK, scrollLockAction.isChecked());
+ memento.putBoolean(TAG_SHOW_FILE_NAME_ONLY_ACTION, showFileNameOnlyAction.isChecked());
+ memento.putInteger(TAG_HISTORY_SIZE, sessionsManager.getHistorySizeLimit());
+ }
+
+ /**
+ * Returns whether the view was disposed.
+ *
+ * @return true if the view was disposed
+ */
+ public boolean isDisposed() {
+ return isDisposed;
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestPathUtils.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestPathUtils.java
new file mode 100644
index 0000000000..512754435a
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestPathUtils.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+
+/**
+ * The utilities collection to work with the test paths for items in test
+ * hierarchy.
+ */
+public class TestPathUtils {
+
+ /**
+ * The delimiter between parts of serialized test path. Should not be met in
+ * test paths names.
+ */
+ private static final String TEST_PATH_PART_DELIMITER = "\n"; //$NON-NLS-1$
+
+ /** The delimiter between parts of human readable test path. */
+ private static final String TEST_PATH_DELIMITER = "."; //$NON-NLS-1$
+
+ /**
+ * Returns the human readable path to the item in test hierarchy (e.g.
+ * MySuite.MyInnerSuite.MyTest1).
+ *
+ * @param testItem test item (test suite or test case)
+ *
+ * @return path to test item
+ */
+ public static String getTestItemPath(ITestItem testItem) {
+ StringBuilder itemPath = new StringBuilder();
+ List<ITestItem> parentItems = new ArrayList<ITestItem>();
+ while (testItem != null) {
+ parentItems.add(testItem);
+ testItem = testItem.getParent();
+ }
+ if (!parentItems.isEmpty()) {
+ for (int i = parentItems.size()-2/* exclude unnamed root test suite */; i >= 0; --i) {
+ itemPath.append(parentItems.get(i).getName());
+ if (i != 0) {
+ itemPath.append(TEST_PATH_DELIMITER);
+ }
+ }
+ }
+ return itemPath.toString();
+ }
+
+ /**
+ * Unpack the paths from the string list.
+ *
+ * @param testPaths packed test paths
+ * @return array of test paths
+ *
+ * @see packTestPaths()
+ */
+ public static String[][] unpackTestPaths(String[] testPaths) {
+ String [][] result = new String[testPaths.length][];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = testPaths[i].split(TEST_PATH_PART_DELIMITER);
+ }
+ return result;
+ }
+
+ /**
+ * Pack the paths to specified test items to string list.
+ *
+ * @param testItems test items to pack
+ * @return string list
+ *
+ * @see unpackTestPaths()
+ */
+ public static String[] packTestPaths(ITestItem[] testItems) {
+ String [] result = new String[testItems.length];
+ List<String> testPath = new ArrayList<String>();
+
+ for (int itemIdx = 0; itemIdx < testItems.length; itemIdx++) {
+ // Collect test path parts (in reverse order)
+ testPath.clear();
+ ITestItem item = testItems[itemIdx];
+ while (item != null) {
+ // Exclude root test suite
+ if (item.getParent()!= null) {
+ testPath.add(item.getName());
+ }
+ item = item.getParent();
+ }
+ // Join path parts into the only string
+ StringBuilder sb = new StringBuilder();
+ boolean needDelimiter = false;
+ for (int pathPartIdx = testPath.size()-1; pathPartIdx >= 0; pathPartIdx--) {
+ if (needDelimiter) {
+ sb.append(TEST_PATH_PART_DELIMITER);
+ } else {
+ needDelimiter = true;
+ }
+ sb.append(testPath.get(pathPartIdx));
+ }
+ result[itemIdx] = sb.toString();
+ }
+ return result;
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestsHierarchyViewer.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestsHierarchyViewer.java
new file mode 100644
index 0000000000..117a7b3bee
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/TestsHierarchyViewer.java
@@ -0,0 +1,554 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.internal.ui.viewsupport.ColoringLabelProvider;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.CopySelectedTestsAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.RedebugSelectedAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.RelaunchSelectedAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.RerunSelectedAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.TestsHierarchyCollapseAllAction;
+import org.eclipse.cdt.testsrunner.internal.ui.view.actions.TestsHierarchyExpandAllAction;
+import org.eclipse.cdt.testsrunner.model.IModelVisitor;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StyledCellLabelProvider;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.actions.ActionFactory;
+
+/**
+ * Shows the tests hierarchy in a flat or hierarchical view.
+ */
+public class TestsHierarchyViewer {
+
+ /**
+ * The content provider for the tests hierarchy viewer.
+ */
+ private class TestTreeContentProvider implements ITreeContentProvider {
+
+ /**
+ * Utility class: recursively collects all the test cases of the
+ * specified test item.
+ *
+ * It is used for flat view of tests hierarchy.
+ */
+ private class TestCasesCollector implements IModelVisitor {
+
+ public List<ITestCase> testCases = new ArrayList<ITestCase>();
+
+ @Override
+ public void visit(ITestCase testCase) {
+ testCases.add(testCase);
+ }
+
+ @Override
+ public void visit(ITestMessage testMessage) {}
+ @Override
+ public void visit(ITestSuite testSuite) {}
+ @Override
+ public void leave(ITestSuite testSuite) {}
+ @Override
+ public void leave(ITestCase testCase) {}
+ @Override
+ public void leave(ITestMessage testMessage) {}
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ return ((ITestItem) parentElement).getChildren();
+ }
+
+ @Override
+ public Object[] getElements(Object rootTestSuite) {
+ if (showTestsHierarchy) {
+ return getChildren(rootTestSuite);
+ } else {
+ TestCasesCollector testCasesCollector = new TestCasesCollector();
+ ((ITestItem)rootTestSuite).visit(testCasesCollector);
+ return testCasesCollector.testCases.toArray();
+ }
+ }
+
+ @Override
+ public Object getParent(Object object) {
+ return ((ITestItem) object).getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object object) {
+ return ((ITestItem) object).hasChildren();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
+
+ @Override
+ public void dispose() {}
+ }
+
+ /**
+ * The label provider for the tests hierarchy viewer.
+ */
+ private class TestLabelProvider extends LabelProvider implements IStyledLabelProvider {
+
+ /** Images for the test cases with the different statuses. */
+ private Map<ITestItem.Status, Image> testCaseImages = new HashMap<ITestItem.Status, Image>();
+ {
+ testCaseImages.put(ITestItem.Status.NotRun, TestsRunnerPlugin.createAutoImage("obj16/test_notrun.gif")); //$NON-NLS-1$
+ testCaseImages.put(ITestItem.Status.Skipped, TestsRunnerPlugin.createAutoImage("obj16/test_skipped.gif")); //$NON-NLS-1$
+ testCaseImages.put(ITestItem.Status.Passed, TestsRunnerPlugin.createAutoImage("obj16/test_passed.gif")); //$NON-NLS-1$
+ testCaseImages.put(ITestItem.Status.Failed, TestsRunnerPlugin.createAutoImage("obj16/test_failed.gif")); //$NON-NLS-1$
+ testCaseImages.put(ITestItem.Status.Aborted, TestsRunnerPlugin.createAutoImage("obj16/test_aborted.gif")); //$NON-NLS-1$
+ }
+
+ /** Running test case image (overrides the test case status image). */
+ private Image testCaseRunImage = TestsRunnerPlugin.createAutoImage("obj16/test_run.gif"); //$NON-NLS-1$
+
+ /** Images for the test suites with the different statuses. */
+ private Map<ITestItem.Status, Image> testSuiteImages = new HashMap<ITestItem.Status, Image>();
+ {
+ // NOTE: There is no skipped-icon for test suite, but it seems it is not a problem
+ testSuiteImages.put(ITestItem.Status.NotRun, TestsRunnerPlugin.createAutoImage("obj16/tsuite_notrun.gif")); //$NON-NLS-1$
+ testSuiteImages.put(ITestItem.Status.Skipped, TestsRunnerPlugin.createAutoImage("obj16/tsuite_notrun.gif")); //$NON-NLS-1$
+ testSuiteImages.put(ITestItem.Status.Passed, TestsRunnerPlugin.createAutoImage("obj16/tsuite_passed.gif")); //$NON-NLS-1$
+ testSuiteImages.put(ITestItem.Status.Failed, TestsRunnerPlugin.createAutoImage("obj16/tsuite_failed.gif")); //$NON-NLS-1$
+ testSuiteImages.put(ITestItem.Status.Aborted, TestsRunnerPlugin.createAutoImage("obj16/tsuite_aborted.gif")); //$NON-NLS-1$
+ }
+
+ /** Running test suite image (overrides the test suite status image). */
+ private Image testSuiteRunImage = TestsRunnerPlugin.createAutoImage("obj16/tsuite_run.gif"); //$NON-NLS-1$
+
+ /** Small optimization: the last test item cache */
+ private ITestItem lastTestItemCache = null;
+
+ /** Small optimization: test path for the last test item is cache */
+ private String lastTestItemPathCache = null;
+
+
+ @Override
+ public Image getImage(Object element) {
+ Map<ITestItem.Status, Image> imagesMap = null;
+ Image runImage = null;
+ if (element instanceof ITestCase) {
+ imagesMap = testCaseImages;
+ runImage = testCaseRunImage;
+
+ } else if (element instanceof ITestSuite) {
+ imagesMap = testSuiteImages;
+ runImage = testSuiteRunImage;
+ }
+ if (imagesMap != null) {
+ ITestItem testItem = (ITestItem)element;
+ if (testingSession.getModelAccessor().isCurrentlyRunning(testItem)) {
+ return runImage;
+ }
+ return imagesMap.get(testItem.getStatus());
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getText(Object element) {
+ ITestItem testItem = (ITestItem)element;
+ StringBuilder sb = new StringBuilder();
+ sb.append(testItem.getName());
+ if (!showTestsHierarchy) {
+ appendTestItemPath(sb, testItem);
+ }
+ if (showTime) {
+ sb.append(getTestingTimeString(element));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public StyledString getStyledText(Object element) {
+ ITestItem testItem = (ITestItem)element;
+ StringBuilder labelBuf = new StringBuilder();
+ labelBuf.append(testItem.getName());
+ StyledString name = new StyledString(labelBuf.toString());
+ if (!showTestsHierarchy) {
+ appendTestItemPath(labelBuf, testItem);
+ name = StyledCellLabelProvider.styleDecoratedString(labelBuf.toString(), StyledString.QUALIFIER_STYLER, name);
+ }
+ if (showTime) {
+ String time = getTestingTimeString(element);
+ labelBuf.append(time);
+ name = StyledCellLabelProvider.styleDecoratedString(labelBuf.toString(), StyledString.COUNTER_STYLER, name);
+ }
+ return name;
+ }
+
+ /**
+ * Appends path to the parent of the specified test item. Also
+ * implements caching of the last path (cause the test item parent is
+ * often the same).
+ *
+ * @param sb string builder to append test item path to
+ * @param testItem specified test item
+ */
+ private void appendTestItemPath(StringBuilder sb, ITestItem testItem) {
+ ITestSuite testItemParent = testItem.getParent();
+ if (lastTestItemCache != testItemParent) {
+ lastTestItemCache = testItemParent;
+ lastTestItemPathCache = TestPathUtils.getTestItemPath(lastTestItemCache);
+ }
+ sb.append(MessageFormat.format(
+ UIViewMessages.TestsHierarchyViewer_test_path_format,
+ new Object[] { lastTestItemPathCache }
+ ));
+ }
+
+ /**
+ * Returns the execution time suffix for the test item.
+ *
+ * @param element test item
+ * @return execution time suffix
+ */
+ private String getTestingTimeString(Object element) {
+ return (element instanceof ITestItem)
+ ? MessageFormat.format(UIViewMessages.TestsHierarchyViewer_test_time_format, Double.toString(((ITestItem)element).getTestingTime()/1000.0))
+ : ""; //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Filters passed test cases and test suites.
+ */
+ private class FailedOnlyFilter extends ViewerFilter {
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ return ((ITestItem)element).getStatus().isError();
+ }
+ }
+
+ /** Testing session to show hierarchy of. */
+ private ITestingSession testingSession;
+
+ /** Main widget. */
+ private TreeViewer treeViewer;
+
+ /** Specifies whether test items execution time should be shown in hierarchy. */
+ private boolean showTime = true;
+
+ /** Specifies whether tests hierarchy should be shown in flat or hierarchical view. */
+ private boolean showTestsHierarchy = true;
+
+ /** Failed only tree filter instance. Created on first demand. */
+ private FailedOnlyFilter failedOnlyFilter = null;
+
+ /** System clipboard access to provide copy operations. */
+ private Clipboard clipboard;
+
+ // Context menu actions
+ private Action expandAllAction;
+ private Action collapseAllAction;
+ private Action copyAction;
+ private RelaunchSelectedAction rerunAction;
+ private RelaunchSelectedAction redebugAction;
+
+
+ public TestsHierarchyViewer(Composite parent, IViewSite viewSite, Clipboard clipboard) {
+ this.clipboard = clipboard;
+ treeViewer = new TreeViewer(parent, SWT.V_SCROLL | SWT.MULTI);
+ treeViewer.setContentProvider(new TestTreeContentProvider());
+ treeViewer.setLabelProvider(new ColoringLabelProvider(new TestLabelProvider()));
+ initContextMenu(viewSite);
+ }
+
+ /**
+ * Initializes the viewer context menu.
+ *
+ * @param viewSite view
+ */
+ private void initContextMenu(IViewSite viewSite) {
+ expandAllAction = new TestsHierarchyExpandAllAction(treeViewer);
+ collapseAllAction = new TestsHierarchyCollapseAllAction(treeViewer);
+ copyAction = new CopySelectedTestsAction(treeViewer, clipboard);
+ rerunAction = new RerunSelectedAction(testingSession, treeViewer);
+ redebugAction = new RedebugSelectedAction(testingSession, treeViewer);
+
+ MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+ menuMgr.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager) {
+ handleMenuAboutToShow(manager);
+ }
+ });
+ viewSite.registerContextMenu(menuMgr, treeViewer);
+ Menu menu = menuMgr.createContextMenu(treeViewer.getTree());
+ treeViewer.getTree().setMenu(menu);
+
+ menuMgr.add(copyAction);
+ menuMgr.add(new Separator());
+ menuMgr.add(rerunAction);
+ menuMgr.add(redebugAction);
+ menuMgr.add(new Separator());
+ menuMgr.add(expandAllAction);
+ menuMgr.add(collapseAllAction);
+
+ IActionBars actionBars = viewSite.getActionBars();
+ actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
+ actionBars.updateActionBars();
+ }
+
+ /**
+ * Handles the context menu showing.
+ *
+ * @param manager context menu manager
+ */
+ private void handleMenuAboutToShow(IMenuManager manager) {
+ IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
+ boolean isRelaunchEnabledForSelection = !selection.isEmpty() &&
+ (testingSession.getTestsRunnerProviderInfo().isAllowedMultipleTestFilter() || (selection.size() == 1));
+ rerunAction.setEnabled(isRelaunchEnabledForSelection);
+ rerunAction.setTestingSession(testingSession);
+ redebugAction.setEnabled(isRelaunchEnabledForSelection);
+ redebugAction.setTestingSession(testingSession);
+ copyAction.setEnabled(!selection.isEmpty());
+
+ boolean hasAnything = treeViewer.getInput() != null;
+ expandAllAction.setEnabled(hasAnything);
+ collapseAllAction.setEnabled(hasAnything);
+ }
+
+ /**
+ * Sets the testing session to show.
+ *
+ * @param testingSession testing session or null to set default empty
+ * session
+ */
+ public void setTestingSession(ITestingSession testingSession) {
+ this.testingSession = testingSession;
+ treeViewer.setInput(testingSession != null ? testingSession.getModelAccessor().getRootSuite() : null);
+ }
+
+ /**
+ * Provides access to the main widget of the tests hierarchy viewer.
+ *
+ * @return main widget of the tests hierarchy viewer
+ */
+ public TreeViewer getTreeViewer() {
+ return treeViewer;
+ }
+
+ /**
+ * Move the selection to the next failed test case.
+ */
+ public void showNextFailure() {
+ showFailure(true);
+ }
+
+ /**
+ * Move the selection to the previous failed test case.
+ */
+ public void showPreviousFailure() {
+ showFailure(false);
+ }
+
+ /**
+ * Common implementation for movement the selection to the next or previous
+ * failed test case.
+ *
+ * @param next true if the next failed test case should be selected and false otherwise
+ */
+ private void showFailure(boolean next) {
+ IStructuredSelection selection = (IStructuredSelection) getTreeViewer().getSelection();
+ ITestItem selected = (ITestItem) selection.getFirstElement();
+ ITestItem failedItem;
+
+ if (selected == null) {
+ ITestItem rootSuite = (ITestItem)treeViewer.getInput();
+ // For next element we should also check its children, for previous shouldn't.
+ failedItem = findFailedImpl(rootSuite, null, next, next);
+ } else {
+ // For next element we should also check its children, for previous shouldn't.
+ failedItem = findFailedImpl(selected.getParent(), selected, next, next);
+ }
+
+ if (failedItem != null)
+ getTreeViewer().setSelection(new StructuredSelection(failedItem), true);
+ }
+
+ /**
+ * Returns the next or previous failed test case relatively to the
+ * <code>currItem</code> that should be a child of <code>parentItem</code>.
+ * If the such item was not found through the children, it steps up to the
+ * parent and continues search.
+ *
+ * @param parentItem parent test item to the current one
+ * @param currItem current item search should be started from or null if
+ * there is no any
+ * @param next true if the next failed test case should be looked for and
+ * false otherwise
+ * @param checkCurrentChild specifies whether the search should be also
+ * through the children for the current item
+ * @return found item or null
+ */
+ private ITestItem findFailedImpl(ITestItem parentItem, ITestItem currItem, boolean next, boolean checkCurrentChild) {
+ ITestItem result = findFailedChild(parentItem, currItem, next, checkCurrentChild);
+ if (result != null) {
+ return result;
+ }
+ // Nothing found at this level - try to step up
+ ITestSuite grandParentItem = parentItem.getParent();
+ if (grandParentItem != null) {
+ return findFailedImpl(grandParentItem, parentItem, next, false);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the next or previous failed test case relatively to the
+ * <code>currItem</code> that should be a child of <code>parentItem</code>.
+ * Note that unlike <code>findFailedImpl()</code> this method search only
+ * through the children items.
+ *
+ * @param parentItem parent test item to the current one
+ * @param currItem current item search should be started from or null if
+ * there is no any
+ * @param next true if the next failed test case should be looked for and
+ * false otherwise
+ * @param checkCurrentChild specifies whether the search should be also
+ * through the children for the current item
+ * @return found item or null
+ */
+ private ITestItem findFailedChild(ITestItem parentItem, ITestItem currItem, boolean next, boolean checkCurrentChild) {
+ ITestItem[] children = parentItem.getChildren();
+ boolean doSearch = (currItem == null);
+ int increment = next ? 1 : -1;
+ int startIndex = next ? 0 : children.length-1;
+ int endIndex = next ? children.length : -1;
+ for (int index = startIndex; index != endIndex; index += increment) {
+ ITestItem item = children[index];
+ // Check element
+ if (doSearch) {
+ if (item instanceof ITestCase && item.getStatus().isError()) {
+ return item;
+ }
+ }
+ // If children of current element should be checked we should enable search here (if necessary)
+ if (checkCurrentChild && item == currItem) {
+ doSearch = true;
+ }
+ // Search element's children
+ if (doSearch) {
+ ITestItem result = findFailedChild(item, null, next, checkCurrentChild);
+ if (result != null) {
+ return result;
+ }
+ }
+ // If children of current element should NOT be checked we should enable search here
+ if (!checkCurrentChild && item == currItem) {
+ doSearch = true;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether test items execution time should be shown in tests
+ * hierarchy.
+ *
+ * @return true if time should be shown and false otherwise
+ */
+ public boolean showTime() {
+ return showTime;
+ }
+
+ /**
+ * Sets whether test items execution time should be shown in tests
+ * hierarchy. Updates tests hierarchy viewer if the view is changed.
+ *
+ * @param showTime true if time is shown and false otherwise
+ */
+ public void setShowTime(boolean showTime) {
+ if (this.showTime != showTime) {
+ this.showTime = showTime;
+ getTreeViewer().refresh();
+ }
+ }
+
+ /**
+ * Sets whether only failed tests should be shown.
+ *
+ * @param showFailedOnly new filter state
+ */
+ public void setShowFailedOnly(boolean showFailedOnly) {
+ // Create filter on first demand
+ if (failedOnlyFilter == null) {
+ failedOnlyFilter = new FailedOnlyFilter();
+ }
+ if (showFailedOnly) {
+ getTreeViewer().addFilter(failedOnlyFilter);
+ } else {
+ getTreeViewer().removeFilter(failedOnlyFilter);
+ }
+ }
+
+ /**
+ * Returns whether tests hierarchy should be shown in flat or hierarchical
+ * mode.
+ *
+ * @return tests hierarchy view mode
+ */
+ public boolean showTestsHierarchy() {
+ return showTestsHierarchy;
+ }
+
+ /**
+ * Sets whether tests hierarchy should be shown in flat or hierarchical
+ * mode. Updates tests hierarchy viewer if the view is changed.
+ *
+ * @param showTestsHierarchy true if tests hierarchy is shown in
+ * hierarchical mode and false otherwise
+ */
+ public void setShowTestsHierarchy(boolean showTestsHierarchy) {
+ if (this.showTestsHierarchy != showTestsHierarchy) {
+ this.showTestsHierarchy = showTestsHierarchy;
+ getTreeViewer().refresh();
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIUpdater.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIUpdater.java
new file mode 100644
index 0000000000..a6738e0d7e
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIUpdater.java
@@ -0,0 +1,517 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import java.text.MessageFormat;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.testsrunner.internal.model.ITestingSessionsManagerListener;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.cdt.testsrunner.model.ITestingSessionListener;
+import org.eclipse.cdt.testsrunner.model.ITestCase;
+import org.eclipse.cdt.testsrunner.model.ITestSuite;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.progress.UIJob;
+
+/**
+ * Tracks and collects the changes in active testing session and updates the UI
+ * periodically. It allows to significantly improve the UI performance.
+ */
+public class UIUpdater {
+
+ /** Access to the results showing view. */
+ private ResultsView resultsView;
+
+ /** Access to the tests hierarchy showing widget. */
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+ /** Access to the statistics showing widget. */
+ private ProgressCountPanel progressCountPanel;
+
+ /** Listener for the changes in active testing session. */
+ private ITestingSessionListener sessionListener;
+
+ /**
+ * Specifies whether tests hierarchy scrolling should be done during the
+ * testing process.
+ */
+ private boolean autoScroll = true;
+
+ /** Access to the testing sessions manager. */
+ private TestingSessionsManager sessionsManager;
+
+ /** Listener to handle active testing session change. */
+ private TestingSessionsManagerListener sessionsManagerListener;
+
+ /** Reference to the active testing session. */
+ ITestingSession testingSession;
+
+ /** Storage for the UI changes that should be done on update. */
+ UIChangesCache uiChangesCache = new UIChangesCache();
+
+ /** A job that makes an UI update periodically. */
+ UpdateUIJob updateUIJob = null;
+
+ /** Time interval over which the UI should be updated. */
+ private static final int REFRESH_INTERVAL = 200;
+
+
+ /**
+ * Storage for the UI changes that should be done on update.
+ */
+ private class UIChangesCache {
+
+ /**
+ * Specifies whether Progress Counter Panel should be updated during the
+ * next UI update.
+ */
+ private boolean needProgressCountPanelUpdate;
+
+ /**
+ * Specifies whether view actions should be updated during the next UI
+ * update.
+ */
+ private boolean needActionsUpdate;
+
+ /**
+ * A test item which path should be shown as a view caption during the
+ * next UI update.
+ */
+ private ITestItem testItemForNewViewCaption;
+
+ /**
+ * Set of tree objects on which <code>refresh()</code> should be called
+ * during the next UI update.
+ */
+ private Set<Object> treeItemsToRefresh = new HashSet<Object>();
+
+ /**
+ * Set of tree objects on which <code>update()</code> should be called
+ * during the next UI update.
+ */
+ private Set<Object> treeItemsToUpdate = new HashSet<Object>();
+
+ /** Tree object that should be revealed during the next UI update. */
+ private Object treeItemToReveal;
+
+ /** Map of tree objects that should be expanded or collapsed to their new states. */
+ private Map<Object, Boolean> treeItemsToExpand = new LinkedHashMap<Object, Boolean>();
+
+
+ UIChangesCache() {
+ resetChanges();
+ }
+
+ /**
+ * Schedules the Progress Counter Panel update during the next UI update.
+ */
+ public void scheduleProgressCountPanelUpdate() {
+ synchronized (this) {
+ needProgressCountPanelUpdate = true;
+ }
+ }
+
+ /**
+ * Schedules the view actions update during the next UI update.
+ */
+ public void scheduleActionsUpdate() {
+ synchronized (this) {
+ needActionsUpdate = true;
+ }
+ }
+
+ /**
+ * Schedules the view caption update to the path to specified test item
+ * during the next UI update.
+ *
+ * @param testItem specified test item
+ */
+ public void scheduleViewCaptionChange(ITestItem testItem) {
+ synchronized (this) {
+ testItemForNewViewCaption = testItem;
+ }
+ }
+
+ /**
+ * Schedules the <code>update()</code> call for the specified tree
+ * object during the next UI update.
+ *
+ * @param item tree object to update
+ */
+ public void scheduleTreeItemUpdate(Object item) {
+ synchronized (this) {
+ treeItemsToUpdate.add(item);
+ }
+ }
+
+ /**
+ * Schedules the revealing of the specified tree object. Overrides
+ * the previously specified tree object to reveal (if any).
+ *
+ * @param item tree object to reveal
+ */
+ public void scheduleTreeItemReveal(Object item) {
+ synchronized (this) {
+ treeItemToReveal = item;
+ }
+ }
+
+ /**
+ * Schedules the expanding or collapsing of the specified tree object.
+ * Overrides the previous state for the same tree object (if any).
+ *
+ * @param item tree object to expand or collapse
+ * @param expandedState true if the node is expanded, and false if
+ * collapsed
+ */
+ public void scheduleTreeItemExpand(Object item, boolean expandedState) {
+ synchronized (this) {
+ treeItemsToExpand.put(item, expandedState);
+ }
+ }
+
+ /**
+ * Schedules the <code>refresh()</code> call for the specified tree
+ * object during the next UI update.
+ *
+ * @param item tree object to refresh
+ */
+ public void scheduleTreeItemRefresh(Object item) {
+ synchronized (this) {
+ treeItemsToRefresh.add(item);
+ }
+ }
+
+
+ /**
+ * Apply any scheduled changes to UI.
+ */
+ public void applyChanges() {
+ synchronized (this) {
+ TreeViewer treeViewer = testsHierarchyViewer.getTreeViewer();
+ // View statistics widgets update
+ if (needProgressCountPanelUpdate) {
+ progressCountPanel.updateInfoFromSession();
+ }
+ // View actions update
+ if (needActionsUpdate) {
+ resultsView.updateActionsFromSession();
+ }
+ // View caption update
+ if (testItemForNewViewCaption != null) {
+ resultsView.setCaption(
+ MessageFormat.format(
+ UIViewMessages.UIUpdater_view_caption_format,
+ testItemForNewViewCaption.getName(),
+ TestPathUtils.getTestItemPath(testItemForNewViewCaption.getParent())
+ )
+ );
+ }
+ // Tree view update
+ if (!treeItemsToRefresh.isEmpty()) {
+ for (Object item : treeItemsToRefresh) {
+ treeViewer.refresh(item, false);
+ }
+ }
+ if (!treeItemsToUpdate.isEmpty()) {
+ treeViewer.update(treeItemsToUpdate.toArray(), null);
+ }
+ if (treeItemToReveal != null) {
+ treeViewer.reveal(treeItemToReveal);
+ }
+ if (!treeItemsToExpand.isEmpty()) {
+ for (Map.Entry<Object, Boolean> entry : treeItemsToExpand.entrySet()) {
+ treeViewer.setExpandedState(entry.getKey(), entry.getValue());
+ }
+ }
+ // All changes are applied, remove them
+ resetChangesImpl();
+ }
+ }
+
+ /**
+ * Reset all the scheduled changes to UI.
+ */
+ public void resetChanges() {
+ synchronized (this) {
+ resetChangesImpl();
+ }
+ }
+
+ /**
+ * Reset all the scheduled changes to UI. Note, this method is not
+ * synchronized so it should be used carefully
+ */
+ private void resetChangesImpl() {
+ needProgressCountPanelUpdate = false;
+ needActionsUpdate = false;
+ testItemForNewViewCaption = null;
+ treeItemsToUpdate.clear();
+ treeItemToReveal = null;
+ treeItemsToExpand.clear();
+ }
+ }
+
+
+ /**
+ * A job that makes an UI update periodically.
+ */
+ private class UpdateUIJob extends UIJob {
+
+ /** Controls whether the job should be scheduled again. */
+ private boolean isRunning = true;
+
+ public UpdateUIJob() {
+ super(UIViewMessages.UIUpdater_update_ui_job);
+ setSystem(true);
+ }
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (!resultsView.isDisposed()) {
+ uiChangesCache.applyChanges();
+ scheduleSelf();
+ }
+ return Status.OK_STATUS;
+ }
+
+ /**
+ * Schedule self for running after time interval.
+ */
+ public void scheduleSelf() {
+ schedule(REFRESH_INTERVAL);
+ }
+
+ /**
+ * Sets the flag that prevents planning this job again.
+ */
+ public void stop() {
+ isRunning = false;
+ }
+
+ @Override
+ public boolean shouldSchedule() {
+ return isRunning;
+ }
+
+ }
+
+
+ /**
+ * Listener for the changes in active testing session.
+ */
+ private class SessionListener implements ITestingSessionListener {
+
+ /**
+ * Common implementation for test case and test suite entering.
+ *
+ * @param testItem test case or test suite
+ */
+ private void enterTestItem(ITestItem testItem) {
+ uiChangesCache.scheduleViewCaptionChange(testItem);
+ uiChangesCache.scheduleTreeItemUpdate(testItem);
+ if (autoScroll) {
+ uiChangesCache.scheduleTreeItemReveal(testItem);
+ }
+ }
+
+ @Override
+ public void enterTestSuite(ITestSuite testSuite) {
+ enterTestItem(testSuite);
+ }
+
+ @Override
+ public void exitTestSuite(ITestSuite testSuite) {
+ uiChangesCache.scheduleTreeItemUpdate(testSuite);
+ if (autoScroll) {
+ uiChangesCache.scheduleTreeItemExpand(testSuite, false);
+ }
+ }
+
+ @Override
+ public void enterTestCase(ITestCase testCase) {
+ enterTestItem(testCase);
+ }
+
+ @Override
+ public void exitTestCase(ITestCase testCase) {
+ uiChangesCache.scheduleActionsUpdate();
+ uiChangesCache.scheduleProgressCountPanelUpdate();
+ uiChangesCache.scheduleTreeItemUpdate(testCase);
+ }
+
+ @Override
+ public void childrenUpdate(ITestSuite parent) {
+ uiChangesCache.scheduleTreeItemRefresh(parent);
+ }
+
+ @Override
+ public void testingStarted() {
+ resultsView.updateActionsFromSession();
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ resultsView.setCaption(testingSession.getStatusMessage());
+ progressCountPanel.updateInfoFromSession();
+ testsHierarchyViewer.getTreeViewer().refresh();
+ }
+ });
+ startUpdateUIJob();
+ }
+
+ @Override
+ public void testingFinished() {
+ stopUpdateUIJob();
+ resultsView.updateActionsFromSession();
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ uiChangesCache.applyChanges();
+ resultsView.setCaption(testingSession.getStatusMessage());
+ progressCountPanel.updateInfoFromSession();
+ testsHierarchyViewer.getTreeViewer().refresh();
+ testsHierarchyViewer.getTreeViewer().collapseAll();
+ testsHierarchyViewer.getTreeViewer().expandToLevel(2);
+ }
+ });
+ }
+ }
+
+
+ /**
+ * Listener to handle active testing session change.
+ */
+ private class TestingSessionsManagerListener implements ITestingSessionsManagerListener {
+
+ @Override
+ public void sessionActivated(ITestingSession newTestingSession) {
+ if (testingSession != newTestingSession) {
+ stopUpdateUIJob();
+ uiChangesCache.resetChanges();
+
+ unsubscribeFromSessionEvent();
+ testingSession = newTestingSession;
+ subscribeToSessionEvent();
+
+ resultsView.updateActionsFromSession();
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ progressCountPanel.setTestingSession(testingSession);
+ testsHierarchyViewer.setTestingSession(testingSession);
+ resultsView.setCaption(testingSession != null ? testingSession.getStatusMessage() : ""); //$NON-NLS-1$
+ }
+ });
+ if (newTestingSession != null && !newTestingSession.isFinished()) {
+ startUpdateUIJob();
+ }
+ }
+ }
+ }
+
+
+ public UIUpdater(ResultsView resultsView, TestsHierarchyViewer testsHierarchyViewer, ProgressCountPanel progressCountPanel, TestingSessionsManager sessionsManager) {
+ this.resultsView = resultsView;
+ this.testsHierarchyViewer = testsHierarchyViewer;
+ this.progressCountPanel = progressCountPanel;
+ this.sessionsManager = sessionsManager;
+ sessionListener = new SessionListener();
+ sessionsManagerListener = new TestingSessionsManagerListener();
+ sessionsManager.addListener(sessionsManagerListener);
+ }
+
+ /**
+ * Returns whether tests hierarchy scrolling should be done during the
+ * testing process.
+ *
+ * @return auto scroll state
+ */
+ public boolean getAutoScroll() {
+ return autoScroll;
+ }
+
+ /**
+ * Sets whether whether tests hierarchy scrolling should be done during the
+ * testing process.
+ *
+ * @param autoScroll new filter state
+ */
+ public void setAutoScroll(boolean autoScroll) {
+ this.autoScroll = autoScroll;
+ }
+
+ /**
+ * Disposes of the UI Updater. Make the necessary clean up.
+ */
+ public void dispose() {
+ unsubscribeFromSessionEvent();
+ sessionsManager.removeListener(sessionsManagerListener);
+ }
+
+ /**
+ * Subscribes to the events of currently set testing session.
+ */
+ private void subscribeToSessionEvent() {
+ if (testingSession != null) {
+ testingSession.getModelAccessor().addChangesListener(sessionListener);
+ }
+ }
+
+ /**
+ * Unsubscribe from the events of currently set testing session.
+ */
+ private void unsubscribeFromSessionEvent() {
+ if (testingSession != null) {
+ testingSession.getModelAccessor().removeChangesListener(sessionListener);
+ }
+ }
+
+ /**
+ * Starts the UI updating job. Stops the previously running (if any).
+ */
+ private void startUpdateUIJob() {
+ stopUpdateUIJob();
+ uiChangesCache.resetChanges();
+ updateUIJob = new UpdateUIJob();
+ updateUIJob.scheduleSelf();
+ }
+
+ /**
+ * Stops the UI updating job (if any).
+ */
+ private void stopUpdateUIJob() {
+ if (updateUIJob != null) {
+ updateUIJob.stop();
+ updateUIJob = null;
+ }
+ }
+
+ /**
+ * Fakes the testing session activation and makes all necessary steps to
+ * handle it.
+ */
+ public void reapplyActiveSession() {
+ sessionsManagerListener.sessionActivated(sessionsManager.getActiveSession());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.java
new file mode 100644
index 0000000000..9db469e8bf
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view;
+
+import org.eclipse.osgi.util.NLS;
+
+public class UIViewMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.internal.ui.view.UIViewMessages"; //$NON-NLS-1$
+ public static String CounterPanel_tests_erred;
+ public static String CounterPanel_tests_failed;
+ public static String CounterPanel_tests_run;
+ public static String CounterPanel_tests_skipped;
+ public static String MessagesPanel_label;
+ public static String MessagesViewer_location_format;
+ public static String MessagesViewer_message_format;
+ public static String ResultsView_layout_menu_text;
+ public static String TestsHierarchyViewer_test_path_format;
+ public static String TestsHierarchyViewer_test_time_format;
+ public static String UIUpdater_update_ui_job;
+ public static String UIUpdater_view_caption_format;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, UIViewMessages.class);
+ }
+
+ private UIViewMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.properties
new file mode 100644
index 0000000000..f586280fdf
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/UIViewMessages.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+CounterPanel_tests_erred=Errors:
+CounterPanel_tests_failed=Failures:
+CounterPanel_tests_run=Runs:
+CounterPanel_tests_skipped={0} ({1} ignored)
+MessagesPanel_label=Messages
+MessagesViewer_location_format={0}({1}):
+MessagesViewer_message_format={0}{1}: {2}
+ResultsView_layout_menu_text=&Layout
+TestsHierarchyViewer_test_path_format=\ - {0}
+TestsHierarchyViewer_test_time_format=\ ({0} s)
+UIUpdater_update_ui_job=Update C/C++ Tests Runner
+UIUpdater_view_caption_format={0} - {1}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.java
new file mode 100644
index 0000000000..1f5097b1c4
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ActionsMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.internal.ui.view.actions.ActionsMessages"; //$NON-NLS-1$
+ public static String CopySelectedMessagesAction_text;
+ public static String CopySelectedMessagesAction_tooltip;
+ public static String CopySelectedTestsAction_text;
+ public static String CopySelectedTestsAction_tooltip;
+ public static String HistoryAction_dialog_button_remove;
+ public static String HistoryAction_dialog_button_remove_all;
+ public static String HistoryAction_dialog_limit_label;
+ public static String HistoryAction_dialog_limit_label_error;
+ public static String HistoryAction_dialog_list_title;
+ public static String HistoryAction_dialog_title;
+ public static String HistoryAction_history_item_clear_text;
+ public static String HistoryAction_history_item_show_text;
+ public static String HistoryAction_history_text;
+ public static String HistoryAction_history_tooltip;
+ public static String MessageLevelFilterAction_errors_text;
+ public static String MessageLevelFilterAction_errors_tooltip;
+ public static String MessageLevelFilterAction_infos_text;
+ public static String MessageLevelFilterAction_infos_tooltip;
+ public static String MessageLevelFilterAction_warnings_text;
+ public static String MessageLevelFilterAction_warnings_tooltip;
+ public static String MessagesOrderingAction_text;
+ public static String MessagesOrderingAction_tooltip;
+ public static String OpenInEditorAction_text;
+ public static String OpenInEditorAction_tooltip;
+ public static String RedebugSelectedAction_text;
+ public static String RedebugSelectedAction_tooltip;
+ public static String RerunAction_text;
+ public static String RerunAction_tooltip;
+ public static String RerunSelectedAction_text;
+ public static String RerunSelectedAction_tooltip;
+ public static String ScrollLockAction_name;
+ public static String ScrollLockAction_tooltip;
+ public static String ShowFailedOnlyAction_text;
+ public static String ShowFailedOnlyAction_tooltip;
+ public static String ShowFileNameOnlyAction_text;
+ public static String ShowFileNameOnlyAction_tooltip;
+ public static String ShowNextFailureAction_text;
+ public static String ShowNextFailureAction_tooltip;
+ public static String ShowPreviousFailureAction_text;
+ public static String ShowPreviousFailureAction_tooltip;
+ public static String ShowTestsInHierarchyAction_text;
+ public static String ShowTestsInHierarchyAction_tooltip;
+ public static String ShowTimeAction_text;
+ public static String ShowTimeAction_tooltip;
+ public static String StopAction_text;
+ public static String StopAction_tooltip;
+ public static String TestsHierarchyCollapseAllAction_text;
+ public static String TestsHierarchyCollapseAllAction_tooltip;
+ public static String TestsHierarchyExpandAllAction_text;
+ public static String TestsHierarchyExpandAllAction_tooltip;
+ public static String ToggleOrientationAction_automatic_text;
+ public static String ToggleOrientationAction_horizontal_text;
+ public static String ToggleOrientationAction_vertical_text;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, ActionsMessages.class);
+ }
+
+ private ActionsMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.properties
new file mode 100644
index 0000000000..267fc50cfe
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ActionsMessages.properties
@@ -0,0 +1,63 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+CopySelectedMessagesAction_text=&Copy
+CopySelectedMessagesAction_tooltip=Copy Selected Messages To Clipboard
+CopySelectedTestsAction_text=&Copy
+CopySelectedTestsAction_tooltip=Copy Selected Test Names To Clipboard
+HistoryAction_dialog_button_remove=&Remove
+HistoryAction_dialog_button_remove_all=Remove &All
+HistoryAction_dialog_limit_label=&Maximum count of remembered test runs:
+HistoryAction_dialog_limit_label_error=Please enter a positive integer smaller than {0}.
+HistoryAction_dialog_list_title=Select a test run:
+HistoryAction_dialog_title=Test Runs
+HistoryAction_history_item_clear_text=&Clear Terminated
+HistoryAction_history_item_show_text=History...
+HistoryAction_history_text=History
+HistoryAction_history_tooltip=Test Run History...
+MessageLevelFilterAction_errors_text=&Errors
+MessageLevelFilterAction_errors_tooltip=Show error messages
+MessageLevelFilterAction_infos_text=&Infos
+MessageLevelFilterAction_infos_tooltip=Show information messages
+MessageLevelFilterAction_warnings_text=&Warnings
+MessageLevelFilterAction_warnings_tooltip=Show warning messages
+MessagesOrderingAction_text=Messages &Ordering
+MessagesOrderingAction_tooltip=Order Messages By Location, Skip Duplicates
+OpenInEditorAction_text=&Go to File
+OpenInEditorAction_tooltip=Show File Referred By the Message
+RedebugSelectedAction_text=&Debug
+RedebugSelectedAction_tooltip=Start Debug Session For Selected Tests
+RerunAction_text=Rerun
+RerunAction_tooltip=Rerun All Tests
+RerunSelectedAction_text=&Run
+RerunSelectedAction_tooltip=Rerun Selected Tests
+ScrollLockAction_name=Scroll Lock
+ScrollLockAction_tooltip=Scroll Lock
+ShowFailedOnlyAction_text=Show &Failures Only
+ShowFailedOnlyAction_tooltip=Show &Failures Only
+ShowFileNameOnlyAction_text=Show File Names Only
+ShowFileNameOnlyAction_tooltip=Show Only File Names in Message Locations
+ShowNextFailureAction_text=Next Failure
+ShowNextFailureAction_tooltip=Next Failed Test
+ShowPreviousFailureAction_text=Previous Failure
+ShowPreviousFailureAction_tooltip=Previous Failed Test
+ShowTestsInHierarchyAction_text=Show Tests in &Hierarchy
+ShowTestsInHierarchyAction_tooltip=Show Tests in Hierarchy
+ShowTimeAction_text=Show Execution &Time
+ShowTimeAction_tooltip=Show Execution Time
+StopAction_text=Stop
+StopAction_tooltip=Stop Test Run
+TestsHierarchyCollapseAllAction_text=C&ollapse All
+TestsHierarchyCollapseAllAction_tooltip=Collapse All Nodes
+TestsHierarchyExpandAllAction_text=&Expand All
+TestsHierarchyExpandAllAction_tooltip=Expand All Nodes
+ToggleOrientationAction_automatic_text=&Automatic
+ToggleOrientationAction_horizontal_text=&Horizontal
+ToggleOrientationAction_vertical_text=&Vertical
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedMessagesAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedMessagesAction.java
new file mode 100644
index 0000000000..bcad308fee
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedMessagesAction.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import java.util.Iterator;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+
+/**
+ * Copies the selected test messages to the clipboard.
+ */
+public class CopySelectedMessagesAction extends Action {
+
+ private Clipboard clipboard;
+ private TableViewer tableViewer;
+
+
+ public CopySelectedMessagesAction(TableViewer tableViewer, Clipboard clipboard) {
+ super(ActionsMessages.CopySelectedMessagesAction_text);
+ setToolTipText(ActionsMessages.CopySelectedMessagesAction_tooltip);
+ setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY);
+ this.tableViewer = tableViewer;
+ this.clipboard = clipboard;
+ }
+
+ @Override
+ public void run() {
+ ITableLabelProvider labelProvider = (ITableLabelProvider)tableViewer.getLabelProvider();
+ IStructuredSelection selection = (IStructuredSelection)tableViewer.getSelection();
+ if (!selection.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ boolean needEOL = false;
+ for (Iterator<?> it = selection.iterator(); it.hasNext();) {
+ Object item = it.next();
+ if (needEOL) {
+ sb.append(System.getProperty("line.separator")); //$NON-NLS-1$
+ } else {
+ needEOL = true;
+ }
+ sb.append(labelProvider.getColumnText(item, 0));
+ }
+ clipboard.setContents(
+ new String[]{ sb.toString() },
+ new Transfer[]{ TextTransfer.getInstance() });
+ }
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedTestsAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedTestsAction.java
new file mode 100644
index 0000000000..488abcdbaf
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/CopySelectedTestsAction.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestPathUtils;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+
+/**
+ * Copies the name of the selected test items (test suites or cases) to the
+ * clipboard.
+ */
+public class CopySelectedTestsAction extends Action {
+
+ private TreeViewer treeViewer;
+ private Clipboard clipboard;
+
+
+ public CopySelectedTestsAction(TreeViewer treeViewer, Clipboard clipboard) {
+ super(ActionsMessages.CopySelectedTestsAction_text);
+ setToolTipText(ActionsMessages.CopySelectedTestsAction_tooltip);
+ setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY);
+ this.treeViewer = treeViewer;
+ this.clipboard = clipboard;
+ }
+
+ @Override
+ public void run() {
+ IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
+ if (!selection.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ boolean needEOL = false;
+ for (Iterator<?> it = selection.iterator(); it.hasNext();) {
+ if (needEOL) {
+ sb.append(System.getProperty("line.separator")); //$NON-NLS-1$
+ } else {
+ needEOL = true;
+ }
+ sb.append(TestPathUtils.getTestItemPath((ITestItem)it.next()));
+ }
+ clipboard.setContents(
+ new String[]{ sb.toString() },
+ new Transfer[]{ TextTransfer.getInstance() });
+ }
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/HistoryDropDownAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/HistoryDropDownAction.java
new file mode 100644
index 0000000000..788879ef15
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/HistoryDropDownAction.java
@@ -0,0 +1,448 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IListAdapter;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.ListDialogField;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringDialogField;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Shows the testing sessions history in drop down list.
+ */
+public class HistoryDropDownAction extends Action {
+
+ /**
+ * The dialog for testing sessions history management. Allows to browse,
+ * activate and remove the selected testing sessions and to set testing
+ * sessions history size limit.
+ */
+ private class HistoryListDialog extends StatusDialog {
+
+ /** Max value for the history size limit that may be set via the dialog. */
+ private static final int MAX_HISTORY_SIZE_LIMIT = 100;
+
+ /** Testing sessions history list. */
+ private ListDialogField<ITestingSession> historyList;
+
+ /** String field that allows to set testing sessions history size limit. */
+ private StringDialogField historySizeLimitField;
+
+ /** Currently set testing sessions history size limit. */
+ private int historySizeLimit;
+
+ /** The currently selected active testing session. */
+ private ITestingSession resultActiveSession;
+
+
+ /**
+ * Label provider for the dialog testing sessions list.
+ */
+ private final class TestRunLabelProvider extends LabelProvider {
+
+ @Override
+ public String getText(Object element) {
+ return ((ITestingSession)element).getName();
+ }
+
+ }
+
+
+ private HistoryListDialog(Shell shell) {
+ super(shell);
+ setHelpAvailable(false);
+ setTitle(ActionsMessages.HistoryAction_dialog_title);
+
+ createHistoryList();
+ createHistorySizeLimitField();
+ }
+
+ @Override
+ protected boolean isResizable() {
+ return true;
+ }
+
+ /**
+ * Fills the testing sessions history list.
+ */
+ private void createHistoryList() {
+ IListAdapter<ITestingSession> adapter = new IListAdapter<ITestingSession>() {
+ @Override
+ public void customButtonPressed(ListDialogField<ITestingSession> field, int index) {
+ doCustomButtonPressed(index);
+ }
+ @Override
+ public void selectionChanged(ListDialogField<ITestingSession> field) {
+ doSelectionChanged();
+ }
+
+ @Override
+ public void doubleClicked(ListDialogField<ITestingSession> field) {
+ doDoubleClicked();
+ }
+ };
+ String[] buttonLabels = new String[] { ActionsMessages.HistoryAction_dialog_button_remove, ActionsMessages.HistoryAction_dialog_button_remove_all };
+ LabelProvider labelProvider = new TestRunLabelProvider();
+ historyList = new ListDialogField<ITestingSession>(adapter, buttonLabels, labelProvider);
+ historyList.setLabelText(ActionsMessages.HistoryAction_dialog_list_title);
+
+ historyList.setElements(testingSessionsManager.getSessions());
+ Object currentEntry = testingSessionsManager.getActiveSession();
+ ISelection sel = (currentEntry != null) ? new StructuredSelection(currentEntry) : new StructuredSelection();
+ historyList.selectElements(sel);
+ }
+
+ /**
+ * Initializes history size limit field of the dialog.
+ */
+ private void createHistorySizeLimitField() {
+ historySizeLimitField = new StringDialogField();
+ historySizeLimitField.setLabelText(ActionsMessages.HistoryAction_dialog_limit_label);
+ historySizeLimitField.setDialogFieldListener(new IDialogFieldListener() {
+ @Override
+ public void dialogFieldChanged(DialogField field) {
+ String maxString = historySizeLimitField.getText();
+ boolean valid;
+ try {
+ historySizeLimit = Integer.parseInt(maxString);
+ valid = historySizeLimit > 0 && historySizeLimit < MAX_HISTORY_SIZE_LIMIT;
+ } catch (NumberFormatException e) {
+ valid = false;
+ }
+ IStatus status = valid ? StatusInfo.OK_STATUS : new StatusInfo(IStatus.ERROR,
+ MessageFormat.format(ActionsMessages.HistoryAction_dialog_limit_label_error,
+ Integer.toString(MAX_HISTORY_SIZE_LIMIT)
+ )
+ );
+ updateStatus(status);
+ }
+ });
+ historySizeLimitField.setText(Integer.toString(testingSessionsManager.getHistorySizeLimit()));
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ initializeDialogUnits(parent);
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ Composite inner = new Composite(composite, SWT.NONE);
+ inner.setLayoutData(new GridData(GridData.FILL_BOTH));
+ inner.setFont(composite.getFont());
+
+ LayoutUtil.doDefaultLayout(inner, new DialogField[] { historyList, new org.eclipse.cdt.internal.ui.wizards.dialogfields.Separator() }, true);
+ LayoutUtil.setHeightHint(historyList.getListControl(null), convertHeightInCharsToPixels(12));
+ LayoutUtil.setHorizontalGrabbing(historyList.getListControl(null));
+
+ Composite additionalControls = new Composite(inner, SWT.NONE);
+ additionalControls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ LayoutUtil.doDefaultLayout(additionalControls, new DialogField[] { historySizeLimitField }, false);
+ LayoutUtil.setHorizontalGrabbing(historySizeLimitField.getTextControl(null));
+
+ applyDialogFont(composite);
+ return composite;
+ }
+
+ /**
+ * Processes dialog custom button pressing.
+ *
+ * @param index index of the button
+ */
+ private void doCustomButtonPressed(int index) {
+ switch (index) {
+ case 0: // remove
+ historyList.removeElements(historyList.getSelectedElements());
+ historyList.selectFirstElement();
+ break;
+
+ case 1: // remove all
+ historyList.removeAllElements();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Processes double click on the item in dialog.
+ */
+ private void doDoubleClicked() {
+ okPressed();
+ }
+
+ /**
+ * Processes the selection change in the dialog
+ */
+ private void doSelectionChanged() {
+ List<ITestingSession> selected = historyList.getSelectedElements();
+ if (selected.size() >= 1) {
+ resultActiveSession = selected.get(0);
+ } else {
+ resultActiveSession = null;
+ }
+ historyList.enableButton(0, selected.size() != 0);
+ }
+
+ /**
+ * Provides access to the active session currently selected by user.
+ *
+ * @return testing session
+ */
+ public ITestingSession getResultActiveSession() {
+ return resultActiveSession;
+ }
+
+ /**
+ * Provides access to the testing sessions history list edited by user.
+ *
+ * @return list of testing sessions
+ */
+ public List<ITestingSession> getResultSessions() {
+ return historyList.getElements();
+ }
+
+ /**
+ * Provides access to value of history size limit specified by user.
+ *
+ * @return history size limit
+ */
+ public int getResultHistorySizeLimit() {
+ return historySizeLimit;
+ }
+ }
+
+
+ /**
+ * Represents a testing sessions history item.
+ */
+ private class HistoryAction extends Action {
+
+ /** Testing session of the history item. */
+ private final ITestingSession testingSession;
+
+ public HistoryAction(int testingSessionIndex, ITestingSession testingSession) {
+ super("", AS_RADIO_BUTTON); //$NON-NLS-1$
+ this.testingSession = testingSession;
+
+ // Generate action text
+ String label = testingSession.getName();
+ if (testingSessionIndex < 10) {
+ // Add the numerical accelerator
+ label = new StringBuilder().append('&').append(testingSessionIndex).append(' ').append(label).toString();
+ }
+ setText(label);
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ testingSessionsManager.setActiveSession(testingSession);
+ }
+ }
+ }
+
+
+ /**
+ * Provides access to the history list management dialog.
+ */
+ private class HistoryListAction extends Action {
+
+ public HistoryListAction() {
+ super(ActionsMessages.HistoryAction_history_item_show_text, AS_RADIO_BUTTON);
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ runHistoryDialog();
+ }
+ }
+ }
+
+
+ /**
+ * Removes the terminated testing sessions from the history list.
+ */
+ private class ClearAction extends Action {
+
+ public ClearAction() {
+ setText(ActionsMessages.HistoryAction_history_item_clear_text);
+
+ boolean enabled = false;
+ for (ITestingSession testingSession : testingSessionsManager.getSessions()) {
+ if (testingSession.isFinished()) {
+ enabled = true;
+ break;
+ }
+ }
+ setEnabled(enabled);
+ }
+
+ @Override
+ public void run() {
+ List<ITestingSession> remainingSessions = new ArrayList<ITestingSession>();
+ for (ITestingSession testingSession : testingSessionsManager.getSessions()) {
+ if (!testingSession.isFinished()) {
+ remainingSessions.add(testingSession);
+ }
+ }
+
+ ITestingSession newActiveSession = remainingSessions.isEmpty() ? null : remainingSessions.get(0);
+ testingSessionsManager.setActiveSession(newActiveSession);
+ testingSessionsManager.setSessions(remainingSessions);
+ }
+ }
+
+
+ /**
+ * Represents the testing sessions history menu factory.
+ */
+ private class HistoryMenuCreator implements IMenuCreator {
+
+ @Override
+ public Menu getMenu(Menu parent) {
+ return null;
+ }
+
+ @Override
+ public Menu getMenu(Control parent) {
+ if (menu != null) {
+ menu.dispose();
+ }
+ final MenuManager manager = new MenuManager();
+ manager.setRemoveAllWhenShown(true);
+ manager.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager2) {
+ boolean checkOthers = addHistoryItems(manager2);
+
+ Action others = new HistoryListAction();
+ others.setChecked(checkOthers);
+ manager2.add(others);
+ manager2.add(new Separator());
+ manager2.add(new ClearAction());
+ }
+
+ private boolean addHistoryItems(IMenuManager manager) {
+ boolean checkOthers = true;
+
+ int sessionsCount = testingSessionsManager.getSessionsCount();
+ if (sessionsCount == 0) {
+ return false;
+ }
+ int menuItemsCount = Math.min(sessionsCount, RESULTS_IN_DROP_DOWN_MENU);
+
+ ITestingSession activeSession = testingSessionsManager.getActiveSession();
+ int testingSessionIndex = 0;
+ for (ITestingSession testingSession : testingSessionsManager.getSessions()) {
+ if (testingSessionIndex >= menuItemsCount) {
+ break;
+ }
+ HistoryAction action = new HistoryAction(testingSessionIndex, testingSession);
+ boolean check = (testingSession == activeSession);
+ action.setChecked(check);
+ if (check) {
+ checkOthers = false;
+ }
+ manager.add(action);
+ testingSessionIndex++;
+ }
+
+ return checkOthers;
+ }
+ });
+
+ menu = manager.createContextMenu(parent);
+ return menu;
+ }
+
+ @Override
+ public void dispose() {
+ if (menu != null) {
+ menu.dispose();
+ menu = null;
+ }
+ }
+ }
+
+
+ /** Defines how many history items should be showed in drop down history menu. */
+ public static final int RESULTS_IN_DROP_DOWN_MENU = 10;
+
+ /** Accessor to the Testing Sessions Plug-in Manager. */
+ private TestingSessionsManager testingSessionsManager;
+
+ /** Required for the history dialog. */
+ private Shell shell;
+
+ /** Drop down menu */
+ private Menu menu;
+
+
+ public HistoryDropDownAction(TestingSessionsManager testingSessionsManager, Shell shell) {
+ super(ActionsMessages.HistoryAction_history_text);
+ setToolTipText(ActionsMessages.HistoryAction_history_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/history_list.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/history_list.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/history_list.gif")); //$NON-NLS-1$
+ this.testingSessionsManager = testingSessionsManager;
+ this.shell = shell;
+ setMenuCreator(new HistoryMenuCreator());
+ }
+
+ /**
+ * Shows the testing sessions history dialog.
+ */
+ private void runHistoryDialog() {
+ HistoryListDialog dialog = new HistoryListDialog(shell);
+ if (dialog.open() == Window.OK) {
+ testingSessionsManager.setHistorySizeLimit(dialog.getResultHistorySizeLimit());
+ testingSessionsManager.setActiveSession(dialog.getResultActiveSession());
+ testingSessionsManager.setSessions(dialog.getResultSessions());
+ }
+ }
+
+ @Override
+ public void run() {
+ runHistoryDialog();
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessageLevelFilterAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessageLevelFilterAction.java
new file mode 100644
index 0000000000..5eba442426
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessageLevelFilterAction.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.ui.view.MessagesViewer;
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Represents a filtering action for test messages. It is used for all kind of
+ * filters (info, warnings, errors).
+ */
+public class MessageLevelFilterAction extends Action {
+
+ private MessagesViewer.LevelFilter levelFilter;
+ private MessagesViewer messagesViewer;
+
+
+ public MessageLevelFilterAction(MessagesViewer messagePanel, MessagesViewer.LevelFilter levelFilter, boolean checked) {
+ super("", AS_CHECK_BOX); //$NON-NLS-1$
+ this.levelFilter = levelFilter;
+ this.messagesViewer = messagePanel;
+ if (levelFilter == MessagesViewer.LevelFilter.Info) {
+ setText(ActionsMessages.MessageLevelFilterAction_infos_text);
+ setToolTipText(ActionsMessages.MessageLevelFilterAction_infos_tooltip);
+ } else if (levelFilter == MessagesViewer.LevelFilter.Warning) {
+ setText(ActionsMessages.MessageLevelFilterAction_warnings_text);
+ setToolTipText(ActionsMessages.MessageLevelFilterAction_warnings_tooltip);
+ } else if (levelFilter == MessagesViewer.LevelFilter.Error) {
+ setText(ActionsMessages.MessageLevelFilterAction_errors_text);
+ setToolTipText(ActionsMessages.MessageLevelFilterAction_errors_tooltip);
+ }
+ setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(levelFilter.getImageId()));
+ setChecked(checked);
+ if (checked) {
+ messagePanel.addLevelFilter(levelFilter, false);
+ }
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ messagesViewer.addLevelFilter(levelFilter, true);
+ } else {
+ messagesViewer.removeLevelFilter(levelFilter);
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessagesOrderingAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessagesOrderingAction.java
new file mode 100644
index 0000000000..b7e032a07b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/MessagesOrderingAction.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.MessagesViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Turns on/off the messages ordering by location.
+ */
+public class MessagesOrderingAction extends Action {
+
+ private MessagesViewer messagesViewer;
+
+
+ public MessagesOrderingAction(MessagesViewer messagesViewer) {
+ super("", AS_CHECK_BOX); //$NON-NLS-1$
+ this.messagesViewer = messagesViewer;
+ setText(ActionsMessages.MessagesOrderingAction_text);
+ setToolTipText(ActionsMessages.MessagesOrderingAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/sort.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/sort.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/sort.gif")); //$NON-NLS-1$
+ setChecked(messagesViewer.getOrderingMode());
+ }
+
+ @Override
+ public void run() {
+ messagesViewer.setOrderingMode(isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/OpenInEditorAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/OpenInEditorAction.java
new file mode 100644
index 0000000000..5438d5b38d
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/OpenInEditorAction.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import java.net.URI;
+
+import org.eclipse.cdt.debug.ui.CDebugUIPlugin;
+import org.eclipse.cdt.debug.core.CDebugCorePlugin;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.model.ITestLocation;
+import org.eclipse.cdt.testsrunner.model.ITestMessage;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.filesystem.URIUtil;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.IPersistableSourceLocator;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.sourcelookup.ISourceLookupResult;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * Opens the editor in place where the currently selected message is pointed to.
+ */
+public class OpenInEditorAction extends Action {
+
+ private TableViewer messagesViewer;
+ private TestingSessionsManager testingSessionsManager;
+ private IWorkbench workbench;
+
+
+ public OpenInEditorAction(TableViewer tableViewer, TestingSessionsManager testingSessionsManager, IWorkbench workbench) {
+ super(ActionsMessages.OpenInEditorAction_text);
+ this.messagesViewer = tableViewer;
+ this.testingSessionsManager = testingSessionsManager;
+ this.workbench = workbench;
+ setToolTipText(ActionsMessages.OpenInEditorAction_tooltip);
+ }
+
+ @Override
+ public void run() {
+ Object selectedObject = ((IStructuredSelection)messagesViewer.getSelection()).getFirstElement();
+ if (selectedObject != null && selectedObject instanceof ITestMessage) {
+ ITestLocation messageLocation = ((ITestMessage)selectedObject).getLocation();
+ if (messageLocation != null) {
+ ILaunch launch = testingSessionsManager.getActiveSession().getLaunch();
+ lookupSource(messageLocation, launch);
+ }
+ }
+ }
+
+ // NOTE: This method is copied from Linux Tools Project (http://www.eclipse.org/linuxtools).
+ // Valgrind Support Plugin is implementing similar functionality so it is just reused.
+ // See also org.eclipse.linuxtools.valgrind.ui/src/org/eclipse/linuxtools/internal/valgrind/ui/CoreMessagesViewer.java
+ private void lookupSource(ITestLocation messageLocation, ILaunch launch) {
+ ISourceLocator locator = launch.getSourceLocator();
+ if (locator instanceof AbstractSourceLookupDirector) {
+ AbstractSourceLookupDirector director = (AbstractSourceLookupDirector) locator;
+ ISourceLookupParticipant[] participants = director.getParticipants();
+ if (participants.length == 0) {
+ // source locator likely disposed, try recreating it
+ IPersistableSourceLocator sourceLocator;
+ ILaunchConfiguration config = launch.getLaunchConfiguration();
+ if (config != null) {
+ try {
+ String id = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String) null);
+ if (id == null) {
+ sourceLocator = CDebugUIPlugin.createDefaultSourceLocator();
+ sourceLocator.initializeDefaults(config);
+ } else {
+ sourceLocator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(id);
+ String memento = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null);
+ if (memento == null) {
+ sourceLocator.initializeDefaults(config);
+ } else {
+ sourceLocator.initializeFromMemento(memento);
+ }
+ }
+
+ // replace old source locator
+ locator = sourceLocator;
+ launch.setSourceLocator(sourceLocator);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ ISourceLookupResult result = DebugUITools.lookupSource(messageLocation.getFile(), locator);
+ try {
+ openEditorAndSelect(result, messageLocation.getLine());
+ } catch (PartInitException e) {
+ TestsRunnerPlugin.log(e);
+ } catch (BadLocationException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ }
+
+ // NOTE: This method is copied from Linux Tools Project (http://www.eclipse.org/linuxtools).
+ // Valgrind Support Plugin is implementing similar functionality so it is just reused.
+ // See also org.eclipse.linuxtools.valgrind.ui/src/org/eclipse/linuxtools/internal/valgrind/ui/CoreMessagesViewer.java
+ private void openEditorAndSelect(ISourceLookupResult result, int line) throws PartInitException, BadLocationException {
+ IEditorInput input = result.getEditorInput();
+ String editorID = result.getEditorId();
+
+ if (input == null || editorID == null) {
+ // Consult the CDT DebugModelPresentation
+ Object sourceElement = result.getSourceElement();
+ if (sourceElement != null) {
+ // Resolve IResource in case we get a LocalFileStorage object
+ if (sourceElement instanceof LocalFileStorage) {
+ IPath filePath = ((LocalFileStorage) sourceElement).getFullPath();
+ URI fileURI = URIUtil.toURI(filePath);
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile[] files = root.findFilesForLocationURI(fileURI);
+ if (files.length > 0) {
+ // Take the first match
+ sourceElement = files[0];
+ }
+ }
+
+ IDebugModelPresentation pres = DebugUITools.newDebugModelPresentation(CDebugCorePlugin.getUniqueIdentifier());
+ input = pres.getEditorInput(sourceElement);
+ editorID = pres.getEditorId(input, sourceElement);
+ pres.dispose();
+ }
+ }
+ if (input != null && editorID != null) {
+ // Open the editor
+ IWorkbenchPage activePage = workbench.getActiveWorkbenchWindow().getActivePage();
+
+ IEditorPart editor = IDE.openEditor(activePage, input, editorID);
+ // Select the line
+ if (editor instanceof ITextEditor) {
+ ITextEditor textEditor = (ITextEditor) editor;
+
+ if (line > 0) {
+ IDocumentProvider provider = textEditor.getDocumentProvider();
+ IDocument document = provider.getDocument(textEditor.getEditorInput());
+
+ IRegion lineRegion = document.getLineInformation(line - 1); //zero-indexed
+ textEditor.selectAndReveal(lineRegion.getOffset(), lineRegion.getLength());
+ }
+ }
+ }
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RedebugSelectedAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RedebugSelectedAction.java
new file mode 100644
index 0000000000..a6b670dbbb
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RedebugSelectedAction.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.jface.viewers.TreeViewer;
+
+/**
+ * Launches the new debug session for the currently selected items of test
+ * hierarchy.
+ */
+public class RedebugSelectedAction extends RelaunchSelectedAction {
+
+ public RedebugSelectedAction(ITestingSession testingSession, TreeViewer treeViewer) {
+ super(testingSession, treeViewer);
+ setText(ActionsMessages.RedebugSelectedAction_text);
+ setToolTipText(ActionsMessages.RedebugSelectedAction_tooltip);
+ }
+
+ @Override
+ protected String getLaunchMode() {
+ return ILaunchManager.DEBUG_MODE;
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RelaunchSelectedAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RelaunchSelectedAction.java
new file mode 100644
index 0000000000..b40e0d6ab8
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RelaunchSelectedAction.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.launcher.ITestsLaunchConfigurationConstants;
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestPathUtils;
+import org.eclipse.cdt.testsrunner.model.ITestItem;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+
+/**
+ * Launches the new run or debug session for the currently selected items of
+ * test hierarchy.
+ */
+public abstract class RelaunchSelectedAction extends Action {
+
+ private ITestingSession testingSession;
+ private TreeViewer treeViewer;
+
+
+ public RelaunchSelectedAction(ITestingSession testingSession, TreeViewer treeViewer) {
+ this.testingSession = testingSession;
+ this.treeViewer = treeViewer;
+ }
+
+ /**
+ * Returns the launch mode that should be use to run selected test item.
+ *
+ * @return launch mode
+ */
+ protected abstract String getLaunchMode();
+
+ @Override
+ public void run() {
+ if (testingSession != null) {
+ try {
+ ILaunch launch = testingSession.getLaunch();
+ ILaunchConfigurationWorkingCopy launchConf = launch.getLaunchConfiguration().getWorkingCopy();
+ List<String> testsFilterAttr = Arrays.asList(TestPathUtils.packTestPaths(getSelectedTestItems()));
+ launchConf.setAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_FILTER, testsFilterAttr);
+ DebugUITools.launch(launchConf, getLaunchMode());
+ return;
+ } catch (CoreException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ }
+ setEnabled(false);
+ }
+
+ /**
+ * Returns the currently selected items of test hierarchy.
+ *
+ * @return array of test items
+ */
+ private ITestItem[] getSelectedTestItems() {
+ IStructuredSelection selection = (IStructuredSelection)treeViewer.getSelection();
+ ITestItem[] result = new ITestItem[selection.size()];
+ int resultIndex = 0;
+ for (Iterator<?> it = selection.iterator(); it.hasNext();) {
+ result[resultIndex] = (ITestItem)it.next();
+ ++resultIndex;
+ }
+ return result;
+ }
+
+ /**
+ * Sets actual testing session.
+ *
+ * @param testingSession testing session
+ */
+ public void setTestingSession(ITestingSession testingSession) {
+ this.testingSession = testingSession;
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunAction.java
new file mode 100644
index 0000000000..54da1a7163
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunAction.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Restarts the last testing session (it may be run or debug session).
+ */
+public class RerunAction extends Action {
+
+ private TestingSessionsManager testingSessionsManager;
+
+
+ public RerunAction(TestingSessionsManager testingSessionsManager) {
+ super(ActionsMessages.RerunAction_text);
+ setToolTipText(ActionsMessages.RerunAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/rerun.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/rerun.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/rerun.gif")); //$NON-NLS-1$
+ this.testingSessionsManager = testingSessionsManager;
+ }
+
+ @Override
+ public void run() {
+ ITestingSession activeSession = testingSessionsManager.getActiveSession();
+ if (activeSession != null) {
+ ILaunch launch = activeSession.getLaunch();
+ DebugUITools.launch(launch.getLaunchConfiguration(), launch.getLaunchMode());
+ } else {
+ setEnabled(false);
+ }
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunSelectedAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunSelectedAction.java
new file mode 100644
index 0000000000..29d57942e4
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/RerunSelectedAction.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.jface.viewers.TreeViewer;
+
+/**
+ * Launches the new run session for the currently selected items of test
+ * hierarchy.
+ */
+public class RerunSelectedAction extends RelaunchSelectedAction {
+
+ public RerunSelectedAction(ITestingSession testingSession, TreeViewer treeViewer) {
+ super(testingSession, treeViewer);
+ setText(ActionsMessages.RerunSelectedAction_text);
+ setToolTipText(ActionsMessages.RerunSelectedAction_tooltip);
+ }
+
+ @Override
+ protected String getLaunchMode() {
+ return ILaunchManager.RUN_MODE;
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ScrollLockAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ScrollLockAction.java
new file mode 100644
index 0000000000..841b8ec408
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ScrollLockAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.UIUpdater;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Toggles the auto-scroll for tests hierarchy tree.
+ */
+public class ScrollLockAction extends Action {
+
+ private UIUpdater modelSyncronizer;
+
+
+ public ScrollLockAction(UIUpdater modelSyncronizer) {
+ super(ActionsMessages.ScrollLockAction_name);
+ this.modelSyncronizer = modelSyncronizer;
+ setToolTipText(ActionsMessages.ScrollLockAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/scroll_lock.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/scroll_lock.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/scroll_lock.gif")); //$NON-NLS-1$
+ setChecked(!this.modelSyncronizer.getAutoScroll());
+ }
+
+ @Override
+ public void run() {
+ modelSyncronizer.setAutoScroll(!isChecked());
+ }
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFailedOnlyAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFailedOnlyAction.java
new file mode 100644
index 0000000000..13d2ee5f5c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFailedOnlyAction.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.ResultsPanel;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Toggles the filter for the passed test items.
+ */
+public class ShowFailedOnlyAction extends Action {
+
+ private ResultsPanel resultsPanel;
+
+
+ public ShowFailedOnlyAction(ResultsPanel resultsPanel) {
+ super("", AS_CHECK_BOX); //$NON-NLS-1$
+ this.resultsPanel = resultsPanel;
+ setText(ActionsMessages.ShowFailedOnlyAction_text);
+ setToolTipText(ActionsMessages.ShowFailedOnlyAction_tooltip);
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("obj16/show_failed_only.gif")); //$NON-NLS-1$
+ setChecked(resultsPanel.getShowFailedOnly());
+ }
+
+ @Override
+ public void run() {
+ resultsPanel.setShowFailedOnly(isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFileNameOnlyAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFileNameOnlyAction.java
new file mode 100644
index 0000000000..a9fdf4914d
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowFileNameOnlyAction.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.ui.view.MessagesViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Toggles the short or long view for file paths in message locations. The short
+ * view shows only the file names instead of full paths.
+ */
+public class ShowFileNameOnlyAction extends Action {
+
+ private MessagesViewer messagesViewer;
+
+
+ public ShowFileNameOnlyAction(MessagesViewer messagesViewer) {
+ super(ActionsMessages.ShowFileNameOnlyAction_text, AS_CHECK_BOX);
+ this.messagesViewer = messagesViewer;
+ setToolTipText(ActionsMessages.ShowFileNameOnlyAction_tooltip);
+ setChecked(messagesViewer.getShowFileNameOnly());
+ }
+
+ @Override
+ public void run() {
+ messagesViewer.setShowFileNameOnly(isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowNextFailureAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowNextFailureAction.java
new file mode 100644
index 0000000000..e337b03fca
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowNextFailureAction.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestsHierarchyViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Looks for the next failed test case in tests hierarchy (corresponding to the
+ * currently selected one).
+ */
+public class ShowNextFailureAction extends Action {
+
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+ public ShowNextFailureAction(TestsHierarchyViewer testsHierarchyViewer) {
+ super(ActionsMessages.ShowNextFailureAction_text);
+ this.testsHierarchyViewer = testsHierarchyViewer;
+ setToolTipText(ActionsMessages.ShowNextFailureAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/show_next.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/show_next.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/show_next.gif")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void run() {
+ testsHierarchyViewer.showNextFailure();
+ }
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowPreviousFailureAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowPreviousFailureAction.java
new file mode 100644
index 0000000000..79c43502e7
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowPreviousFailureAction.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestsHierarchyViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Looks for the previous failed test case in tests hierarchy (corresponding to the
+ * currently selected one).
+ */
+public class ShowPreviousFailureAction extends Action {
+
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+ public ShowPreviousFailureAction(TestsHierarchyViewer testsHierarchyViewer) {
+ super(ActionsMessages.ShowPreviousFailureAction_text);
+ this.testsHierarchyViewer = testsHierarchyViewer;
+ setToolTipText(ActionsMessages.ShowPreviousFailureAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/show_previous.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/show_previous.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/show_previous.gif")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void run() {
+ testsHierarchyViewer.showPreviousFailure();
+ }
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTestsInHierarchyAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTestsInHierarchyAction.java
new file mode 100644
index 0000000000..ab4869cedf
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTestsInHierarchyAction.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestsHierarchyViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Specifies whether tests hierarchy should be shown in hierarchical or flat
+ * view.
+ */
+public class ShowTestsInHierarchyAction extends Action {
+
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+
+ public ShowTestsInHierarchyAction(TestsHierarchyViewer testsHierarchyViewer) {
+ super(ActionsMessages.ShowTestsInHierarchyAction_text, AS_CHECK_BOX);
+ this.testsHierarchyViewer = testsHierarchyViewer;
+ setToolTipText(ActionsMessages.ShowTestsInHierarchyAction_tooltip);
+ setChecked(testsHierarchyViewer.showTestsHierarchy());
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/show_tests_hierarchy.gif")); //$NON-NLS-1$
+ }
+
+ @Override
+ public void run() {
+ testsHierarchyViewer.setShowTestsHierarchy(isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTimeAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTimeAction.java
new file mode 100644
index 0000000000..c312bdcebb
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ShowTimeAction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestsHierarchyViewer;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Toggles the test execution time showing in tests hierarchy viewer.
+ */
+public class ShowTimeAction extends Action {
+
+ private TestsHierarchyViewer testsHierarchyViewer;
+
+
+ public ShowTimeAction(TestsHierarchyViewer testsHierarchyViewer) {
+ super(ActionsMessages.ShowTimeAction_text, AS_CHECK_BOX);
+ this.testsHierarchyViewer = testsHierarchyViewer;
+ setToolTipText(ActionsMessages.ShowTimeAction_tooltip);
+ setChecked(testsHierarchyViewer.showTime());
+ }
+
+ @Override
+ public void run() {
+ testsHierarchyViewer.setShowTime(isChecked());
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/StopAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/StopAction.java
new file mode 100644
index 0000000000..e6905998d6
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/StopAction.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.model.TestingSessionsManager;
+import org.eclipse.cdt.testsrunner.model.ITestingSession;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Stops running of the active testing session.
+ */
+public class StopAction extends Action {
+
+ private TestingSessionsManager testingSessionsManager;
+
+
+ public StopAction(TestingSessionsManager testingSessionsManager) {
+ super(ActionsMessages.StopAction_text);
+ setToolTipText(ActionsMessages.StopAction_tooltip);
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/stop.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/stop.gif")); //$NON-NLS-1$
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/stop.gif")); //$NON-NLS-1$
+ this.testingSessionsManager = testingSessionsManager;
+ }
+
+ @Override
+ public void run() {
+ ITestingSession activeSession = testingSessionsManager.getActiveSession();
+ if (activeSession != null) {
+ activeSession.stop();
+ }
+ setEnabled(false);
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyCollapseAllAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyCollapseAllAction.java
new file mode 100644
index 0000000000..c42a42cb1e
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyCollapseAllAction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+
+/**
+ * Collapses the tests hierarchy tree in the viewer.
+ */
+public class TestsHierarchyCollapseAllAction extends Action {
+
+ private AbstractTreeViewer testsHierarchyTreeViewer;
+
+
+ public TestsHierarchyCollapseAllAction(AbstractTreeViewer testsHierarchyTreeViewer) {
+ setText(ActionsMessages.TestsHierarchyCollapseAllAction_text);
+ setToolTipText(ActionsMessages.TestsHierarchyCollapseAllAction_tooltip);
+ this.testsHierarchyTreeViewer = testsHierarchyTreeViewer;
+ }
+
+ @Override
+ public void run(){
+ testsHierarchyTreeViewer.collapseAll();
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyExpandAllAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyExpandAllAction.java
new file mode 100644
index 0000000000..a48ba783ad
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/TestsHierarchyExpandAllAction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+
+/**
+ * Expands the tests hierarchy tree in the viewer.
+ */
+public class TestsHierarchyExpandAllAction extends Action {
+
+ private AbstractTreeViewer testsHierarchyTreeViewer;
+
+
+ public TestsHierarchyExpandAllAction(AbstractTreeViewer testsHierarchyTreeViewer) {
+ setText(ActionsMessages.TestsHierarchyExpandAllAction_text);
+ setToolTipText(ActionsMessages.TestsHierarchyExpandAllAction_tooltip);
+ this.testsHierarchyTreeViewer = testsHierarchyTreeViewer;
+ }
+
+ @Override
+ public void run(){
+ testsHierarchyTreeViewer.expandAll();
+ }
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ToggleOrientationAction.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ToggleOrientationAction.java
new file mode 100644
index 0000000000..1ecaafe8ed
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/internal/ui/view/actions/ToggleOrientationAction.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.internal.ui.view.actions;
+
+
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.ui.view.ResultsView;
+import org.eclipse.jface.action.Action;
+
+/**
+ * Toggles the orientation of the view.
+ */
+public class ToggleOrientationAction extends Action {
+
+ private ResultsView resultsView;
+ private ResultsView.Orientation orientation;
+
+
+ public ToggleOrientationAction(ResultsView resultsView, ResultsView.Orientation orientation) {
+ super("", AS_RADIO_BUTTON); //$NON-NLS-1$
+ this.resultsView = resultsView;
+ if (orientation == ResultsView.Orientation.Horizontal) {
+ setText(ActionsMessages.ToggleOrientationAction_horizontal_text);
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_horizontal.gif")); //$NON-NLS-1$
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/orientation_horizontal.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_horizontal.gif")); //$NON-NLS-1$
+ } else if (orientation == ResultsView.Orientation.Vertical) {
+ setText(ActionsMessages.ToggleOrientationAction_vertical_text);
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_vertical.gif")); //$NON-NLS-1$
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/orientation_vertical.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_vertical.gif")); //$NON-NLS-1$
+ } else if (orientation == ResultsView.Orientation.Auto) {
+ setText(ActionsMessages.ToggleOrientationAction_automatic_text);
+ setImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_auto.gif")); //$NON-NLS-1$
+ setDisabledImageDescriptor(TestsRunnerPlugin.getImageDescriptor("dlcl16/orientation_auto.gif")); //$NON-NLS-1$
+ setHoverImageDescriptor(TestsRunnerPlugin.getImageDescriptor("elcl16/orientation_auto.gif")); //$NON-NLS-1$
+ }
+ this.orientation = orientation;
+ }
+
+ public ResultsView.Orientation getOrientation() {
+ return orientation;
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ resultsView.setOrientation(orientation);
+ }
+ }
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/BaseTestsLaunchDelegate.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/BaseTestsLaunchDelegate.java
new file mode 100644
index 0000000000..2effdce889
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/BaseTestsLaunchDelegate.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.launcher;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
+import org.eclipse.cdt.testsrunner.internal.launcher.ITestsLaunchConfigurationConstants;
+import org.eclipse.cdt.testsrunner.internal.launcher.LauncherMessages;
+import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProviderInfo;
+import org.eclipse.cdt.testsrunner.internal.ui.view.TestPathUtils;
+import org.eclipse.cdt.testsrunner.model.TestingException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchDelegate;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * Launch delegate implementation that redirects its queries to the preferred
+ * launch delegate, correcting the arguments attribute (to take into account
+ * auto generated test module parameters) and setting up the custom process
+ * factory (to handle testing process IO streams).
+ */
+public abstract class BaseTestsLaunchDelegate extends LaunchConfigurationDelegate {
+
+ /** Stores the changes made to the launch configuration. */
+ private Map<String, String> changesToLaunchConfiguration = new HashMap<String, String>();
+
+
+ @Override
+ public ILaunch getLaunch(ILaunchConfiguration config, String mode) throws CoreException {
+ return getPreferredDelegate(config, mode).getLaunch(config, mode);
+ }
+
+ @Override
+ public boolean buildForLaunch(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException {
+ return getPreferredDelegate(config, mode).buildForLaunch(config, mode, monitor);
+ }
+
+ @Override
+ public boolean finalLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException {
+ return getPreferredDelegate(config, mode).finalLaunchCheck(config, mode, monitor);
+ }
+
+ @Override
+ public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException {
+ return getPreferredDelegate(config, mode).preLaunchCheck(config, mode, monitor);
+ }
+
+ @Override
+ public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException {
+
+ if (mode.equals(ILaunchManager.RUN_MODE) || mode.equals(ILaunchManager.DEBUG_MODE)) {
+
+ // NOTE: The modified working copy of launch configuration cannot be passed directly
+ // to the preferred delegate because in this case the LaunchHistory will not work
+ // properly (and the rerun last launched configuration action will fail). So we
+ // just modify the existing configuration and revert all the changes back after
+ // the launch is done.
+
+ try {
+ // Changes launch configuration a bit and redirect it to the preferred C/C++ Application Launch delegate
+ updatedLaunchConfiguration(config);
+ getPreferredDelegate(config, mode).launch(config, mode, launch, monitor);
+ }
+ finally {
+ revertChangedToLaunchConfiguration(config);
+ }
+ activateTestingView();
+ }
+ }
+
+ /**
+ * Revert the changes to launch configuration previously made with
+ * <code>updatedLaunchConfigurationAttribute()</code>.
+ *
+ * @param config launch configuration to revert
+ */
+ private void revertChangedToLaunchConfiguration(ILaunchConfiguration config) throws CoreException {
+ ILaunchConfigurationWorkingCopy configWC = config.getWorkingCopy();
+ for (Map.Entry<String, String> changeEntry : changesToLaunchConfiguration.entrySet()) {
+ configWC.setAttribute(changeEntry.getKey(), changeEntry.getValue());
+ }
+ configWC.doSave();
+ changesToLaunchConfiguration.clear();
+ }
+
+ /**
+ * Saves the current value of the specified attribute (to be reverted later)
+ * and update its value in launch configuration.
+ *
+ * @param config launch configuration which attribute should be updated
+ * @param attributeName attribute name
+ * @param value new value of the specified attribute
+ */
+ private void updatedLaunchConfigurationAttribute(ILaunchConfigurationWorkingCopy config, String attributeName, String value) throws CoreException {
+ changesToLaunchConfiguration.put(attributeName, config.getAttribute(attributeName, "")); //$NON-NLS-1$
+ config.setAttribute(attributeName, value);
+ }
+
+ /**
+ * Makes the necessary changes to the launch configuration before passing it
+ * to the underlying delegate. Currently, updates the program arguments with
+ * the value that was obtained from Tests Runner provider plug-in.
+ *
+ * @param config launch configuration
+ */
+ private void updatedLaunchConfiguration(ILaunchConfiguration config) throws CoreException {
+ changesToLaunchConfiguration.clear();
+ ILaunchConfigurationWorkingCopy configWC = config.getWorkingCopy();
+ setProgramArguments(configWC);
+ configWC.doSave();
+ }
+
+ /**
+ * Updates the program arguments with the value that was obtained from Tests
+ * Runner provider plug-in.
+ *
+ * @param config launch configuration
+ */
+ private void setProgramArguments(ILaunchConfigurationWorkingCopy config) throws CoreException {
+ List<?> packedTestsFilter = config.getAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_FILTER, Collections.EMPTY_LIST);
+ String [][] testsFilter = TestPathUtils.unpackTestPaths(packedTestsFilter.toArray(new String[packedTestsFilter.size()]));
+
+ // Configure test module run parameters with a Tests Runner
+ String[] params = null;
+ try {
+ params = getTestsRunner(config).getAdditionalLaunchParameters(testsFilter);
+
+ } catch (TestingException e) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(),
+ e.getLocalizedMessage(), null
+ )
+ );
+ }
+
+ // Rewrite ATTR_PROGRAM_ARGUMENTS attribute of launch configuration
+ if (params != null && params.length >= 1) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$
+ for (String param : params) {
+ sb.append(' ');
+ sb.append(param);
+ }
+ updatedLaunchConfigurationAttribute(config, ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, sb.toString());
+ }
+ }
+
+ /**
+ * Resolves Tests Runner provider plug-in interface by the value written in
+ * launch configuration.
+ *
+ * @param config launch configuration
+ */
+ private ITestsRunnerProvider getTestsRunner(ILaunchConfiguration config) throws CoreException {
+ TestsRunnerProviderInfo testsRunnerProviderInfo = TestsRunnerPlugin.getDefault().getTestsRunnerProvidersManager().getTestsRunnerProviderInfo(config);
+ if (testsRunnerProviderInfo == null) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(),
+ LauncherMessages.BaseTestsLaunchDelegate_invalid_tests_runner, null
+ )
+ );
+ }
+ ITestsRunnerProvider testsRunnerProvider = testsRunnerProviderInfo.instantiateTestsRunnerProvider();
+ if (testsRunnerProvider == null) {
+ throw new CoreException(
+ new Status(
+ IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(),
+ LauncherMessages.BaseTestsLaunchDelegate_tests_runner_load_failed, null
+ )
+ );
+ }
+ return testsRunnerProvider;
+ }
+
+ /**
+ * Resolves the preferred launch delegate for the specified configuration to
+ * launch C/C++ Local Application in the specified mode. The preferred
+ * launch delegate ID is taken from <code>getPreferredDelegateId()</code>.
+ *
+ * @param config launch configuration
+ * @param mode mode
+ * @return launch delegate
+ */
+ @SuppressWarnings("unchecked")
+ private ILaunchConfigurationDelegate2 getPreferredDelegate(ILaunchConfiguration config, String mode) throws CoreException {
+ ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType localCfg =
+ launchMgr.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP);
+ Set<String> modes = config.getModes();
+ modes.add(mode);
+ String preferredDelegateId = getPreferredDelegateId();
+ for (ILaunchDelegate delegate : localCfg.getDelegates(modes)) {
+ if (preferredDelegateId.equals(delegate.getId())) {
+ return (ILaunchConfigurationDelegate2) delegate.getDelegate();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the launch delegate id which should be used to redirect the
+ * launch.
+ *
+ * @return launch delegate ID
+ */
+ public abstract String getPreferredDelegateId();
+
+ /**
+ * Activates the view showing testing results.
+ */
+ private void activateTestingView() {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IWorkbenchWindow activeWindow = TestsRunnerPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
+ IViewPart view = activeWindow.getActivePage().showView(ITestsRunnerConstants.TESTS_RUNNER_RESULTS_VIEW_ID);
+ TestsRunnerPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().activate(view);
+ } catch (PartInitException e) {
+ TestsRunnerPlugin.log(e);
+ }
+ }
+ });
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerConstants.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerConstants.java
new file mode 100644
index 0000000000..948e4e685f
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerConstants.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.launcher;
+
+/**
+ * Constants used for attributes in CDT Tests Runner launch configurations.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface ITestsRunnerConstants {
+
+ /**
+ * Tests Runner launch configuration type.
+ */
+ public static final String LAUNCH_CONFIGURATION_TYPE_ID = "org.eclipse.cdt.testsrunner.launch.CTestsRunner"; //$NON-NLS-1$
+
+ /**
+ * Specifies the default launch delegate for a Tests Run session.
+ */
+ public static final String PREFERRED_RUN_TESTS_LAUNCH_DELEGATE = "org.eclipse.cdt.testsrunner.launch.runTests"; //$NON-NLS-1$
+
+ /**
+ * Specifies the default launch delegate for a Tests Debug session.
+ */
+ public static final String PREFERRED_DEBUG_TESTS_LAUNCH_DELEGATE = "org.eclipse.cdt.testsrunner.launch.dsf.runTests"; //$NON-NLS-1$
+
+ /**
+ * Specifies the ID of the Tests Runner main view for browsing results.
+ */
+ public static final String TESTS_RUNNER_RESULTS_VIEW_ID = "org.eclipse.cdt.testsrunner.resultsview"; //$NON-NLS-1$
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProvider.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProvider.java
new file mode 100644
index 0000000000..4f6ceb049b
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProvider.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.launcher;
+
+import java.io.InputStream;
+
+import org.eclipse.cdt.testsrunner.model.ITestModelUpdater;
+import org.eclipse.cdt.testsrunner.model.TestingException;
+
+
+/**
+ * The interface for a Tests Runner provider plug-in.
+ *
+ * <p>
+ * Clients may implement this interface.
+ * </p>
+ */
+public interface ITestsRunnerProvider {
+
+ /**
+ * Returns the list of automatically generated parameters that should be
+ * passed to test module for launching. Usually there are parameters to
+ * configure test module output format and content. If testPaths is not
+ * <code>null</code>, it contains the paths to the test suites and test
+ * cases that should be run during the testing process, so the proper
+ * filters should be generated too.
+ *
+ * @param testPaths the array of test paths
+ * @return parameters list
+ * @throws TestingException if test parameters cannot be generated
+ */
+ public String[] getAdditionalLaunchParameters(String[][] testPaths) throws TestingException;
+
+ /**
+ * Starts the processing of testing results by Tests Runner Plug-in. The
+ * input data are provided via the stream. They should be converted to the
+ * commands for the Model Updater.
+ *
+ * @param modelUpdater model updater instance
+ * @param inputStream test model output or error data stream
+ * @throws TestingException if there are errors during the testing process
+ * or in data stream
+ */
+ public void run(ITestModelUpdater modelUpdater, InputStream inputStream) throws TestingException;
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProviderInfo.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProviderInfo.java
new file mode 100644
index 0000000000..37272797d4
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/launcher/ITestsRunnerProviderInfo.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.launcher;
+
+/**
+ * Describes the Tests Runner input provider plug-in, its requirements and
+ * features provided.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestsRunnerProviderInfo {
+
+ /**
+ * Returns the user readable name of the Tests Runner provider plug-in.
+ *
+ * @return readable name
+ */
+ public String getName();
+
+ /**
+ * Returns the unique ID of the Tests Runner provider plug-in.
+ *
+ * @return unique id
+ */
+ public String getId();
+
+ /**
+ * Returns the short description of the Tests Runner provider plug-in.
+ *
+ * @return short description
+ */
+ public String getDescription();
+
+ /**
+ * Returns whether Tests Runner provider plug-in allows to add a filter for
+ * running a few custom test cases or test suites at a time (e.g. Google
+ * Test and Qt Test allow it, but Boost.Test doesn't).
+ *
+ * @return whether multiple filter is supported
+ */
+ public boolean isAllowedMultipleTestFilter();
+
+ /**
+ * Returns whether Tests Runner provider plug-in requires to handle standard
+ * output stream of the testing process.
+ *
+ * @return whether output stream is required
+ */
+ public boolean isOutputStreamRequired();
+
+ /**
+ * Returns whether Tests Runner provider plug-in requires to handle standard
+ * error stream of the testing process.
+ *
+ * @return whether error stream is required
+ */
+ public boolean isErrorStreamRequired();
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/IModelVisitor.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/IModelVisitor.java
new file mode 100644
index 0000000000..5bf196610f
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/IModelVisitor.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Interface to the visitor through the test model.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IModelVisitor {
+
+ public void visit(ITestSuite testSuite);
+
+ public void leave(ITestSuite testSuite);
+
+ public void visit(ITestCase testCase);
+
+ public void leave(ITestCase testCase);
+
+ public void visit(ITestMessage testMessage);
+
+ public void leave(ITestMessage testMessage);
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestCase.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestCase.java
new file mode 100644
index 0000000000..8aea7d533c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestCase.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Interface to the test case (test) of the test hierarchy.
+ *
+ * Test cases stores the name, status, testing time and messages.
+ * Also has the reference to the parent test suite (if any).
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestCase extends ITestItem {
+
+ /**
+ * Returns test messages that were produced during the test case running.
+ *
+ * @return array of test messages
+ */
+ public ITestMessage[] getTestMessages();
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestItem.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestItem.java
new file mode 100644
index 0000000000..92d3d46ab8
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestItem.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Base interface to the structural item of test hierarchy (test suite or test
+ * case).
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestItem {
+
+ /**
+ * Represents status of the test item.
+ *
+ * @note Order of values is significant (cause enumeration values comparison
+ * is necessary)
+ */
+ public enum Status {
+ NotRun,
+ Skipped,
+ Passed,
+ Failed,
+ Aborted;
+
+ public boolean isError() {
+ return (this == Failed) || (this == Aborted);
+ }
+ }
+
+ /**
+ * @return name of the test item.
+ */
+ public String getName();
+
+ /**
+ * Returns status of the test item.
+ * For test case it is its own status.
+ * For test suite it is the greatest status of all its children.
+ *
+ * @return test item status
+ */
+ public Status getStatus();
+
+ /**
+ * Returns execution time (in milliseconds) of the test item.
+ * For test case it is its own execution time.
+ * For test suite it is the sum of execution time of all its children.
+ *
+ * @return item execution time (in milliseconds)
+ */
+ public int getTestingTime();
+
+ /**
+ * Returns parent of the current test item or null if not available
+ * (e.g. it is a root test suite).
+ *
+ * @return parent or null
+ */
+ public ITestSuite getParent();
+
+ /**
+ * Returns <code>true</code> if test item has children.
+ * Always returns <code>false</code> for test cases.
+ *
+ * @return true if has children
+ */
+ public boolean hasChildren();
+
+ /**
+ * Returns all the children of the test item.
+ * For test case always returns empty array.
+ * For test suite returns all child test suites and test cases.
+ *
+ * @return array of test item children
+ */
+ public ITestItem[] getChildren();
+
+ /**
+ * Visitor pattern support for the tests hierarchy.
+ *
+ * @param visitor - any object that supports visitor interface
+ */
+ public void visit(IModelVisitor visitor);
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestLocation.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestLocation.java
new file mode 100644
index 0000000000..133d15bf30
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestLocation.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Describes the location of the test object.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestLocation {
+
+ /**
+ * Returns the file name in which testing object is located.
+ *
+ * @return file name
+ */
+ public String getFile();
+
+ /**
+ * Returns the line number on which testing object is located.
+ *
+ * @return line number
+ */
+ public int getLine();
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestMessage.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestMessage.java
new file mode 100644
index 0000000000..60ba09219c
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestMessage.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Describes the message that was produced during the testing process.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestMessage {
+
+ /**
+ * The level of the test message.
+ */
+ public enum Level {
+ Info(ModelMessages.MessageLevel_info),
+ Message(ModelMessages.MessageLevel_message),
+ Warning(ModelMessages.MessageLevel_warning),
+ Error(ModelMessages.MessageLevel_error),
+ FatalError(ModelMessages.MessageLevel_fatal_error),
+ Exception(ModelMessages.MessageLevel_exception);
+
+ String stringRepr;
+
+ Level(String stringRepr) {
+ this.stringRepr = stringRepr;
+ }
+
+ @Override
+ public String toString() {
+ return stringRepr;
+ }
+ }
+
+ /**
+ * Returns the location of the test message.
+ *
+ * @return message location
+ */
+ public ITestLocation getLocation();
+
+ /**
+ * Returns the level of the test message.
+ *
+ * @return message level
+ */
+ public Level getLevel();
+
+ /**
+ * Returns the text of the test message.
+ *
+ * @return message text
+ */
+ public String getText();
+
+ /**
+ * Visitor pattern support for the tests hierarchy.
+ *
+ * @param visitor - any object that supports visitor interface
+ */
+ public void visit(IModelVisitor visitor);
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelAccessor.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelAccessor.java
new file mode 100644
index 0000000000..8a797c7423
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelAccessor.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Provides an access to the tests model.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestModelAccessor {
+
+ /**
+ * Checks whether the specified testing item (case or suite) is running now.
+ *
+ * @param item the interested item
+ * @return whether the item is running now
+ */
+ public boolean isCurrentlyRunning(ITestItem item);
+
+ /**
+ * Provides access to the root test suite.
+ *
+ * @return root test suite
+ */
+ public ITestSuite getRootSuite();
+
+ /**
+ * Adds the given listener to this registered listeners collection.
+ * Has no effect if an identical listener is already registered.
+ *
+ * @param listener the listener to add
+ */
+ public void addChangesListener(ITestingSessionListener listener);
+
+ /**
+ * Removes the given listener from registered listeners collection.
+ * Has no effect if the listener is not already registered.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeChangesListener(ITestingSessionListener listener);
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelUpdater.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelUpdater.java
new file mode 100644
index 0000000000..6cc419318a
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestModelUpdater.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * The interface to easily build or update testing model.
+ * It is intended to use from the Tests Runner provider plug-in.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestModelUpdater {
+
+ /**
+ * Specifies that a new test suite has been started.
+ *
+ * @param name the name of the started test suite
+ */
+ public void enterTestSuite(String name);
+
+ /**
+ * Specifies that the last test suite has been finished.
+ * Automatically exists from the currently running test case (if any).
+ */
+ public void exitTestSuite();
+
+ /**
+ * Specifies that a new test case has been started.
+ *
+ * @param name the name of the started test case
+ */
+ public void enterTestCase(String name);
+
+ /**
+ * Sets the status of the currently running test case.
+ * The exception is thrown if no test case is running.
+ *
+ * @param status new test status
+ */
+ public void setTestStatus(ITestItem.Status status);
+
+ /**
+ * Sets the execution time of the currently running test case.
+ * If the execution time has already been set, it will be overridden.
+ * The exception is thrown if no test case is running.
+ *
+ * @param testingTime test execution time
+ */
+ public void setTestingTime(int testingTime);
+
+ /**
+ * Specifies that the currently running test case has been finished.
+ * The test execution time is set if Tests Runner provider plug-in
+ * requires time measurement.
+ */
+ public void exitTestCase();
+
+ /**
+ * Add a new testing message connected to the currently running test case.
+ *
+ * @param file message file name
+ * @param line message line number
+ * @param level message level
+ * @param text message text
+ *
+ * @note If file name is <code>null</code> or empty or if line number is
+ * negative or 0 then message location will not be set.
+ */
+ public void addTestMessage(String file, int line, ITestMessage.Level level, String text);
+
+
+ /**
+ * Access the top most currently running test suite object.
+ *
+ * @return top most test suite
+ */
+ public ITestSuite currentTestSuite();
+
+ /**
+ * Access the currently running test case object.
+ *
+ * @return top most test case
+ */
+ public ITestCase currentTestCase();
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestSuite.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestSuite.java
new file mode 100644
index 0000000000..b2db06c594
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestSuite.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Interface to the test suite of the tests hierarchy.
+ * Test suites group the test cases and the other test suites.
+ * They also provides group operations (e.g. status or execution time access).
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestSuite extends ITestItem {
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSession.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSession.java
new file mode 100644
index 0000000000..fee3089860
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSession.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+import org.eclipse.cdt.testsrunner.launcher.ITestsRunnerProviderInfo;
+import org.eclipse.debug.core.ILaunch;
+
+
+/**
+ * Stores the information about tests running.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestingSession {
+
+ /**
+ * Returns the count of already finished tests.
+ *
+ * @return already finished tests count
+ */
+ public int getCurrentCounter();
+
+ /**
+ * Returns the total tests count (if available).
+ *
+ * @note Usually testing frameworks do not provide the information about
+ * total tests count (at least Boost.Test, Google Test and Qt Test do not).
+ * So the total tests count from previous launch of the same test module is
+ * used instead. That is why, it is unavailable for the first run and it may
+ * be not accurate. When testing is finished the total tests count is
+ * updated to the accurate value.
+ *
+ * @return total tests count or -1 if unavailable
+ */
+ public int getTotalCounter();
+
+ /**
+ * Returns the count tests with the specified status at the moment.
+ *
+ * @note Tests count with the specified status may change if testing session
+ * is not terminated.
+ *
+ * @param status the required status
+ * @return tests count with status 'status'
+ */
+ public int getCount(ITestItem.Status status);
+
+ /**
+ * Returns whether the testing session contains errors at the moment.
+ * Testing session may contain errors if one of its tests failed or if there
+ * were some errors during tests running (e.g. test module cannot be
+ * launched or output parsing failed).
+ *
+ * @return whether the testing session contains errors
+ */
+ public boolean hasErrors();
+
+ /**
+ * Returns whether the testing session was stopped by user.
+ *
+ * @note Testing session is not considered as stopped when it was terminated
+ * by the <code>ILaunch.terminate()</code> method (e.g. when user clicks on
+ * 'Stop' button of the 'Console' or 'Debug' view). In this case it will be
+ * considered as finished (probably, with errors cause not all output was
+ * obtained from launched process). To stop testing session properly the
+ * <code>stop()</code> method should be used.
+ *
+ * @return whether the testing session was stopped
+ */
+ public boolean wasStopped();
+
+ /**
+ * Returns whether the testing session has been finished (with or without
+ * errors).
+ *
+ * @return whether the testing session has been finished
+ */
+ public boolean isFinished();
+
+ /**
+ * Returns the testing model accessor that is associated with this session.
+ *
+ * @return testing model accessor
+ */
+ public ITestModelAccessor getModelAccessor();
+
+ /**
+ * Returns the launch that is associated with this testing session.
+ *
+ * @return launch
+ */
+ public ILaunch getLaunch();
+
+ /**
+ * Returns the information about the tests runner which was used to launch
+ * this testing session.
+ *
+ * @return tests runner information
+ */
+ public ITestsRunnerProviderInfo getTestsRunnerProviderInfo();
+
+ /**
+ * Returns the current status message for the current testing session. It
+ * may contain error, some session information or simple statistics.
+ *
+ * @return text status of the testing session
+ */
+ public String getStatusMessage();
+
+ /**
+ * Returns the name of the current testing session. Usually it contains
+ * launch configuration name with some additional information.
+ *
+ * @return testing session name
+ */
+ public String getName();
+
+ /**
+ * Stops the current session with a special status setting. Does nothing if
+ * the launched process of testing session has already been terminated or
+ * cannot been terminated.
+ */
+ public void stop();
+
+}
+
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSessionListener.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSessionListener.java
new file mode 100644
index 0000000000..b75b34c8d4
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ITestingSessionListener.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+/**
+ * Testing session listener is notified of testing process going.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITestingSessionListener {
+
+ /**
+ * Notifies the listener that the new test suite running is started.
+ *
+ * @param testSuite the started test suite
+ */
+ public void enterTestSuite(ITestSuite testSuite);
+
+ /**
+ * Notifies the listener that the test suite running is finished.
+ *
+ * @param testSuite the finished test suite
+ */
+ public void exitTestSuite(ITestSuite testSuite);
+
+ /**
+ * Notifies the listener that the new test case running is started.
+ *
+ * @param testCase the started test case
+ */
+ public void enterTestCase(ITestCase testCase);
+
+ /**
+ * Notifies the listener that the test case running is finished.
+ *
+ * @param testCase the finished test case
+ */
+ public void exitTestCase(ITestCase testCase);
+
+ /**
+ * Notifies the listener that the children of the test suite were updated.
+ *
+ * @param testSuite the test suite which require children update
+ */
+ public void childrenUpdate(ITestSuite testSuite);
+
+ /**
+ * Notifies the listener that the testing process is started.
+ */
+ public void testingStarted();
+
+ /**
+ * Notifies the listener that the testing process is finished.
+ */
+ public void testingFinished();
+
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.java
new file mode 100644
index 0000000000..eb1f39edf3
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ModelMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.testsrunner.model.ModelMessages"; //$NON-NLS-1$
+ public static String MessageLevel_error;
+ public static String MessageLevel_exception;
+ public static String MessageLevel_fatal_error;
+ public static String MessageLevel_info;
+ public static String MessageLevel_message;
+ public static String MessageLevel_warning;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, ModelMessages.class);
+ }
+
+ private ModelMessages() {
+ }
+}
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.properties
new file mode 100644
index 0000000000..05dfe24e33
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/ModelMessages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2011 Anton Gorenkov
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Anton Gorenkov - Initial implementation
+###############################################################################
+MessageLevel_error=Error
+MessageLevel_exception=Exception
+MessageLevel_fatal_error=Fatal error
+MessageLevel_info=Info
+MessageLevel_message=Message
+MessageLevel_warning=Warning
diff --git a/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/TestingException.java b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/TestingException.java
new file mode 100644
index 0000000000..5e3c4716ad
--- /dev/null
+++ b/testsrunner/org.eclipse.cdt.testsrunner/src/org/eclipse/cdt/testsrunner/model/TestingException.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Anton Gorenkov
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Anton Gorenkov - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.testsrunner.model;
+
+
+/**
+ * Represents a failure in the Tests Runner operations.
+ */
+public class TestingException extends Exception {
+
+ /**
+ * Constructs an exception with the given descriptive message.
+ *
+ * @param msg Description of the occurred exception.
+ */
+ public TestingException(String msg) {
+ super(msg);
+ }
+
+}

Back to the top