Skip to content

Commit

Permalink
Merge pull request #1179 from TestCentric/issue-1149
Browse files Browse the repository at this point in the history
Sort tree nodes by name or duration
  • Loading branch information
rowo360 authored Feb 9, 2025
2 parents c2f2ba4 + dd59d86 commit 06b5b40
Show file tree
Hide file tree
Showing 10 changed files with 462 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/TestCentric/testcentric.gui/Presenters/DisplayStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ namespace TestCentric.Gui.Presenters
using Model;
using Model.Settings;
using Views;
using Elements;
using System.IO;
using System.Linq;

/// <summary>
Expand Down Expand Up @@ -96,6 +94,10 @@ public virtual void OnTestRunStarting()

public virtual void OnTestRunFinished()
{
if (_view.SortCommand.SelectedItem == TreeViewNodeComparer.Duration)
{
_view.InvokeIfRequired(() => _view.Sort());
}
if (_settings.Gui.TestTree.ShowTestDuration)
_view.InvokeIfRequired(() => UpdateTreeNodeNames());
}
Expand Down
112 changes: 112 additions & 0 deletions src/TestCentric/testcentric.gui/Presenters/TreeViewNodeComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

using System.Collections;
using System.Windows.Forms;
using TestCentric.Gui.Model;

namespace TestCentric.Gui.Presenters
{
/// <summary>
/// This class is responsible for the sorting functionality of tree nodes
/// by providing different IComparer implementations.
/// </summary>
public class TreeViewNodeComparer
{
public const string Name = "Name";
public const string Duration = "Duration";
public const string Ascending = "Ascending";
public const string Descending = "Descending";


/// <summary>
/// Get a IComparer implementation used to sort the tree nodes
/// The sortModes are used by the context menu items in their Tag property
/// </summary>
public static IComparer GetComparer(ITestModel model, string sortMode, string sortDirection)
{
bool ascending = sortDirection == Ascending;

if (sortMode == Duration)
return new DurationComparer(model, ascending);

return new NameComparer(ascending);
}

/// <summary>
/// The NameComparer uses the Name of the TestNodes (either Namespace or class or method name)
/// It's invoked by Windows Forms for all nodes of one hierarchy level to provide a proper ordering
/// </summary>
private class NameComparer : IComparer
{
private bool _ascending;

internal NameComparer(bool ascending)
{
_ascending = ascending;
}

public int Compare(object x, object y)
{
TreeNode node1 = x as TreeNode;
TreeNode node2 = y as TreeNode;

if (!_ascending)
Swap(ref node1, ref node2);

if (node1 != null && node2 != null)
return node1.Text.CompareTo(node2.Text);

return 1;
}
}

/// <summary>
/// The DurationComparer uses the Duration of the TestResults
/// It no test results are available yet, it uses the Name.
/// </summary>
private class DurationComparer : IComparer
{
private ITestModel _model;
private bool _ascending;

internal DurationComparer(ITestModel model, bool ascending)
{
_model = model;
_ascending = ascending;
}

public int Compare(object x, object y)
{
TreeNode node1 = x as TreeNode;
TreeNode node2 = y as TreeNode;

if (!_ascending)
Swap(ref node1, ref node2);

TestNode testNode1 = node1?.Tag as TestNode;
TestNode testNode2 = node2?.Tag as TestNode;

if (testNode1 == null || testNode2 == null)
return 1;

ResultNode resultNode1 = _model.GetResultForTest(testNode1.Id);
ResultNode resultNode2 = _model.GetResultForTest(testNode2.Id);

if (resultNode1 != null && resultNode2 != null)
return resultNode1.Duration.CompareTo(resultNode2.Duration);

return node1.Text.CompareTo(node2.Text); ;
}
}

internal static void Swap<T>(ref T x, ref T y)
{
T tmp = x;
x = y;
y = tmp;
}
}
}
22 changes: 18 additions & 4 deletions src/TestCentric/testcentric.gui/Presenters/TreeViewPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@
// ***********************************************************************

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TestCentric.Common;

namespace TestCentric.Gui.Presenters
{
using Model;
using Views;
using Dialogs;
using System.Xml;
using System.Drawing;
using System.IO;
using TestCentric.Gui.Controls;
using System.Collections;

/// <summary>
/// TreeViewPresenter is the presenter for the TestTreeView
Expand Down Expand Up @@ -44,6 +41,7 @@ public TreeViewPresenter(ITestTreeView treeView, ITestModel model, ITreeDisplayS
_view.ShowCheckBoxes.Checked = _view.CheckBoxes = _treeSettings.ShowCheckBoxes;
_view.ShowTestDuration.Checked = _treeSettings.ShowTestDuration;
_view.AlternateImageSet = _treeSettings.AlternateImageSet;
UpdateTreeViewSortMode();

WireUpEvents();
}
Expand Down Expand Up @@ -172,6 +170,10 @@ private void WireUpEvents()
Strategy?.UpdateTreeNodeNames();
};

_view.SortCommand.SelectionChanged += () => UpdateTreeViewSortMode();

_view.SortDirectionCommand.SelectionChanged += () => UpdateTreeViewSortMode();

_view.RunContextCommand.Execute += () =>
{
if (_view.ContextNode != null)
Expand Down Expand Up @@ -300,6 +302,18 @@ private void WireUpEvents()
//};
}

private void UpdateTreeViewSortMode()
{
var sortMode = _view.SortCommand.SelectedItem;

// Activate 'ShowTestDuration' in case sort by duration is selected
if (sortMode == TreeViewNodeComparer.Duration)
_view.ShowTestDuration.Checked = true;

IComparer comparer = TreeViewNodeComparer.GetComparer(_model, sortMode, _view.SortDirectionCommand.SelectedItem);
_view.Sort(comparer);
}

private void UpdateTreeSettingsFromVisualState(VisualState visualState)
{
_treeSettings.DisplayFormat = visualState.DisplayStrategy;
Expand Down
7 changes: 7 additions & 0 deletions src/TestCentric/testcentric.gui/Views/ITestTreeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace TestCentric.Gui.Views
{
using System.Collections;
using System.Collections.Generic;
using Elements;

Expand All @@ -29,6 +30,9 @@ public interface ITestTreeView : IView
IToolStripMenu ActiveConfiguration { get; }
IChecked ShowCheckBoxes { get; }
IChecked ShowTestDuration { get; }
ISelection SortCommand { get; }
ISelection SortDirectionCommand { get; }

ICommand ExpandAllCommand { get; }
ICommand CollapseAllCommand { get; }
ICommand CollapseToFixturesCommand { get; }
Expand Down Expand Up @@ -66,6 +70,9 @@ public interface ITestTreeView : IView
void Add(TreeNode treeNode);
void ExpandAll();
void CollapseAll();

void Sort();
void Sort(IComparer comparer);
void SetImageIndex(TreeNode treeNode, int imageIndex);

/// <summary>
Expand Down
73 changes: 73 additions & 0 deletions src/TestCentric/testcentric.gui/Views/TestTreeView.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions src/TestCentric/testcentric.gui/Views/TestTreeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace TestCentric.Gui.Views
{
using System;
using System.Collections;
using System.Collections.Generic;
using Elements;

Expand Down Expand Up @@ -48,6 +49,8 @@ public TestTreeView()
CollapseToFixturesCommand = new CommandMenuElement(collapseToFixturesMenuItem);
TestPropertiesCommand = new CommandMenuElement(testPropertiesMenuItem);
ViewAsXmlCommand = new CommandMenuElement(viewAsXmlMenuItem);
SortCommand = new CheckedToolStripMenuGroup("Sort", sortByNameMenuItem, sortByDurationMenuItem);
SortDirectionCommand = new CheckedToolStripMenuGroup("SortDirection", sortAscendingMenuItem, sortDescendingMenuItem);
OutcomeFilter = new MultiCheckedToolStripButtonGroup(new[] { filterOutcomePassedButton, filterOutcomeFailedButton, filterOutcomeWarningButton, filterOutcomeNotRunButton });
TextFilter = new ToolStripTextBoxElement(filterTextBox, "Filter...");
CategoryFilter = new ToolStripCategoryFilterButton(filterByCategory);
Expand Down Expand Up @@ -119,6 +122,9 @@ public bool CheckBoxes
public IToolStripMenu ActiveConfiguration { get; private set; }
public IChecked ShowCheckBoxes { get; private set; }
public IChecked ShowTestDuration { get; private set; }

public ISelection SortCommand { get; private set; }
public ISelection SortDirectionCommand { get; private set; }
public ICommand ExpandAllCommand { get; private set; }
public ICommand CollapseAllCommand { get; private set; }
public ICommand CollapseToFixturesCommand { get; private set; }
Expand Down Expand Up @@ -245,6 +251,28 @@ public void LoadAlternateImages(string imageSet)
this.Refresh();
}

/// <summary>
/// Apply the current active TreeViewNodeSorter to sort the tree view
/// </summary>
public void Sort()
{
// Restore selected node after tree sorting
var selectedNode = treeView.SelectedNode;
treeView.Sort();
treeView.SelectedNode = selectedNode;
}

/// <summary>
/// Set a comparer as the TreeViewNodeSorter to sort the tree view
/// </summary>
public void Sort(IComparer comparer)
{
// Restore selected node after tree sorting
var selectedNode = treeView.SelectedNode;
treeView.TreeViewNodeSorter = comparer;
treeView.SelectedNode = selectedNode;
}

#endregion

#region Helper Methods
Expand Down
Loading

0 comments on commit 06b5b40

Please sign in to comment.