-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathTestTreeView.cs
More file actions
290 lines (238 loc) · 10.5 KB
/
TestTreeView.cs
File metadata and controls
290 lines (238 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// ***********************************************************************
// 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.IO;
using System.Reflection;
namespace TestCentric.Gui.Views
{
using System;
using System.Collections.Generic;
using Elements;
public partial class TestTreeView : UserControl, ITestTreeView
{
/// <summary>
/// Image indices for various test states - the values
/// must match the indices of the image list used and
/// are ordered so that the higher values are those
/// that propagate upwards.
/// </summary>
public const int InitIndex = 0;
public const int SkippedIndex = 0;
public const int InconclusiveIndex = 1;
public const int SuccessIndex = 2;
public const int WarningIndex = 3;
public const int FailureIndex = 4;
public event TreeNodeActionHandler SelectedNodeChanged;
public event TreeNodeActionHandler AfterCheck;
public event TreeNodeActionHandler TreeNodeDoubleClick;
public event EventHandler ContextMenuOpening;
public TestTreeView()
{
InitializeComponent();
RunContextCommand = new CommandMenuElement(this.runMenuItem);
DebugContextCommand = new CommandMenuElement(this.debugMenuItem);
ActiveConfiguration = new PopupMenuElement(this.activeConfigMenuItem);
ShowCheckBoxes = new CheckedMenuElement(showCheckboxesMenuItem);
ShowTestDuration = new CheckedMenuElement(showTestDurationMenuItem);
ExpandAllCommand = new CommandMenuElement(expandAllMenuItem);
CollapseAllCommand = new CommandMenuElement(collapseAllMenuItem);
CollapseToFixturesCommand = new CommandMenuElement(collapseToFixturesMenuItem);
TestPropertiesCommand = new CommandMenuElement(testPropertiesMenuItem);
ViewAsXmlCommand = new CommandMenuElement(viewAsXmlMenuItem);
OutcomeFilter = new MultiCheckedToolStripButtonGroup(new[] { filterOutcomePassedButton, filterOutcomeFailedButton, filterOutcomeWarningButton, filterOutcomeNotRunButton });
TextFilter = new TextBoxElement(filterTextBox.Control, "Filter...");
TreeView = treeView;
// NOTE: We use MouseDown here rather than MouseUp because
// the menu strip Opening event occurs before MouseUp.
treeView.MouseDown += (s, e) =>
{
if (e.Button == MouseButtons.Right)
{
ContextNode = TreeView.GetNodeAt(e.X, e.Y);
}
};
treeView.ContextMenuStrip.Opening += (s, e) =>
{
bool clickedOnNode = ContextNode != null;
runMenuItem.Visible =
debugMenuItem.Visible =
contextMenuSeparator1.Visible =
viewAsXmlMenuItem.Visible =
contextMenuSeparator2.Visible = clickedOnNode;
ContextMenuOpening?.Invoke(s, e);
// In case presenter cancels
if (!e.Cancel && clickedOnNode)
SelectedNode = ContextNode;
};
treeView.NodeMouseDoubleClick += (s, e) => TreeNodeDoubleClick?.Invoke(e.Node);
treeView.AfterSelect += (s, e) => SelectedNodeChanged?.Invoke(e.Node);
treeView.AfterCheck += (s, e) => AfterCheck?.Invoke(e.Node);
}
#region Properties
private bool _checkBoxes;
public bool CheckBoxes
{
get { return _checkBoxes; }
set
{
if (_checkBoxes != value)
{
var expandedNodes = new List<TreeNode>();
// Turning off checkboxes collapses everything, so we
// have to save and restore the expanded nodes.
if (!value)
foreach (TreeNode node in treeView.Nodes)
RecordExpandedNodes(expandedNodes, node);
InvokeIfRequired(() => { treeView.CheckBoxes = _checkBoxes = value; });
if (!value)
foreach (var node in expandedNodes)
node.Expand();
}
}
}
public ICommand RunContextCommand { get; private set; }
public ICommand DebugContextCommand { get; private set; }
public IToolStripMenu ActiveConfiguration { get; private set; }
public IChecked ShowCheckBoxes { get; private set; }
public IChecked ShowTestDuration { get; private set; }
public ICommand ExpandAllCommand { get; private set; }
public ICommand CollapseAllCommand { get; private set; }
public ICommand CollapseToFixturesCommand { get; private set; }
public ICommand TestPropertiesCommand { get; private set; }
public ICommand ViewAsXmlCommand { get; private set; }
public TreeView TreeView { get; private set; }
public IMultiSelection OutcomeFilter { get; private set; }
public ISelection TextFilter { get; private set; }
public TreeNode ContextNode { get; private set; }
public ContextMenuStrip TreeContextMenu => TreeView.ContextMenuStrip;
private string _alternateImageSet;
public string AlternateImageSet
{
get { return _alternateImageSet; }
set
{
_alternateImageSet = value;
if (!string.IsNullOrEmpty(value))
LoadAlternateImages(value);
}
}
public TreeNodeCollection Nodes => treeView.Nodes;
public int VisibleNodeCount => treeView.VisibleCount;
public TreeNode TopNode
{
get { return treeView.TopNode; }
set { InvokeIfRequired(() => treeView.TopNode = value); }
}
public TreeNode SelectedNode
{
get { return treeView.SelectedNode; }
set { InvokeIfRequired(() => treeView.SelectedNode = value); }
}
//public IList<TreeNode> SelectedNodes => treeView.SelectedNodes;
public IList<TreeNode> CheckedNodes => GetCheckedNodes();
#endregion
#region Public Methods
public void Clear() => InvokeIfRequired(() => treeView.Nodes.Clear());
public void Add(TreeNode treeNode) => InvokeIfRequired(() =>
{
treeView.BeginUpdate();
treeView.Nodes.Add(treeNode);
if (treeView.SelectedNode == null)
treeView.SelectedNode = treeNode;
treeView.EndUpdate();
treeView.Select();
});
public void ExpandAll() => InvokeIfRequired(() => treeView.ExpandAll());
public void CollapseAll() => InvokeIfRequired(() => treeView.CollapseAll());
public void SetImageIndex(TreeNode treeNode, int imageIndex) =>
InvokeIfRequired(() => treeNode.ImageIndex = treeNode.SelectedImageIndex = imageIndex);
public void ResetAllTreeNodeImages()
{
InvokeIfRequired(() => ResetAllTreeNodeImages(treeView.Nodes));
}
private void ResetAllTreeNodeImages(TreeNodeCollection treeNodes)
{
foreach (TreeNode treeNode in treeNodes)
{
treeNode.ImageIndex = treeNode.SelectedImageIndex = InitIndex;
ResetAllTreeNodeImages(treeNode.Nodes);
}
}
public void InvokeIfRequired(MethodInvoker _delegate)
{
if (treeView.InvokeRequired)
treeView.Invoke(_delegate);
else
_delegate();
}
public void SetTestFilterVisibility(bool isVisible)
{
filterToolStrip.Visible = isVisible;
filterTextToolStrip.Visible = isVisible;
}
public void LoadAlternateImages(string imageSet)
{
string[] imageNames = { "Skipped", "Inconclusive", "Success", "Ignored", "Failure" };
string imageDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Path.Combine("Images", Path.Combine("Tree", imageSet)));
// 1. Load all images once
IDictionary<string, Image> images = new Dictionary<string, Image>();
foreach (string imageName in imageNames)
images[imageName] = LoadAlternateImage(imageName, imageDir);
// 2. Set tree images
for (int index = 0; index < imageNames.Length; index++)
{
string imageName = imageNames[index];
treeImages.Images[index] = images[imageName];
}
// 3. Set filter outcome toolbar images
filterOutcomeFailedButton.Image = images["Failure"];
filterOutcomePassedButton.Image = images["Success"];
filterOutcomeWarningButton.Image = images["Ignored"];
filterOutcomeNotRunButton.Image = images["Skipped"];
this.Invalidate();
this.Refresh();
}
#endregion
#region Helper Methods
private Image LoadAlternateImage(string name, string imageDir)
{
string[] extensions = { ".png", ".jpg" };
foreach (string ext in extensions)
{
string filePath = Path.Combine(imageDir, name + ext);
if (File.Exists(filePath))
{
return Image.FromFile(filePath);
}
}
return null;
}
private IList<TreeNode> GetCheckedNodes()
{
var checkedNodes = new List<TreeNode>();
foreach (TreeNode node in treeView.Nodes)
CollectCheckedNodes(checkedNodes, node);
return checkedNodes;
}
private void CollectCheckedNodes(List<TreeNode> checkedNodes, TreeNode node)
{
if (node.Checked)
checkedNodes.Add(node);
else
foreach (TreeNode child in node.Nodes)
CollectCheckedNodes(checkedNodes, child);
}
private void RecordExpandedNodes(List<TreeNode> expanded, TreeNode startNode)
{
if (startNode.IsExpanded)
expanded.Add(startNode);
foreach (TreeNode node in startNode.Nodes)
RecordExpandedNodes(expanded, node);
}
#endregion
}
}