Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit f71eec2

Browse files
Merge branch 'master' into fixes/cache-invalidation-error
2 parents 360a485 + d4eb1f4 commit f71eec2

File tree

2 files changed

+255
-52
lines changed

2 files changed

+255
-52
lines changed

src/GitHub.Api/UI/TreeBase.cs

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -183,23 +183,9 @@ protected bool PromoteNode(TNode previouslyAddedNode, string nextLabel)
183183

184184
public void SetCheckStateOnAll(bool isChecked)
185185
{
186-
var nodeCheckState = isChecked ? CheckState.Checked : CheckState.Empty;
187186
foreach (var node in Nodes)
188187
{
189-
var wasChecked = node.CheckState == CheckState.Checked;
190-
node.CheckState = nodeCheckState;
191-
192-
if (!node.IsFolder)
193-
{
194-
if (isChecked && !wasChecked)
195-
{
196-
AddCheckedNode(node);
197-
}
198-
else if (!isChecked && wasChecked)
199-
{
200-
RemoveCheckedNode(node);
201-
}
202-
}
188+
SetCheckStateOnNode(node, isChecked);
203189
}
204190
}
205191

@@ -250,60 +236,41 @@ protected void ToggleNodeVisibility(int idx, TNode node)
250236

251237
protected void ToggleNodeChecked(int idx, TNode node)
252238
{
239+
CheckState checkState;
253240
var isChecked = false;
254-
255241
switch (node.CheckState)
256242
{
257243
case CheckState.Mixed:
258244
case CheckState.Empty:
259-
node.CheckState = CheckState.Checked;
245+
checkState = CheckState.Checked;
260246
isChecked = true;
261247
break;
262248

263249
case CheckState.Checked:
264-
node.CheckState = CheckState.Empty;
250+
checkState = CheckState.Empty;
265251
break;
266-
}
267252

268-
if (!node.IsFolder)
269-
{
270-
if (isChecked)
271-
{
272-
AddCheckedNode(node);
273-
}
274-
else
275-
{
276-
RemoveCheckedNode(node);
277-
}
253+
default:
254+
throw new ArgumentOutOfRangeException("Unknown CheckState");
278255
}
279256

257+
SetCheckStateOnNode(node, checkState);
258+
280259
if (node.IsFolderOrContainer)
281260
{
282261
ToggleChildrenChecked(idx, node, isChecked);
283262
}
284263

285-
ToggleParentFoldersChecked(idx, node, isChecked);
264+
ToggleParentFolderAndContainersChecked(idx, node, checkState);
286265
}
287266

288267
private void ToggleChildrenChecked(int idx, TNode node, bool isChecked)
289268
{
290269
for (var i = idx + 1; i < Nodes.Count && node.Level < Nodes[i].Level; i++)
291270
{
292271
var childNode = Nodes[i];
293-
var wasChecked = childNode.CheckState == CheckState.Checked;
294-
childNode.CheckState = isChecked ? CheckState.Checked : CheckState.Empty;
295272

296-
if (!childNode.IsFolder)
297-
{
298-
if (isChecked && !wasChecked)
299-
{
300-
AddCheckedNode(childNode);
301-
}
302-
else if (!isChecked && wasChecked)
303-
{
304-
RemoveCheckedNode(childNode);
305-
}
306-
}
273+
SetCheckStateOnNode(childNode, isChecked);
307274

308275
if (childNode.IsFolderOrContainer)
309276
{
@@ -332,9 +299,36 @@ private List<TNode> GetLeafNodes(TNode node, int idx)
332299
return results;
333300
}
334301

302+
private void SetCheckStateOnNode(TNode node, bool setChecked)
303+
{
304+
SetCheckStateOnNode(node, setChecked ? CheckState.Checked : CheckState.Empty);
305+
}
306+
307+
private void SetCheckStateOnNode(TNode node, CheckState setCheckState)
308+
{
309+
var isChecked = setCheckState == CheckState.Checked
310+
|| setCheckState == CheckState.Mixed;
311+
312+
var wasChecked = node.CheckState == CheckState.Checked;
313+
314+
node.CheckState = setCheckState;
315+
316+
if (!node.IsFolder)
317+
{
318+
if (isChecked && !wasChecked)
319+
{
320+
AddCheckedNode(node);
321+
}
322+
else if (!isChecked && wasChecked)
323+
{
324+
RemoveCheckedNode(node);
325+
}
326+
}
327+
}
335328

336-
private void ToggleParentFoldersChecked(int idx, TNode node, bool isChecked)
329+
private void ToggleParentFolderAndContainersChecked(int idx, TNode node, CheckState checkState)
337330
{
331+
var isChecked = checkState != CheckState.Empty;
338332
while (true)
339333
{
340334
if (node.Level > 0)
@@ -384,14 +378,13 @@ private void ToggleParentFoldersChecked(int idx, TNode node, bool isChecked)
384378

385379
var parentIndex = firstSiblingIndex - 1;
386380
var parentNode = Nodes[parentIndex];
387-
if (siblingsInSameState)
388-
{
389-
parentNode.CheckState = isChecked ? CheckState.Checked : CheckState.Empty;
390-
}
391-
else
392-
{
393-
parentNode.CheckState = CheckState.Mixed;
394-
}
381+
382+
var parentNodeState =
383+
siblingsInSameState
384+
? node.CheckState
385+
: CheckState.Mixed;
386+
387+
SetCheckStateOnNode(parentNode, parentNodeState);
395388

396389
idx = parentIndex;
397390
node = parentNode;

src/tests/UnitTests/UI/TreeBaseTests.cs

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ public override TestTreeNode SelectedNode
185185
}
186186
}
187187

188+
public new void ToggleNodeChecked(int idx, TestTreeNode node)
189+
{
190+
base.ToggleNodeChecked(idx, node);
191+
}
192+
188193
protected override List<TestTreeNode> Nodes
189194
{
190195
get
@@ -606,6 +611,211 @@ public void ShouldPopulateTreeWithSingleEntryWithMetaInPath()
606611
}
607612
});
608613
}
614+
615+
[Test]
616+
public void ShouldCheckParentOfMetaFile()
617+
{
618+
var testTree = new TestTree(true);
619+
var testTreeListener = testTree.TestTreeListener;
620+
621+
testTreeListener.GetCollapsedFolders().Returns(new string[0]);
622+
testTreeListener.SelectedNode.Returns((TestTreeNode)null);
623+
testTreeListener.GetCheckedFiles().Returns(new string[0]);
624+
testTreeListener.Nodes.Returns(new List<TestTreeNode>());
625+
testTreeListener.PathSeparator.Returns(@"\");
626+
testTreeListener.DisplayRootNode.Returns(true);
627+
testTreeListener.IsSelectable.Returns(false);
628+
testTreeListener.Title.Returns("Test Tree");
629+
testTreeListener.PromoteMetaFiles.Returns(true);
630+
631+
var testTreeData = new[] {
632+
new TestTreeData {
633+
Path = "Folder\\Default Scene.unity"
634+
},
635+
new TestTreeData {
636+
Path = "Folder\\Default Scene.unity.meta"
637+
}
638+
};
639+
testTree.Load(testTreeData);
640+
641+
testTree.CreatedTreeNodes.ShouldAllBeEquivalentTo(new[] {
642+
new TestTreeNode {
643+
Path = "Test Tree",
644+
Label = "Test Tree",
645+
IsFolder = true
646+
},
647+
new TestTreeNode {
648+
Path = "Folder",
649+
Label = "Folder",
650+
Level = 1,
651+
IsFolder = true
652+
},
653+
new TestTreeNode {
654+
Path = "Folder\\Default Scene.unity",
655+
Label = "Default Scene.unity",
656+
Level = 2,
657+
TreeData = testTreeData[0],
658+
IsContainer = true
659+
},
660+
new TestTreeNode {
661+
Path = "Folder\\Default Scene.unity.meta",
662+
Label = "Default Scene.unity.meta",
663+
Level = 3,
664+
TreeData = testTreeData[1]
665+
}
666+
});
667+
668+
var sceneNode = testTree.CreatedTreeNodes[2];
669+
var sceneMetaNode = testTree.CreatedTreeNodes[3];
670+
671+
Assert.AreEqual(CheckState.Empty, sceneNode.CheckState);
672+
Assert.AreEqual(CheckState.Empty, sceneMetaNode.CheckState);
673+
674+
testTree.ToggleNodeChecked(3, sceneMetaNode);
675+
676+
Assert.AreEqual(CheckState.Checked, sceneNode.CheckState);
677+
Assert.AreEqual(CheckState.Checked, sceneMetaNode.CheckState);
678+
679+
testTreeListener.Received(2).AddCheckedNode(Arg.Any<TestTreeNode>());
680+
}
681+
682+
[Test]
683+
public void ShouldRippleChecksCorrectly()
684+
{
685+
var testTree = new TestTree(true);
686+
var testTreeListener = testTree.TestTreeListener;
687+
688+
testTreeListener.GetCollapsedFolders().Returns(new string[0]);
689+
testTreeListener.SelectedNode.Returns((TestTreeNode)null);
690+
testTreeListener.GetCheckedFiles().Returns(new string[0]);
691+
testTreeListener.Nodes.Returns(new List<TestTreeNode>());
692+
testTreeListener.PathSeparator.Returns(@"\");
693+
testTreeListener.DisplayRootNode.Returns(true);
694+
testTreeListener.IsSelectable.Returns(false);
695+
testTreeListener.Title.Returns("Test Tree");
696+
testTreeListener.PromoteMetaFiles.Returns(true);
697+
698+
var testTreeData = new[] {
699+
new TestTreeData {
700+
Path = "Root\\Parent\\A.txt"
701+
},
702+
new TestTreeData {
703+
Path = "Root\\Parent\\B.txt"
704+
},
705+
new TestTreeData {
706+
Path = "Root\\Parent\\C.txt"
707+
}
708+
};
709+
710+
testTree.Load(testTreeData);
711+
712+
testTree.CreatedTreeNodes.ShouldAllBeEquivalentTo(new[] {
713+
new TestTreeNode {
714+
Path = "Test Tree",
715+
Label = "Test Tree",
716+
IsFolder = true
717+
},
718+
new TestTreeNode {
719+
Path = "Root",
720+
Label = "Root",
721+
Level = 1,
722+
IsFolder = true
723+
},
724+
new TestTreeNode {
725+
Path = "Root\\Parent",
726+
Label = "Parent",
727+
Level = 2,
728+
IsFolder = true
729+
},
730+
new TestTreeNode {
731+
Path = "Root\\Parent\\A.txt",
732+
Label = "A.txt",
733+
Level = 3,
734+
TreeData = testTreeData[0],
735+
},
736+
new TestTreeNode {
737+
Path = "Root\\Parent\\B.txt",
738+
Label = "B.txt",
739+
Level = 3,
740+
TreeData = testTreeData[1],
741+
},
742+
new TestTreeNode {
743+
Path = "Root\\Parent\\C.txt",
744+
Label = "C.txt",
745+
Level = 3,
746+
TreeData = testTreeData[2],
747+
}
748+
});
749+
750+
var rootNode = testTree.CreatedTreeNodes[1];
751+
var parentNode = testTree.CreatedTreeNodes[2];
752+
var aNode = testTree.CreatedTreeNodes[3];
753+
var bNode = testTree.CreatedTreeNodes[4];
754+
var cNode = testTree.CreatedTreeNodes[5];
755+
756+
// Initial state, everything unchecked
757+
758+
Assert.AreEqual(CheckState.Empty, rootNode.CheckState);
759+
Assert.AreEqual(CheckState.Empty, parentNode.CheckState);
760+
Assert.AreEqual(CheckState.Empty, aNode.CheckState);
761+
Assert.AreEqual(CheckState.Empty, bNode.CheckState);
762+
Assert.AreEqual(CheckState.Empty, cNode.CheckState);
763+
764+
testTree.ToggleNodeChecked(1, rootNode);
765+
766+
// Checked the root node, everything checked
767+
768+
Assert.AreEqual(CheckState.Checked, rootNode.CheckState);
769+
Assert.AreEqual(CheckState.Checked, parentNode.CheckState);
770+
Assert.AreEqual(CheckState.Checked, aNode.CheckState);
771+
Assert.AreEqual(CheckState.Checked, bNode.CheckState);
772+
Assert.AreEqual(CheckState.Checked, cNode.CheckState);
773+
774+
testTreeListener.Received(3).AddCheckedNode(Arg.Any<TestTreeNode>());
775+
testTreeListener.ClearReceivedCalls();
776+
777+
// Unchecked c.txt, c.txt unchecked, parents mixed
778+
779+
testTree.ToggleNodeChecked(5, cNode);
780+
781+
Assert.AreEqual(CheckState.Mixed, rootNode.CheckState);
782+
Assert.AreEqual(CheckState.Mixed, parentNode.CheckState);
783+
Assert.AreEqual(CheckState.Checked, aNode.CheckState);
784+
Assert.AreEqual(CheckState.Checked, bNode.CheckState);
785+
Assert.AreEqual(CheckState.Empty, cNode.CheckState);
786+
787+
testTreeListener.Received(1).RemoveCheckedNode(Arg.Any<TestTreeNode>());
788+
testTreeListener.ClearReceivedCalls();
789+
790+
testTree.ToggleNodeChecked(5, cNode);
791+
792+
// Checked c.txt, everything checked
793+
794+
Assert.AreEqual(CheckState.Checked, rootNode.CheckState);
795+
Assert.AreEqual(CheckState.Checked, parentNode.CheckState);
796+
Assert.AreEqual(CheckState.Checked, aNode.CheckState);
797+
Assert.AreEqual(CheckState.Checked, bNode.CheckState);
798+
Assert.AreEqual(CheckState.Checked, cNode.CheckState);
799+
800+
testTreeListener.Received(1).AddCheckedNode(Arg.Any<TestTreeNode>());
801+
testTreeListener.ClearReceivedCalls();
802+
803+
// Unchecked a.txt b.txt and c.txt, everything checked
804+
805+
testTree.ToggleNodeChecked(3, aNode);
806+
testTree.ToggleNodeChecked(4, bNode);
807+
testTree.ToggleNodeChecked(5, cNode);
808+
809+
Assert.AreEqual(CheckState.Empty, rootNode.CheckState);
810+
Assert.AreEqual(CheckState.Empty, parentNode.CheckState);
811+
Assert.AreEqual(CheckState.Empty, aNode.CheckState);
812+
Assert.AreEqual(CheckState.Empty, bNode.CheckState);
813+
Assert.AreEqual(CheckState.Empty, cNode.CheckState);
814+
815+
testTreeListener.Received(3).RemoveCheckedNode(Arg.Any<TestTreeNode>());
816+
testTreeListener.ClearReceivedCalls();
817+
}
818+
609819
[Test]
610820
public void ShouldPopulateTreeWithSingleEntryWithNonPromotedMetaInPath()
611821
{

0 commit comments

Comments
 (0)