From 26d90e4907c64876821f1f09090e798a02e7ab10 Mon Sep 17 00:00:00 2001 From: Roman Chernyatchik Date: Sat, 16 Aug 2008 12:26:14 +0400 Subject: [PATCH] Ruby test runner: Navigation between testsuites in statistics tab was added. --- .../testunit/runner/ui/RTestUnitResultsForm.java | 44 ++++-- .../ui/RTestUnitTestProxySelectionListener.java | 12 ++ .../runner/ui/RTestUnitUIActionsHandler.java | 7 +- .../runner/ui/statistics/ColumnResults.java | 5 +- .../ui/statistics/RTestUnitStatisticsPanel.java | 121 ++++++++++++++ .../runner/ui/RTestUnitUIActionsHandlerTest.java | 4 +- .../statistics/RTestUnitStatisticsPanelTest.java | 173 +++++++++++++++++++++ 7 files changed, 350 insertions(+), 16 deletions(-) create mode 100644 plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitTestProxySelectionListener.java create mode 100644 plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanelTest.java diff --git a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitResultsForm.java b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitResultsForm.java index 088d836aef..74f6d300a2 100644 --- a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitResultsForm.java +++ b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitResultsForm.java @@ -25,6 +25,7 @@ import com.intellij.ui.TabbedPaneWrapper; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.ruby.support.UIUtil; import org.jetbrains.plugins.ruby.testing.testunit.runConfigurations.RTestUnitRunConfiguration; import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitEventsListener; import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitTestProxy; @@ -56,7 +57,7 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso private ColorProgressBar myProgressLine; private JLabel myStatusLabel; private JPanel toolbarPanel; - private RTestUnitTestTreeView tree; + private RTestUnitTestTreeView myTreeView; private JPanel myTabbedPaneConatiner; private final TestsProgressAnimator myAnimator; @@ -113,10 +114,10 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso myTabbedPaneConatiner.add(myTabbedPane.getComponent()); // Setup tests tree - tree.setLargeModel(true); - tree.attachToModel(this); + myTreeView.setLargeModel(true); + myTreeView.attachToModel(this); final RTestUnitTreeStructure structure = new RTestUnitTreeStructure(project, myTestsRootNode); - myTreeBuilder = new RTestUnitTreeBuilder(tree, structure); + myTreeBuilder = new RTestUnitTreeBuilder(myTreeView, structure); myAnimator = new MyAnimator(myTreeBuilder); myToolbar = initToolbarPanel(consoleProperties, runnerSettings, configurationSettings); @@ -125,7 +126,7 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso } public void addTestsTreeSelectionListener(final TreeSelectionListener listener) { - tree.getSelectionModel().addTreeSelectionListener(listener); + myTreeView.getSelectionModel().addTreeSelectionListener(listener); } public void attachToProcess(final ProcessHandler processHandler) { @@ -152,8 +153,10 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso public void addTestsProxySelectionListener(final TestProxyTreeSelectionListener listener) { addTestsTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(final TreeSelectionEvent e) { - //TODO - //if (tree.isFocusOwner()) { + //We should fire event only if it was generated by this component, + //e.g. it is focused. Otherwise it is side effect of selecing proxy in + //try by other component + //if (myTreeView.isFocusOwner()) { final PrintableTestProxy selectedProxy = (PrintableTestProxy)getTreeView().getSelectedTest(); listener.onSelected(selectedProxy); //} @@ -245,7 +248,7 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso myAnimator.stopMovie(); - tree.repaint(); + myTreeView.repaint(); LvcsHelper.addLabel(this); @@ -331,7 +334,7 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso } public TestTreeView getTreeView() { - return tree; + return myTreeView; } public boolean hasTestSuites() { @@ -343,6 +346,11 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso return myTestsRootNode; } + /** + * Will select proxy in Event Dispatch Thread. Invocation of this + * method may be not in event dispatch thread + * @param testProxy Test or suite + */ public void selectAndNotify(@Nullable final AbstractTestProxy testProxy) { //is used by Test Runner actions - go to next failed, passed, first failed, etc //if (testProxy != getTestsRootNode()) { @@ -476,6 +484,24 @@ public class RTestUnitResultsForm implements TestFrameworkRunningModel, LogConso myTreeBuilder.performUpdate(); } + public RTestUnitTestProxySelectionListener createSelectionListener() { + return new RTestUnitTestProxySelectionListener() { + public void onSelected(@Nullable final RTestUnitTestProxy selectedTestProxy, + final boolean requestFocus) { + UIUtil.addToInvokeLater(new Runnable() { + public void run() { + selectAndNotify(selectedTestProxy); + + // Request focus if necessary + if (requestFocus) { + myTreeView.requestFocusInWindow(); + } + } + }); + } + }; + } + private static class MyAnimator extends TestsProgressAnimator { public MyAnimator(final AbstractTestTreeBuilder builder) { diff --git a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitTestProxySelectionListener.java b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitTestProxySelectionListener.java new file mode 100644 index 0000000000..da31ca63f0 --- /dev/null +++ b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitTestProxySelectionListener.java @@ -0,0 +1,12 @@ +package org.jetbrains.plugins.ruby.testing.testunit.runner.ui; + +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitTestProxy; + +/** + * @author Roman Chernyatchik + */ +public interface RTestUnitTestProxySelectionListener { + void onSelected(@Nullable final RTestUnitTestProxy selectedTestProxy, + final boolean requestFocus); +} diff --git a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandler.java b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandler.java index 58a48118ae..0d075cd1bc 100644 --- a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandler.java +++ b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandler.java @@ -44,10 +44,9 @@ public class RTestUnitUIActionsHandler implements TestResultsViewer.EventsListen if (TestConsoleProperties.SELECT_FIRST_DEFECT.value(myConsoleProperties)) { final AbstractTestProxy firstDefect = Filter.DEFECTIVE_LEAF.detectIn(testsRootNode.getAllTests()); - testProxy = firstDefect != null ? firstDefect : testsRootNode; - } else { - testProxy = testsRootNode; + if (firstDefect != null) { + sender.selectAndNotify(firstDefect); + } } - sender.selectAndNotify(testProxy); } } diff --git a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/ColumnResults.java b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/ColumnResults.java index 518a37f6d5..2eade62a00 100644 --- a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/ColumnResults.java +++ b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/ColumnResults.java @@ -19,7 +19,10 @@ public class ColumnResults extends ColumnInfo { ////TODO sort // @Nullable //public Comparator getComparator(){ - // return null; + // return new Comparator() { + // public int compare(final RTestUnitTestProxy o1, final RTestUnitTestProxy o2) { + // } + // }; //} public ColumnResults() { diff --git a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanel.java b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanel.java index 58edb8aecf..add166a7f8 100644 --- a/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanel.java +++ b/plugins/ruby/src/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanel.java @@ -4,9 +4,16 @@ import com.intellij.execution.testframework.TestsUIUtil; import com.intellij.ui.table.TableView; import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitEventsListener; import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitTestProxy; +import org.jetbrains.plugins.ruby.testing.testunit.runner.ui.RTestUnitTestProxySelectionListener; import org.jetbrains.plugins.ruby.testing.testunit.runner.ui.TestProxyTreeSelectionListener; +import org.jetbrains.plugins.ruby.support.UIUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; /** * @author Roman Chernyatchik @@ -18,10 +25,32 @@ public class RTestUnitStatisticsPanel extends JPanel { private JPanel myContentPane; private RTestUnitStatisticsTableModel myTableModel; + private final List mySelectionListeners = new ArrayList(); public RTestUnitStatisticsPanel() { myTableModel = new RTestUnitStatisticsTableModel(); myStatisticsTableView.setModel(myTableModel); + myStatisticsTableView.addMouseListener(new MouseAdapter(){ + @Override + public void mouseClicked(final MouseEvent e) { + if (e.getClickCount() == 2) { + final Collection proxies = myStatisticsTableView.getSelection(); + if (proxies.isEmpty()) { + return; + } + + fireOnSelectionChanged(proxies.iterator().next()); + } + } + }); + + // Fire selection changed and move focus on SHIFT+ENTER + final KeyStroke shiftEnterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK); + registerAsAction(shiftEnterKey, "change-selection-on-test-proxy", createChangeSelectionAction()); + + // Expand selected or go to parent on ENTER + final KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); + registerAsAction(enterKey, "go-to-selected-suite-or-parent", createGotoSuiteOrParentAction()); } public JPanel getContentPane() { @@ -36,7 +65,99 @@ public class RTestUnitStatisticsPanel extends JPanel { return myTableModel.createTestEventsListener(); } + public void addSelectionListener(final RTestUnitTestProxySelectionListener listener) { + mySelectionListeners.add(listener); + } + + protected Runnable createChangeSelectionAction() { + // Change selection + return new Runnable() { + public void run() { + final Collection proxies = myStatisticsTableView.getSelection(); + if (proxies.isEmpty()) { + return; + } + final RTestUnitTestProxy proxy = proxies.iterator().next(); + myStatisticsTableView.clearSelection(); + fireOnSelectionChanged(proxy); + } + }; + } + + protected Runnable createGotoSuiteOrParentAction() { + final TestProxyTreeSelectionListener selectionListener = createSelectionListener(); + + // Expand selected or go to parent + return new Runnable() { + public void run() { + final RTestUnitTestProxy selectedProxy = getSelectedItem(); + if (selectedProxy == null) { + return; + } + + final int i = myStatisticsTableView.getSelectedRow(); + assert i >= 0; //because something is selected + + // If first line is selected we should go to parent suite + if (ColumnTest.TestsCellRenderer.isFirstLine(i)) { + final RTestUnitTestProxy parentSuite = selectedProxy.getParent(); + if (parentSuite != null) { + showInTableAndSelectFirstRow(parentSuite, selectionListener); + } + } else { + // if selected element is suite - we should expand it + if (selectedProxy.isSuite()) { + showInTableAndSelectFirstRow(selectedProxy, selectionListener); + } + } + } + }; + } + + /** + * Selects row in table + * @param rowIndex Row's index + */ + protected void selectRow(final int rowIndex) { + UIUtil.addToInvokeLater(new Runnable() { + public void run() { + // updates model + myStatisticsTableView.setRowSelectionInterval(rowIndex, rowIndex); + } + }); + } + + @Nullable + protected RTestUnitTestProxy getSelectedItem() { + return myStatisticsTableView.getSelectedObject(); + } + + private void fireOnSelectionChanged(final RTestUnitTestProxy selectedTestProxy) { + for (RTestUnitTestProxySelectionListener listener : mySelectionListeners) { + listener.onSelected(selectedTestProxy, true); + } + } + private void createUIComponents() { myStatisticsTableView = new TableView(); } + + private void registerAsAction(final KeyStroke keyStroke, + final String actionKey, + final Runnable action) { + final InputMap inputMap = myStatisticsTableView.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + inputMap.put(keyStroke, actionKey); + myStatisticsTableView.getActionMap().put(inputMap.get(keyStroke), new AbstractAction() { + public void actionPerformed(final ActionEvent e) { + action.run(); + } + }); + } + + private void showInTableAndSelectFirstRow(final RTestUnitTestProxy suite, + final TestProxyTreeSelectionListener selectionListener) { + selectionListener.onSelected(suite); + selectRow(0); + } } diff --git a/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandlerTest.java b/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandlerTest.java index 1196abbfc8..d6ad18e03b 100644 --- a/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandlerTest.java +++ b/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/RTestUnitUIActionsHandlerTest.java @@ -218,7 +218,7 @@ public class RTestUnitUIActionsHandlerTest extends BaseRUnitTestsTestCase { //failed test 2 - final RTestUnitTestProxy testFailed2 = createTestProxy("testFailed1", testsSuite); + final RTestUnitTestProxy testFailed2 = createTestProxy("testFailed2", testsSuite); testFailed2.setStarted(); myUIActionsHandler.onTestNodeAdded(myResultsViewer, testFailed2); assertEquals(testFailed2, mySelectedTestProxy); @@ -238,6 +238,6 @@ public class RTestUnitUIActionsHandlerTest extends BaseRUnitTestsTestCase { //testing finished myUIActionsHandler.onTestingFinished(myResultsViewer); - assertEquals(myResultsViewer.getTestsRootNode(), mySelectedTestProxy); + assertEquals(lastSelectedTest, mySelectedTestProxy); } } diff --git a/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanelTest.java b/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanelTest.java new file mode 100644 index 0000000000..4df194f6c3 --- /dev/null +++ b/plugins/ruby/testSrc/org/jetbrains/plugins/ruby/testing/testunit/runner/ui/statistics/RTestUnitStatisticsPanelTest.java @@ -0,0 +1,173 @@ +package org.jetbrains.plugins.ruby.testing.testunit.runner.ui.statistics; + +import com.intellij.openapi.util.Ref; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.ruby.Marker; +import org.jetbrains.plugins.ruby.testing.testunit.runner.BaseRUnitTestsTestCase; +import org.jetbrains.plugins.ruby.testing.testunit.runner.RTestUnitTestProxy; +import org.jetbrains.plugins.ruby.testing.testunit.runner.ui.RTestUnitTestProxySelectionListener; +import org.jetbrains.plugins.ruby.testing.testunit.runner.ui.TestProxyTreeSelectionListener; + +/** + * @author Roman Chernyatchik + */ +public class RTestUnitStatisticsPanelTest extends BaseRUnitTestsTestCase { + private RTestUnitStatisticsPanel myRTestUnitStatisticsPanel; + private TestProxyTreeSelectionListener mySelectionListener; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + myRTestUnitStatisticsPanel = new RTestUnitStatisticsPanel(); + mySelectionListener = myRTestUnitStatisticsPanel.createSelectionListener(); + } + + public void testGotoSuite_OnTest() { + // create test sturcure + final RTestUnitTestProxy rootSuite = createSuiteProxy("rootSuite"); + final RTestUnitTestProxy suite1 = createSuiteProxy("suite1", rootSuite); + final RTestUnitTestProxy test1 = createTestProxy("test1", suite1); + + // show suite in table + mySelectionListener.onSelected(suite1); + // selects row that corresponds to test1 + myRTestUnitStatisticsPanel.selectRow(1); + + // Check that necessary row is selected + assertEquals(test1, myRTestUnitStatisticsPanel.getSelectedItem()); + + // Perform action on test + myRTestUnitStatisticsPanel.createGotoSuiteOrParentAction().run(); + + // Check that current suite in table wasn't changed. + // For it let's select Total row and check selected object + myRTestUnitStatisticsPanel.selectRow(0); + assertEquals(suite1, myRTestUnitStatisticsPanel.getSelectedItem()); + } + + public void testGotoSuite_OnSuite() { + // create test sturcure + final RTestUnitTestProxy rootSuite = createSuiteProxy("rootSuite"); + final RTestUnitTestProxy suite1 = createSuiteProxy("suite1", rootSuite); + + // show root suite in table + mySelectionListener.onSelected(rootSuite); + // selects row that corresponds to suite1 + myRTestUnitStatisticsPanel.selectRow(1); + + // Check that necessary row is selected + assertEquals(suite1, myRTestUnitStatisticsPanel.getSelectedItem()); + + // Perform action on suite + myRTestUnitStatisticsPanel.createGotoSuiteOrParentAction().run(); + + // Check that current suite in table was changed. + // For it let's select Total row and check selected object + myRTestUnitStatisticsPanel.selectRow(0); + assertEquals(suite1, myRTestUnitStatisticsPanel.getSelectedItem()); + } + + public void testGotoParentSuite_Total() { + // create test sturcure + final RTestUnitTestProxy rootSuite = createSuiteProxy("rootSuite"); + final RTestUnitTestProxy suite1 = createSuiteProxy("suite1", rootSuite); + + // show suite in table + mySelectionListener.onSelected(suite1); + // selects Total row + myRTestUnitStatisticsPanel.selectRow(0); + + // Check that necessary row is selected + assertEquals(suite1, myRTestUnitStatisticsPanel.getSelectedItem()); + + // Perform action on suite + myRTestUnitStatisticsPanel.createGotoSuiteOrParentAction().run(); + + // Check that current suite in table was changed. + // For it let's select Total row and check selected object + myRTestUnitStatisticsPanel.selectRow(0); + assertEquals(rootSuite, myRTestUnitStatisticsPanel.getSelectedItem()); + } + + public void testGotoParentSuite_TotalRoot() { + // create test sturcure + final RTestUnitTestProxy rootSuite = createSuiteProxy("rootSuite"); + createSuiteProxy("suite1", rootSuite); + + // show root suite in table + mySelectionListener.onSelected(rootSuite); + // selects Total row + myRTestUnitStatisticsPanel.selectRow(0); + + // Check that necessary row is selected + assertEquals(rootSuite, myRTestUnitStatisticsPanel.getSelectedItem()); + + // Perform action on suite + myRTestUnitStatisticsPanel.createGotoSuiteOrParentAction().run(); + + // Check that current suite in table wasn't changed. + // For it let's select Total row and check selected object + myRTestUnitStatisticsPanel.selectRow(0); + assertEquals(rootSuite, myRTestUnitStatisticsPanel.getSelectedItem()); + } + + public void testChangeSelectionAction() { + final Marker onSelectedHappend = new Marker(); + final Ref proxyRef = new Ref(); + final Ref focusRequestedRef = new Ref(); + + myRTestUnitStatisticsPanel.addSelectionListener(new RTestUnitTestProxySelectionListener() { + public void onSelected(@Nullable final RTestUnitTestProxy selectedTestProxy, final boolean requestFocus) { + onSelectedHappend.set(); + proxyRef.set(selectedTestProxy); + focusRequestedRef.set(requestFocus); + } + }); + + // create data fixture + final RTestUnitTestProxy rootSuite = createSuiteProxy("rootSuite"); + final RTestUnitTestProxy suite1 = createSuiteProxy("suite1", rootSuite); + final RTestUnitTestProxy test1 = createTestProxy("test1", suite1); + + //on test + mySelectionListener.onSelected(suite1); + myRTestUnitStatisticsPanel.selectRow(1); + assertEquals(test1, myRTestUnitStatisticsPanel.getSelectedItem()); + + myRTestUnitStatisticsPanel.createChangeSelectionAction().run(); + assertTrue(onSelectedHappend.isSet()); + assertEquals(test1, proxyRef.get()); + assertTrue(focusRequestedRef.get()); + + //on suite + //reset markers + onSelectedHappend.reset(); + proxyRef.set(null); + focusRequestedRef.set(null); + + mySelectionListener.onSelected(rootSuite); + myRTestUnitStatisticsPanel.selectRow(1); + assertEquals(suite1, myRTestUnitStatisticsPanel.getSelectedItem()); + + myRTestUnitStatisticsPanel.createChangeSelectionAction().run(); + assertTrue(onSelectedHappend.isSet()); + assertEquals(suite1, proxyRef.get()); + assertTrue(focusRequestedRef.get()); + + //on Total + //reset markers + onSelectedHappend.reset(); + proxyRef.set(null); + focusRequestedRef.set(null); + + mySelectionListener.onSelected(rootSuite); + myRTestUnitStatisticsPanel.selectRow(0); + assertEquals(rootSuite, myRTestUnitStatisticsPanel.getSelectedItem()); + + myRTestUnitStatisticsPanel.createChangeSelectionAction().run(); + assertTrue(onSelectedHappend.isSet()); + assertEquals(rootSuite, proxyRef.get()); + assertTrue(focusRequestedRef.get()); + } +} -- 2.11.4.GIT