Skip to content

Commit 8d60a2c

Browse files
authored
Merge pull request #1166 from TestCentric/issue-1161
Add UI elements for textual filtering of tests
2 parents 5ab4979 + ea469cf commit 8d60a2c

File tree

8 files changed

+198
-0
lines changed

8 files changed

+198
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// ***********************************************************************
2+
// Copyright (c) Charlie Poole and TestCentric contributors.
3+
// Licensed under the MIT License. See LICENSE file in root directory.
4+
// ***********************************************************************
5+
6+
using System.Drawing;
7+
using System.Windows.Forms;
8+
using System;
9+
10+
namespace TestCentric.Gui.Controls
11+
{
12+
/// <summary>
13+
/// This class is required to stretch a ToolStripTextBox control within a ToolStrip to fill the available space and to resize when the control resizes.
14+
/// The implementation is from the Microsoft Windows Forms documentation, but simplified to the current use case.
15+
/// "How to: Stretch a ToolStripTextBox to Fill the Remaining Width of a ToolStrip"
16+
/// 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
17+
/// </summary>
18+
internal class StretchToolStripTextBox : ToolStripTextBox
19+
{
20+
public override Size GetPreferredSize(Size constrainingSize)
21+
{
22+
// Get width of the owning ToolStrip
23+
int textBoxMargin = 2;
24+
Int32 width = Owner.DisplayRectangle.Width - textBoxMargin;
25+
26+
// If the available width is less than the default width, use the default width
27+
if (width < DefaultSize.Width) width = DefaultSize.Width;
28+
29+
// Retrieve the preferred size from the base class, but change the width to the calculated width.
30+
Size size = base.GetPreferredSize(constrainingSize);
31+
size.Width = width;
32+
return size;
33+
}
34+
}
35+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// ***********************************************************************
2+
// Copyright (c) Charlie Poole and TestCentric contributors.
3+
// Licensed under the MIT License. See LICENSE file in root directory.
4+
// ***********************************************************************
5+
6+
namespace TestCentric.Gui.Elements
7+
{
8+
/// <summary>
9+
/// The IChanged interface represents a IViewElement.
10+
/// If the IViewElement changes, it will raise the Changed event.
11+
/// </summary>
12+
public interface IChanged : IViewElement
13+
{
14+
/// <summary>
15+
/// Event raised when the element is changed by the user
16+
/// </summary>
17+
event CommandHandler Changed;
18+
}
19+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// ***********************************************************************
2+
// Copyright (c) Charlie Poole and TestCentric contributors.
3+
// Licensed under the MIT License. See LICENSE file in root directory.
4+
// ***********************************************************************
5+
6+
7+
using System;
8+
using System.Windows.Forms;
9+
10+
namespace TestCentric.Gui.Elements
11+
{
12+
/// <summary>
13+
/// This class implements the IChanged interface for a ToolStripTextBox control. It provides this additional functionality:
14+
/// - show a PlaceHoder text if there's no text input
15+
/// - Invoke the Changed event as soon as no further input is made within a short period of time.
16+
/// </summary>
17+
public class ToolStripTextBoxElement : ToolStripElement, IChanged
18+
{
19+
private Timer _typingTimer;
20+
21+
public event CommandHandler Changed;
22+
23+
public ToolStripTextBoxElement(ToolStripTextBox textBox, string placeHolderText)
24+
: base(textBox)
25+
{
26+
TextBox = textBox;
27+
PlaceHolderText = placeHolderText;
28+
TextBox.TextChanged += OnTextChanged;
29+
30+
TextBox.LostFocus += OnTextBoxLostFocus;
31+
TextBox.GotFocus += OnTextBoxGotFocus;
32+
33+
// Call LostFocus to set initial text and color
34+
OnTextBoxLostFocus(null, EventArgs.Empty);
35+
}
36+
37+
private string PlaceHolderText { get; set; }
38+
39+
private ToolStripTextBox TextBox { get; }
40+
41+
private bool IsPlaceHolderTextShown { get; set; }
42+
43+
private void OnTextBoxGotFocus(object sender, EventArgs e)
44+
{
45+
// If the PlaceHolderText is shown, replace it with an empty text
46+
if (IsPlaceHolderTextShown)
47+
{
48+
TextBox.Text = "";
49+
TextBox.ForeColor = System.Drawing.Color.Black;
50+
IsPlaceHolderTextShown = false;
51+
}
52+
}
53+
54+
private void OnTextBoxLostFocus(object sender, EventArgs e)
55+
{
56+
// If there's no text input, show the PlaceHolderText instead
57+
string searchText = TextBox.Text;
58+
if (string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(PlaceHolderText))
59+
{
60+
IsPlaceHolderTextShown = true;
61+
TextBox.Text = PlaceHolderText;
62+
TextBox.ForeColor = System.Drawing.Color.LightGray;
63+
}
64+
}
65+
66+
private void OnTextChanged(object sender, EventArgs e)
67+
{
68+
if (IsPlaceHolderTextShown)
69+
return;
70+
71+
if (_typingTimer == null)
72+
{
73+
_typingTimer = new Timer();
74+
_typingTimer.Interval = 600;
75+
_typingTimer.Tick += TypingTimerTimeout;
76+
}
77+
78+
_typingTimer.Stop();
79+
_typingTimer.Start();
80+
}
81+
82+
private void TypingTimerTimeout(object sender, EventArgs e)
83+
{
84+
var timer = sender as Timer;
85+
if (timer == null)
86+
return;
87+
88+
// The timer must be stopped!
89+
timer.Stop();
90+
if (Changed != null)
91+
Changed();
92+
93+
TextBox.Focus();
94+
}
95+
}
96+
}

src/TestCentric/testcentric.gui/Presenters/TreeViewPresenter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ private void WireUpEvents()
257257
_model.TestCentricTestFilter.OutcomeFilter = filter;
258258
};
259259

260+
_view.TextFilter.Changed += () =>
261+
{
262+
var text = _view.TextFilter.Text;
263+
_model.TestCentricTestFilter.TextFilter = text;
264+
};
265+
260266
// Node selected in tree
261267
//_treeView.SelectedNodesChanged += (nodes) =>
262268
//{

src/TestCentric/testcentric.gui/Views/ITestTreeView.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public interface ITestTreeView : IView
5353
// Test Filter related properties / methods
5454
IMultiSelection OutcomeFilter { get; }
5555

56+
IChanged TextFilter { get; }
57+
5658
void SetTestFilterVisibility(bool visible);
5759

5860
// Tree-related Methods

src/TestCentric/testcentric.gui/Views/TestTreeView.Designer.cs

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/TestCentric/testcentric.gui/Views/TestTreeView.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public TestTreeView()
4949
TestPropertiesCommand = new CommandMenuElement(testPropertiesMenuItem);
5050
ViewAsXmlCommand = new CommandMenuElement(viewAsXmlMenuItem);
5151
OutcomeFilter = new MultiCheckedToolStripButtonGroup(new[] { filterOutcomePassedButton, filterOutcomeFailedButton, filterOutcomeWarningButton, filterOutcomeNotRunButton });
52+
TextFilter = new ToolStripTextBoxElement(filterTextBox, "Filter...");
5253
TreeView = treeView;
5354

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

128129
public IMultiSelection OutcomeFilter { get; private set; }
129130

131+
public IChanged TextFilter { get; private set; }
132+
130133
public TreeNode ContextNode { get; private set; }
131134
public ContextMenuStrip TreeContextMenu => TreeView.ContextMenuStrip;
132135

@@ -205,6 +208,7 @@ public void InvokeIfRequired(MethodInvoker _delegate)
205208
public void SetTestFilterVisibility(bool isVisible)
206209
{
207210
filterToolStrip.Visible = isVisible;
211+
filterTextToolStrip.Visible = isVisible;
208212
}
209213

210214
public void LoadAlternateImages(string imageSet)

src/TestCentric/tests/Presenters/TestTree/TreeViewPresenterTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,19 @@ public void OutcomeFilterChanged_ApplyFilter()
249249
_model.TestCentricTestFilter.Received().OutcomeFilter = selectedItems;
250250
}
251251

252+
[Test]
253+
public void TextFilterChanged_ApplyFilter()
254+
{
255+
// 1. Arrange
256+
_view.TextFilter.Text.Returns("TestA");
257+
258+
// 2. Act
259+
_view.TextFilter.Changed += Raise.Event<CommandHandler>();
260+
261+
// 3. Assert
262+
_model.TestCentricTestFilter.Received().TextFilter = "TestA";
263+
}
264+
252265
// TODO: Version 1 Test - Make it work if needed.
253266
//[Test]
254267
//public void WhenContextNodeIsNotNull_RunCommandExecutesThatTest()

0 commit comments

Comments
 (0)