Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UI elements for textual filtering of tests #1166

Merged
merged 3 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

using System.Drawing;
using System.Windows.Forms;
using System;

namespace TestCentric.Gui.Controls
{
/// <summary>
/// This class is required to stretch a ToolStripTextBox control within a ToolStrip to fill the available space and to resize when the control resizes.
/// The implementation is from the Microsoft Windows Forms documentation, but simplified to the current use case.
/// "How to: Stretch a ToolStripTextBox to Fill the Remaining Width of a ToolStrip"
/// https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/stretch-a-toolstriptextbox-to-fill-the-remaining-width-of-a-toolstrip-wf?view=netframeworkdesktop-4.8
/// </summary>
internal class StretchToolStripTextBox : ToolStripTextBox
{
public override Size GetPreferredSize(Size constrainingSize)
{
// Get width of the owning ToolStrip
int textBoxMargin = 2;
Int32 width = Owner.DisplayRectangle.Width - textBoxMargin;

// If the available width is less than the default width, use the default width
if (width < DefaultSize.Width) width = DefaultSize.Width;

// Retrieve the preferred size from the base class, but change the width to the calculated width.
Size size = base.GetPreferredSize(constrainingSize);
size.Width = width;
return size;
}
}
}
19 changes: 19 additions & 0 deletions src/TestCentric/testcentric.gui/Elements/IChanged.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

namespace TestCentric.Gui.Elements
{
/// <summary>
/// The IChanged interface represents a IViewElement.
/// If the IViewElement changes, it will raise the Changed event.
/// </summary>
public interface IChanged : IViewElement
{
/// <summary>
/// Event raised when the element is changed by the user
/// </summary>
event CommandHandler Changed;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************


using System;
using System.Windows.Forms;

namespace TestCentric.Gui.Elements
{
/// <summary>
/// This class implements the IChanged interface for a ToolStripTextBox control. It provides this additional functionality:
/// - show a PlaceHoder text if there's no text input
/// - Invoke the Changed event as soon as no further input is made within a short period of time.
/// </summary>
public class ToolStripTextBoxElement : ToolStripElement, IChanged
{
private Timer _typingTimer;

public event CommandHandler Changed;

public ToolStripTextBoxElement(ToolStripTextBox textBox, string placeHolderText)
: base(textBox)
{
TextBox = textBox;
PlaceHolderText = placeHolderText;
TextBox.TextChanged += OnTextChanged;

TextBox.LostFocus += OnTextBoxLostFocus;
TextBox.GotFocus += OnTextBoxGotFocus;

// Call LostFocus to set initial text and color
OnTextBoxLostFocus(null, EventArgs.Empty);
}

private string PlaceHolderText { get; set; }

private ToolStripTextBox TextBox { get; }

private bool IsPlaceHolderTextShown { get; set; }

private void OnTextBoxGotFocus(object sender, EventArgs e)
{
// If the PlaceHolderText is shown, replace it with an empty text
if (IsPlaceHolderTextShown)
{
TextBox.Text = "";
TextBox.ForeColor = System.Drawing.Color.Black;
IsPlaceHolderTextShown = false;
}
}

private void OnTextBoxLostFocus(object sender, EventArgs e)
{
// If there's no text input, show the PlaceHolderText instead
string searchText = TextBox.Text;
if (string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(PlaceHolderText))
{
IsPlaceHolderTextShown = true;
TextBox.Text = PlaceHolderText;
TextBox.ForeColor = System.Drawing.Color.LightGray;
}
}

private void OnTextChanged(object sender, EventArgs e)
{
if (IsPlaceHolderTextShown)
return;

if (_typingTimer == null)
{
_typingTimer = new Timer();
_typingTimer.Interval = 600;
_typingTimer.Tick += TypingTimerTimeout;
}

_typingTimer.Stop();
_typingTimer.Start();
}

private void TypingTimerTimeout(object sender, EventArgs e)
{
var timer = sender as Timer;
if (timer == null)
return;

// The timer must be stopped!
timer.Stop();
if (Changed != null)
Changed();

TextBox.Focus();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ private void WireUpEvents()
_model.TestCentricTestFilter.OutcomeFilter = filter;
};

_view.TextFilter.Changed += () =>
{
var text = _view.TextFilter.Text;
_model.TestCentricTestFilter.TextFilter = text;
};

// Node selected in tree
//_treeView.SelectedNodesChanged += (nodes) =>
//{
Expand Down
2 changes: 2 additions & 0 deletions src/TestCentric/testcentric.gui/Views/ITestTreeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public interface ITestTreeView : IView
// Test Filter related properties / methods
IMultiSelection OutcomeFilter { get; }

IChanged TextFilter { get; }

void SetTestFilterVisibility(bool visible);

// Tree-related Methods
Expand Down
23 changes: 23 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.

4 changes: 4 additions & 0 deletions src/TestCentric/testcentric.gui/Views/TestTreeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public TestTreeView()
TestPropertiesCommand = new CommandMenuElement(testPropertiesMenuItem);
ViewAsXmlCommand = new CommandMenuElement(viewAsXmlMenuItem);
OutcomeFilter = new MultiCheckedToolStripButtonGroup(new[] { filterOutcomePassedButton, filterOutcomeFailedButton, filterOutcomeWarningButton, filterOutcomeNotRunButton });
TextFilter = new ToolStripTextBoxElement(filterTextBox, "Filter...");
TreeView = treeView;

// NOTE: We use MouseDown here rather than MouseUp because
Expand Down Expand Up @@ -127,6 +128,8 @@ public bool CheckBoxes

public IMultiSelection OutcomeFilter { get; private set; }

public IChanged TextFilter { get; private set; }

public TreeNode ContextNode { get; private set; }
public ContextMenuStrip TreeContextMenu => TreeView.ContextMenuStrip;

Expand Down Expand Up @@ -205,6 +208,7 @@ public void InvokeIfRequired(MethodInvoker _delegate)
public void SetTestFilterVisibility(bool isVisible)
{
filterToolStrip.Visible = isVisible;
filterTextToolStrip.Visible = isVisible;
}

public void LoadAlternateImages(string imageSet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ public void OutcomeFilterChanged_ApplyFilter()
_model.TestCentricTestFilter.Received().OutcomeFilter = selectedItems;
}

[Test]
public void TextFilterChanged_ApplyFilter()
{
// 1. Arrange
_view.TextFilter.Text.Returns("TestA");

// 2. Act
_view.TextFilter.Changed += Raise.Event<CommandHandler>();

// 3. Assert
_model.TestCentricTestFilter.Received().TextFilter = "TestA";
}

// TODO: Version 1 Test - Make it work if needed.
//[Test]
//public void WhenContextNodeIsNotNull_RunCommandExecutesThatTest()
Expand Down