TreeViewTests.cs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435
  1. using System.Text;
  2. using UnitTests;
  3. using Xunit.Abstractions;
  4. namespace UnitTests.ViewsTests;
  5. public class TreeViewTests (ITestOutputHelper output)
  6. {
  7. /// <summary>Tests that TreeView.Expand(object) results in a correct content height</summary>
  8. [Fact]
  9. public void ContentHeight_BiggerAfterExpand ()
  10. {
  11. TreeView<object> tree = CreateTree (out Factory f, out _, out _);
  12. Assert.Equal (1, tree.ContentHeight);
  13. tree.Expand (f);
  14. Assert.Equal (3, tree.ContentHeight);
  15. tree.Collapse (f);
  16. Assert.Equal (1, tree.ContentHeight);
  17. }
  18. [Fact]
  19. public void ContentWidth_BiggerAfterExpand ()
  20. {
  21. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  22. tree.BeginInit ();
  23. tree.EndInit ();
  24. tree.Viewport = new Rectangle (0, 0, 10, 10);
  25. //-+Factory
  26. Assert.Equal (9, tree.GetContentWidth (true));
  27. car1.Name = "123456789";
  28. tree.Expand (f);
  29. //..├-123456789
  30. Assert.Equal (13, tree.GetContentWidth (true));
  31. tree.Collapse (f);
  32. //-+Factory
  33. Assert.Equal (9, tree.GetContentWidth (true));
  34. }
  35. [Fact]
  36. public void ContentWidth_VisibleVsAll ()
  37. {
  38. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out Car car2);
  39. tree.BeginInit ();
  40. tree.EndInit ();
  41. // control only allows 1 row to be viewed at once
  42. tree.Viewport = new Rectangle (0, 0, 20, 1);
  43. //-+Factory
  44. Assert.Equal (9, tree.GetContentWidth (true));
  45. Assert.Equal (9, tree.GetContentWidth (false));
  46. car1.Name = "123456789";
  47. car2.Name = "12345678";
  48. tree.Expand (f);
  49. // Although expanded the bigger (longer) child node is not in the rendered area of the control
  50. Assert.Equal (9, tree.GetContentWidth (true));
  51. Assert.Equal (
  52. 13,
  53. tree.GetContentWidth (false)
  54. ); // If you ask for the global max width it includes the longer child
  55. // Now that we have scrolled down 1 row we should see the big child
  56. tree.ScrollOffsetVertical = 1;
  57. Assert.Equal (13, tree.GetContentWidth (true));
  58. Assert.Equal (13, tree.GetContentWidth (false));
  59. // Scroll down so only car2 is visible
  60. tree.ScrollOffsetVertical = 2;
  61. Assert.Equal (12, tree.GetContentWidth (true));
  62. Assert.Equal (13, tree.GetContentWidth (false));
  63. // Scroll way down (off bottom of control even)
  64. tree.ScrollOffsetVertical = 5;
  65. Assert.Equal (0, tree.GetContentWidth (true));
  66. Assert.Equal (13, tree.GetContentWidth (false));
  67. }
  68. [Fact]
  69. [AutoInitShutdown]
  70. public void CursorVisibility_MultiSelect ()
  71. {
  72. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  73. var n1 = new TreeNode ("normal");
  74. var n2 = new TreeNode ("pink");
  75. tv.AddObject (n1);
  76. tv.AddObject (n2);
  77. var top = new Toplevel ();
  78. top.Add (tv);
  79. Application.Begin (top);
  80. Assert.True (tv.MultiSelect);
  81. Assert.True (tv.HasFocus);
  82. Assert.Equal (CursorVisibility.Invisible, tv.CursorVisibility);
  83. tv.SelectAll ();
  84. tv.CursorVisibility = CursorVisibility.Default;
  85. Application.PositionCursor ();
  86. Application.Driver!.GetCursorVisibility (out CursorVisibility visibility);
  87. Assert.Equal (CursorVisibility.Default, tv.CursorVisibility);
  88. Assert.Equal (CursorVisibility.Default, visibility);
  89. top.Dispose ();
  90. }
  91. [Fact]
  92. public void EmptyTreeView_ContentSizes ()
  93. {
  94. var emptyTree = new TreeView ();
  95. Assert.Equal (0, emptyTree.ContentHeight);
  96. Assert.Equal (0, emptyTree.GetContentWidth (true));
  97. Assert.Equal (0, emptyTree.GetContentWidth (false));
  98. }
  99. [Fact]
  100. public void EmptyTreeViewGeneric_ContentSizes ()
  101. {
  102. TreeView<string> emptyTree = new ();
  103. Assert.Equal (0, emptyTree.ContentHeight);
  104. Assert.Equal (0, emptyTree.GetContentWidth (true));
  105. Assert.Equal (0, emptyTree.GetContentWidth (false));
  106. }
  107. /// <summary>
  108. /// Tests that <see cref="TreeView.GetChildren(object)"/> returns the child objects for the factory. Note that
  109. /// the method only works once the parent branch (Factory) is expanded to expose the child (Car)
  110. /// </summary>
  111. [Fact]
  112. public void GetChildren_ReturnsChildrenOnlyWhenExpanded ()
  113. {
  114. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  115. Assert.Empty (tree.GetChildren (f));
  116. Assert.Empty (tree.GetChildren (c1));
  117. Assert.Empty (tree.GetChildren (c2));
  118. // now when we expand the factory we discover the cars
  119. tree.Expand (f);
  120. Assert.Contains (c1, tree.GetChildren (f));
  121. Assert.Contains (c2, tree.GetChildren (f));
  122. Assert.Empty (tree.GetChildren (c1));
  123. Assert.Empty (tree.GetChildren (c2));
  124. tree.Collapse (f);
  125. Assert.Empty (tree.GetChildren (f));
  126. Assert.Empty (tree.GetChildren (c1));
  127. Assert.Empty (tree.GetChildren (c2));
  128. }
  129. /// <summary>
  130. /// Tests that <see cref="TreeView.GetParent(object)"/> returns the parent object for Cars (Factories). Note that
  131. /// the method only works once the parent branch (Factory) is expanded to expose the child (Car)
  132. /// </summary>
  133. [Fact]
  134. public void GetParent_ReturnsParentOnlyWhenExpanded ()
  135. {
  136. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  137. Assert.Null (tree.GetParent (f));
  138. Assert.Null (tree.GetParent (c1));
  139. Assert.Null (tree.GetParent (c2));
  140. // now when we expand the factory we discover the cars
  141. tree.Expand (f);
  142. Assert.Null (tree.GetParent (f));
  143. Assert.Equal (f, tree.GetParent (c1));
  144. Assert.Equal (f, tree.GetParent (c2));
  145. tree.Collapse (f);
  146. Assert.Null (tree.GetParent (f));
  147. Assert.Null (tree.GetParent (c1));
  148. Assert.Null (tree.GetParent (c2));
  149. }
  150. /// <summary>Tests <see cref="TreeView.GetScrollOffsetOf(object)"/> for objects that are as yet undiscovered by the tree</summary>
  151. [Fact]
  152. public void GetScrollOffsetOf_MinusOneForUnRevealed ()
  153. {
  154. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  155. // to start with the tree is collapsed and only knows about the root object
  156. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  157. Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
  158. Assert.Equal (-1, tree.GetScrollOffsetOf (c2));
  159. // reveal it by expanding the root object
  160. tree.Expand (f);
  161. // tree now knows about children
  162. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  163. Assert.Equal (1, tree.GetScrollOffsetOf (c1));
  164. Assert.Equal (2, tree.GetScrollOffsetOf (c2));
  165. // after collapsing the root node again
  166. tree.Collapse (f);
  167. // tree no longer knows about the locations of these objects
  168. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  169. Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
  170. Assert.Equal (-1, tree.GetScrollOffsetOf (c2));
  171. }
  172. [Fact]
  173. public void GoTo_OnlyAppliesToExposedObjects ()
  174. {
  175. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  176. tree.BeginInit ();
  177. tree.EndInit ();
  178. // Make tree bounds 1 in height so that EnsureVisible always requires updating scroll offset
  179. tree.Viewport = new Rectangle (0, 0, 50, 1);
  180. Assert.Null (tree.SelectedObject);
  181. Assert.Equal (0, tree.ScrollOffsetVertical);
  182. // car 1 is not yet exposed
  183. tree.GoTo (car1);
  184. Assert.Null (tree.SelectedObject);
  185. Assert.Equal (0, tree.ScrollOffsetVertical);
  186. tree.Expand (f);
  187. // Car1 is now exposed by expanding the factory
  188. tree.GoTo (car1);
  189. Assert.Equal (car1, tree.SelectedObject);
  190. Assert.Equal (1, tree.ScrollOffsetVertical);
  191. }
  192. [Fact]
  193. public void GoToEnd_ShouldNotFailOnEmptyTreeView ()
  194. {
  195. var tree = new TreeView ();
  196. Exception exception = Record.Exception (() => tree.GoToEnd ());
  197. Assert.Null (exception);
  198. }
  199. /// <summary>
  200. /// Tests that <see cref="TreeView.IsExpanded(object)"/> and <see cref="TreeView.Expand(object)"/> behaves
  201. /// correctly when an object cannot be expanded (because it has no children)
  202. /// </summary>
  203. [Fact]
  204. public void IsExpanded_FalseIfCannotExpand ()
  205. {
  206. TreeView<object> tree = CreateTree (out Factory f, out Car c, out _);
  207. // expose the car by expanding the factory
  208. tree.Expand (f);
  209. // car is not expanded
  210. Assert.False (tree.IsExpanded (c));
  211. //try to expand the car (should have no effect because cars have no children)
  212. tree.Expand (c);
  213. Assert.False (tree.IsExpanded (c));
  214. // should also be ignored
  215. tree.Collapse (c);
  216. Assert.False (tree.IsExpanded (c));
  217. }
  218. /// <summary>Tests that <see cref="TreeView.Expand(object)"/> and <see cref="TreeView.IsExpanded(object)"/> are consistent</summary>
  219. [Fact]
  220. public void IsExpanded_TrueAfterExpand ()
  221. {
  222. TreeView<object> tree = CreateTree (out Factory f, out _, out _);
  223. Assert.False (tree.IsExpanded (f));
  224. tree.Expand (f);
  225. Assert.True (tree.IsExpanded (f));
  226. tree.Collapse (f);
  227. Assert.False (tree.IsExpanded (f));
  228. }
  229. [Fact]
  230. public void MultiSelect_GetAllSelectedObjects ()
  231. {
  232. var tree = new TreeView ();
  233. TreeNode l1;
  234. TreeNode l2;
  235. TreeNode l3;
  236. TreeNode l4;
  237. var root = new TreeNode ("Root");
  238. root.Children.Add (l1 = new TreeNode ("Leaf1"));
  239. root.Children.Add (l2 = new TreeNode ("Leaf2"));
  240. root.Children.Add (l3 = new TreeNode ("Leaf3"));
  241. root.Children.Add (l4 = new TreeNode ("Leaf4"));
  242. tree.AddObject (root);
  243. tree.MultiSelect = true;
  244. tree.Expand (root);
  245. Assert.Empty (tree.GetAllSelectedObjects ());
  246. tree.SelectedObject = root;
  247. Assert.Single (tree.GetAllSelectedObjects (), root);
  248. // move selection down 1
  249. tree.AdjustSelection (1);
  250. Assert.Single (tree.GetAllSelectedObjects (), l1);
  251. // expand selection down 2 (e.g. shift down twice)
  252. tree.AdjustSelection (1, true);
  253. tree.AdjustSelection (1, true);
  254. Assert.Equal (3, tree.GetAllSelectedObjects ().Count ());
  255. Assert.Contains (l1, tree.GetAllSelectedObjects ());
  256. Assert.Contains (l2, tree.GetAllSelectedObjects ());
  257. Assert.Contains (l3, tree.GetAllSelectedObjects ());
  258. tree.Collapse (root);
  259. // No selected objects since the root was collapsed
  260. Assert.Empty (tree.GetAllSelectedObjects ());
  261. }
  262. [Fact]
  263. public void ObjectActivated_Called ()
  264. {
  265. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  266. object activated = null;
  267. var called = false;
  268. // register for the event
  269. tree.ObjectActivated += (s, e) =>
  270. {
  271. activated = e.ActivatedObject;
  272. called = true;
  273. };
  274. Assert.False (called);
  275. // no object is selected yet so no event should happen
  276. tree.NewKeyDownEvent (Key.Enter);
  277. Assert.Null (activated);
  278. Assert.False (called);
  279. // down to select factory
  280. tree.NewKeyDownEvent (Key.CursorDown);
  281. tree.NewKeyDownEvent (Key.Enter);
  282. Assert.True (called);
  283. Assert.Same (f, activated);
  284. }
  285. [Fact]
  286. public void ObjectActivated_CustomKey ()
  287. {
  288. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  289. tree.ObjectActivationKey = KeyCode.Delete;
  290. object activated = null;
  291. var called = false;
  292. // register for the event
  293. tree.ObjectActivated += (s, e) =>
  294. {
  295. activated = e.ActivatedObject;
  296. called = true;
  297. };
  298. Assert.False (called);
  299. // no object is selected yet so no event should happen
  300. tree.NewKeyDownEvent (Key.Enter);
  301. Assert.Null (activated);
  302. Assert.False (called);
  303. // down to select factory
  304. tree.NewKeyDownEvent (Key.CursorDown);
  305. tree.NewKeyDownEvent (Key.Enter);
  306. // Enter is not the activation key in this unit test
  307. Assert.Null (activated);
  308. Assert.False (called);
  309. // Delete is the activation key in this test so should result in activation occurring
  310. tree.NewKeyDownEvent (Key.Delete);
  311. Assert.True (called);
  312. Assert.Same (f, activated);
  313. }
  314. [Fact]
  315. public void ObjectActivationButton_DoubleClick ()
  316. {
  317. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  318. object activated = null;
  319. var called = false;
  320. // register for the event
  321. tree.ObjectActivated += (s, e) =>
  322. {
  323. activated = e.ActivatedObject;
  324. called = true;
  325. };
  326. Assert.False (called);
  327. // double click triggers activation
  328. tree.NewMouseEvent (new MouseEventArgs { Flags = MouseFlags.Button1DoubleClicked });
  329. Assert.True (called);
  330. Assert.Same (f, activated);
  331. Assert.Same (f, tree.SelectedObject);
  332. }
  333. [Fact]
  334. public void ObjectActivationButton_RightClick ()
  335. {
  336. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  337. tree.ObjectActivationButton = MouseFlags.Button2Clicked;
  338. tree.ExpandAll ();
  339. object activated = null;
  340. var called = false;
  341. // register for the event
  342. tree.ObjectActivated += (s, e) =>
  343. {
  344. activated = e.ActivatedObject;
  345. called = true;
  346. };
  347. Assert.False (called);
  348. // double click does nothing because we changed button binding to right click
  349. tree.NewMouseEvent (new MouseEventArgs { Position = new (0, 1), Flags = MouseFlags.Button1DoubleClicked });
  350. Assert.Null (activated);
  351. Assert.False (called);
  352. tree.NewMouseEvent (new MouseEventArgs { Position = new (0, 1), Flags = MouseFlags.Button2Clicked });
  353. Assert.True (called);
  354. Assert.Same (car1, activated);
  355. Assert.Same (car1, tree.SelectedObject);
  356. }
  357. [Fact]
  358. public void ObjectActivationButton_SetToNull ()
  359. {
  360. TreeView<object> tree = CreateTree (out Factory f, out Car car1, out _);
  361. Assert.Null (tree.SelectedObject);
  362. Assert.True (tree.SetFocus ());
  363. tree.SelectedObject = null;
  364. Assert.Null (tree.SelectedObject);
  365. // disable activation
  366. tree.ObjectActivationButton = null;
  367. object activated = null;
  368. var called = false;
  369. // register for the event
  370. tree.ObjectActivated += (s, e) =>
  371. {
  372. activated = e.ActivatedObject;
  373. called = true;
  374. };
  375. Assert.False (called);
  376. // double click does nothing because we changed button to null
  377. tree.NewMouseEvent (new MouseEventArgs { Flags = MouseFlags.Button1DoubleClicked });
  378. Assert.False (called);
  379. Assert.Null (activated);
  380. Assert.Null (tree.SelectedObject);
  381. }
  382. /// <summary>
  383. /// Same as <see cref="RefreshObject_AfterChangingChildrenGetterDuringRuntime"/> but uses
  384. /// <see cref="TreeView.RebuildTree()"/> instead of <see cref="TreeView.RefreshObject(object, bool)"/>
  385. /// </summary>
  386. [Fact]
  387. public void RebuildTree_AfterChangingChildrenGetterDuringRuntime ()
  388. {
  389. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  390. var wheel = "Shiny Wheel";
  391. // Expand the Factory
  392. tree.Expand (f);
  393. // c1 cannot have children
  394. Assert.Equal (f, tree.GetParent (c1));
  395. // expanding it does nothing
  396. tree.Expand (c1);
  397. Assert.False (tree.IsExpanded (c1));
  398. // change the children getter so that now cars can have wheels
  399. tree.TreeBuilder = new DelegateTreeBuilder<object> (
  400. o =>
  401. // factories have cars
  402. o is Factory
  403. ? new object [] { c1, c2 }
  404. // cars have wheels
  405. : new object [] { wheel }
  406. );
  407. // still cannot expand
  408. tree.Expand (c1);
  409. Assert.False (tree.IsExpanded (c1));
  410. // Rebuild the tree
  411. tree.RebuildTree ();
  412. // Rebuild should not have collapsed any branches or done anything wierd
  413. Assert.True (tree.IsExpanded (f));
  414. tree.Expand (c1);
  415. Assert.True (tree.IsExpanded (c1));
  416. Assert.Equal (wheel, tree.GetChildren (c1).FirstOrDefault ());
  417. }
  418. /// <summary>
  419. /// Tests how the tree adapts to changes in the ChildrenGetter delegate during runtime when some branches are
  420. /// expanded and the new delegate returns children for a node that previously didn't have any children
  421. /// </summary>
  422. [Fact]
  423. public void RefreshObject_AfterChangingChildrenGetterDuringRuntime ()
  424. {
  425. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  426. var wheel = "Shiny Wheel";
  427. // Expand the Factory
  428. tree.Expand (f);
  429. // c1 cannot have children
  430. Assert.Equal (f, tree.GetParent (c1));
  431. // expanding it does nothing
  432. tree.Expand (c1);
  433. Assert.False (tree.IsExpanded (c1));
  434. // change the children getter so that now cars can have wheels
  435. tree.TreeBuilder = new DelegateTreeBuilder<object> (
  436. o =>
  437. // factories have cars
  438. o is Factory
  439. ? new object [] { c1, c2 }
  440. // cars have wheels
  441. : new object [] { wheel }
  442. );
  443. // still cannot expand
  444. tree.Expand (c1);
  445. Assert.False (tree.IsExpanded (c1));
  446. tree.RefreshObject (c1);
  447. tree.Expand (c1);
  448. Assert.True (tree.IsExpanded (c1));
  449. Assert.Equal (wheel, tree.GetChildren (c1).FirstOrDefault ());
  450. }
  451. /// <summary>
  452. /// Simulates behind the scenes changes to an object (which children it has) and how to sync that into the tree
  453. /// using <see cref="TreeView.RefreshObject(object, bool)"/>
  454. /// </summary>
  455. [Fact]
  456. public void RefreshObject_ChildRemoved ()
  457. {
  458. TreeView<object> tree = CreateTree (out Factory f, out Car c1, out Car c2);
  459. //reveal it by expanding the root object
  460. tree.Expand (f);
  461. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  462. Assert.Equal (1, tree.GetScrollOffsetOf (c1));
  463. Assert.Equal (2, tree.GetScrollOffsetOf (c2));
  464. // Factory now no longer makes Car c1 (only c2)
  465. f.Cars = new [] { c2 };
  466. // Tree does not know this yet
  467. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  468. Assert.Equal (1, tree.GetScrollOffsetOf (c1));
  469. Assert.Equal (2, tree.GetScrollOffsetOf (c2));
  470. // If the user has selected the node c1
  471. tree.SelectedObject = c1;
  472. // When we refresh the tree
  473. tree.RefreshObject (f);
  474. // Now tree knows that factory has only one child node c2
  475. Assert.Equal (0, tree.GetScrollOffsetOf (f));
  476. Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
  477. Assert.Equal (1, tree.GetScrollOffsetOf (c2));
  478. // The old selection was c1 which is now gone so selection should default to the parent of that branch (the factory)
  479. Assert.Equal (f, tree.SelectedObject);
  480. }
  481. /// <summary>
  482. /// Simulates behind the scenes changes to an object (which children it has) and how to sync that into the tree
  483. /// using <see cref="TreeView.RefreshObject(object, bool)"/>
  484. /// </summary>
  485. [Fact]
  486. public void RefreshObject_EqualityTest ()
  487. {
  488. var obj1 = new EqualityTestObject { Name = "Bob", Age = 1 };
  489. var obj2 = new EqualityTestObject { Name = "Bob", Age = 2 };
  490. ;
  491. var root = "root";
  492. TreeView<object> tree = new ();
  493. tree.TreeBuilder =
  494. new DelegateTreeBuilder<object> (s => ReferenceEquals (s, root) ? new object [] { obj1 } : null);
  495. tree.AddObject (root);
  496. // Tree is not expanded so the root has no children yet
  497. Assert.Empty (tree.GetChildren (root));
  498. tree.Expand (root);
  499. // now that the tree is expanded we should get our child returned
  500. Assert.Equal (1, tree.GetChildren (root).Count (child => ReferenceEquals (obj1, child)));
  501. // change the getter to return an Equal object (but not the same reference - obj2)
  502. tree.TreeBuilder =
  503. new DelegateTreeBuilder<object> (s => ReferenceEquals (s, root) ? new object [] { obj2 } : null);
  504. // tree has cached the knowledge of what children the root has so won't know about the change (we still get obj1)
  505. Assert.Equal (1, tree.GetChildren (root).Count (child => ReferenceEquals (obj1, child)));
  506. // now that we refresh the root we should get the new child reference (obj2)
  507. tree.RefreshObject (root);
  508. Assert.Equal (1, tree.GetChildren (root).Count (child => ReferenceEquals (obj2, child)));
  509. }
  510. /// <summary>Tests illegal ranges for <see cref="TreeView.ScrollOffset"/></summary>
  511. [Fact]
  512. public void ScrollOffset_CannotBeNegative ()
  513. {
  514. TreeView<object> tree = CreateTree ();
  515. Assert.Equal (0, tree.ScrollOffsetVertical);
  516. tree.ScrollOffsetVertical = -100;
  517. Assert.Equal (0, tree.ScrollOffsetVertical);
  518. tree.ScrollOffsetVertical = 10;
  519. Assert.Equal (10, tree.ScrollOffsetVertical);
  520. }
  521. [Fact]
  522. [SetupFakeApplication]
  523. public void TestBottomlessTreeView_MaxDepth_3 ()
  524. {
  525. TreeView<string> tv = new ()
  526. {
  527. Driver = ApplicationImpl.Instance.Driver,
  528. Width = 20, Height = 10
  529. };
  530. tv.TreeBuilder = new DelegateTreeBuilder<string> (
  531. s => new [] { (int.Parse (s) + 1).ToString () }
  532. );
  533. tv.AddObject ("1");
  534. tv.SetScheme (new Scheme ());
  535. tv.LayoutSubViews ();
  536. tv.Draw ();
  537. // Nothing expanded
  538. DriverAssert.AssertDriverContentsAre (
  539. @"└+1
  540. ",
  541. output
  542. );
  543. tv.MaxDepth = 3;
  544. tv.ExpandAll ();
  545. tv.SetClipToScreen ();
  546. tv.Draw ();
  547. // Normal drawing of the tree view
  548. DriverAssert.AssertDriverContentsAre (
  549. @"
  550. └-1
  551. └-2
  552. └-3
  553. └─4
  554. ",
  555. output
  556. );
  557. }
  558. [Fact]
  559. [SetupFakeApplication]
  560. public void TestBottomlessTreeView_MaxDepth_5 ()
  561. {
  562. TreeView<string> tv = new () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  563. tv.TreeBuilder = new DelegateTreeBuilder<string> (
  564. s => new [] { (int.Parse (s) + 1).ToString () }
  565. );
  566. tv.AddObject ("1");
  567. tv.SetScheme (new Scheme ());
  568. tv.LayoutSubViews ();
  569. tv.Draw ();
  570. // Nothing expanded
  571. DriverAssert.AssertDriverContentsAre (
  572. @"└+1
  573. ",
  574. output
  575. );
  576. tv.MaxDepth = 5;
  577. tv.ExpandAll ();
  578. tv.SetClipToScreen ();
  579. tv.Draw ();
  580. // Normal drawing of the tree view
  581. DriverAssert.AssertDriverContentsAre (
  582. @"
  583. └-1
  584. └-2
  585. └-3
  586. └-4
  587. └-5
  588. └─6
  589. ",
  590. output
  591. );
  592. Assert.False (tv.CanExpand ("6"));
  593. Assert.False (tv.IsExpanded ("6"));
  594. tv.Collapse ("6");
  595. Assert.False (tv.CanExpand ("6"));
  596. Assert.False (tv.IsExpanded ("6"));
  597. tv.Collapse ("5");
  598. Assert.True (tv.CanExpand ("5"));
  599. Assert.False (tv.IsExpanded ("5"));
  600. tv.SetClipToScreen ();
  601. tv.Draw ();
  602. // Normal drawing of the tree view
  603. DriverAssert.AssertDriverContentsAre (
  604. @"
  605. └-1
  606. └-2
  607. └-3
  608. └-4
  609. └+5
  610. ",
  611. output
  612. );
  613. }
  614. [Fact]
  615. [SetupFakeApplication]
  616. public void TestGetObjectOnRow ()
  617. {
  618. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  619. tv.BeginInit ();
  620. tv.EndInit ();
  621. var n1 = new TreeNode ("normal");
  622. var n1_1 = new TreeNode ("pink");
  623. var n1_2 = new TreeNode ("normal");
  624. n1.Children.Add (n1_1);
  625. n1.Children.Add (n1_2);
  626. var n2 = new TreeNode ("pink");
  627. tv.AddObject (n1);
  628. tv.AddObject (n2);
  629. tv.Expand (n1);
  630. tv.SetScheme (new Scheme ());
  631. tv.LayoutSubViews ();
  632. tv.Draw ();
  633. DriverAssert.AssertDriverContentsAre (
  634. @"├-normal
  635. │ ├─pink
  636. │ └─normal
  637. └─pink
  638. ",
  639. output
  640. );
  641. Assert.Same (n1, tv.GetObjectOnRow (0));
  642. Assert.Same (n1_1, tv.GetObjectOnRow (1));
  643. Assert.Same (n1_2, tv.GetObjectOnRow (2));
  644. Assert.Same (n2, tv.GetObjectOnRow (3));
  645. Assert.Null (tv.GetObjectOnRow (4));
  646. tv.Collapse (n1);
  647. tv.SetClipToScreen ();
  648. tv.Draw ();
  649. DriverAssert.AssertDriverContentsAre (
  650. @"├+normal
  651. └─pink
  652. ",
  653. output
  654. );
  655. Assert.Same (n1, tv.GetObjectOnRow (0));
  656. Assert.Same (n2, tv.GetObjectOnRow (1));
  657. Assert.Null (tv.GetObjectOnRow (2));
  658. Assert.Null (tv.GetObjectOnRow (3));
  659. Assert.Null (tv.GetObjectOnRow (4));
  660. }
  661. [Fact]
  662. [SetupFakeApplication]
  663. public void TestGetObjectRow ()
  664. {
  665. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  666. var n1 = new TreeNode ("normal");
  667. var n1_1 = new TreeNode ("pink");
  668. var n1_2 = new TreeNode ("normal");
  669. n1.Children.Add (n1_1);
  670. n1.Children.Add (n1_2);
  671. var n2 = new TreeNode ("pink");
  672. tv.AddObject (n1);
  673. tv.AddObject (n2);
  674. tv.Expand (n1);
  675. tv.SetScheme (new Scheme ());
  676. tv.LayoutSubViews ();
  677. tv.SetClipToScreen ();
  678. tv.Draw ();
  679. DriverAssert.AssertDriverContentsAre (
  680. @"├-normal
  681. │ ├─pink
  682. │ └─normal
  683. └─pink
  684. ",
  685. output
  686. );
  687. Assert.Equal (0, tv.GetObjectRow (n1));
  688. Assert.Equal (1, tv.GetObjectRow (n1_1));
  689. Assert.Equal (2, tv.GetObjectRow (n1_2));
  690. Assert.Equal (3, tv.GetObjectRow (n2));
  691. tv.Collapse (n1);
  692. tv.LayoutSubViews ();
  693. tv.SetClipToScreen ();
  694. tv.Draw ();
  695. DriverAssert.AssertDriverContentsAre (
  696. @"├+normal
  697. └─pink
  698. ",
  699. output
  700. );
  701. Assert.Equal (0, tv.GetObjectRow (n1));
  702. Assert.Null (tv.GetObjectRow (n1_1));
  703. Assert.Null (tv.GetObjectRow (n1_2));
  704. Assert.Equal (1, tv.GetObjectRow (n2));
  705. // scroll down 1
  706. tv.ScrollOffsetVertical = 1;
  707. tv.LayoutSubViews ();
  708. tv.SetClipToScreen ();
  709. tv.Draw ();
  710. DriverAssert.AssertDriverContentsAre (
  711. @"└─pink
  712. ",
  713. output
  714. );
  715. Assert.Equal (-1, tv.GetObjectRow (n1));
  716. Assert.Null (tv.GetObjectRow (n1_1));
  717. Assert.Null (tv.GetObjectRow (n1_2));
  718. Assert.Equal (0, tv.GetObjectRow (n2));
  719. }
  720. [Fact]
  721. [SetupFakeApplication]
  722. public void TestTreeView_DrawLineEvent ()
  723. {
  724. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  725. List<DrawTreeViewLineEventArgs<ITreeNode>> eventArgs = new ();
  726. tv.DrawLine += (s, e) => { eventArgs.Add (e); };
  727. var n1 = new TreeNode ("root one");
  728. var n1_1 = new TreeNode ("leaf 1");
  729. var n1_2 = new TreeNode ("leaf 2");
  730. n1.Children.Add (n1_1);
  731. n1.Children.Add (n1_2);
  732. var n2 = new TreeNode ("root two");
  733. tv.AddObject (n1);
  734. tv.AddObject (n2);
  735. tv.Expand (n1);
  736. tv.SetScheme (new Scheme ());
  737. tv.LayoutSubViews ();
  738. tv.SetClipToScreen ();
  739. tv.Draw ();
  740. // Normal drawing of the tree view
  741. DriverAssert.AssertDriverContentsAre (
  742. @"
  743. ├-root one
  744. │ ├─leaf 1
  745. │ └─leaf 2
  746. └─root two
  747. ",
  748. output
  749. );
  750. Assert.Equal (4, eventArgs.Count ());
  751. Assert.Equal (0, eventArgs [0].Y);
  752. Assert.Equal (1, eventArgs [1].Y);
  753. Assert.Equal (2, eventArgs [2].Y);
  754. Assert.Equal (3, eventArgs [3].Y);
  755. Assert.All (eventArgs, ea => Assert.Equal (ea.Tree, tv));
  756. Assert.All (eventArgs, ea => Assert.False (ea.Handled));
  757. Assert.Equal ("├-root one", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  758. Assert.Equal ("│ ├─leaf 1", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  759. Assert.Equal ("│ └─leaf 2", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  760. Assert.Equal ("└─root two", eventArgs [3].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  761. Assert.Equal (1, eventArgs [0].IndexOfExpandCollapseSymbol);
  762. Assert.Equal (3, eventArgs [1].IndexOfExpandCollapseSymbol);
  763. Assert.Equal (3, eventArgs [2].IndexOfExpandCollapseSymbol);
  764. Assert.Equal (1, eventArgs [3].IndexOfExpandCollapseSymbol);
  765. Assert.Equal (2, eventArgs [0].IndexOfModelText);
  766. Assert.Equal (4, eventArgs [1].IndexOfModelText);
  767. Assert.Equal (4, eventArgs [2].IndexOfModelText);
  768. Assert.Equal (2, eventArgs [3].IndexOfModelText);
  769. Assert.Equal ("root one", eventArgs [0].Model.Text);
  770. Assert.Equal ("leaf 1", eventArgs [1].Model.Text);
  771. Assert.Equal ("leaf 2", eventArgs [2].Model.Text);
  772. Assert.Equal ("root two", eventArgs [3].Model.Text);
  773. }
  774. [Fact]
  775. [SetupFakeApplication]
  776. public void TestTreeView_DrawLineEvent_Handled ()
  777. {
  778. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  779. tv.DrawLine += (s, e) =>
  780. {
  781. if (e.Model.Text.Equals ("leaf 1"))
  782. {
  783. e.Handled = true;
  784. for (var i = 0; i < 10; i++)
  785. {
  786. e.Tree.AddRune (i, e.Y, new Rune ('F'));
  787. }
  788. }
  789. };
  790. var n1 = new TreeNode ("root one");
  791. var n1_1 = new TreeNode ("leaf 1");
  792. var n1_2 = new TreeNode ("leaf 2");
  793. n1.Children.Add (n1_1);
  794. n1.Children.Add (n1_2);
  795. var n2 = new TreeNode ("root two");
  796. tv.AddObject (n1);
  797. tv.AddObject (n2);
  798. tv.Expand (n1);
  799. tv.SetScheme (new Scheme ());
  800. tv.LayoutSubViews ();
  801. tv.Draw ();
  802. // Normal drawing of the tree view
  803. DriverAssert.AssertDriverContentsAre (
  804. @"
  805. ├-root one
  806. FFFFFFFFFF
  807. │ └─leaf 2
  808. └─root two
  809. ",
  810. output
  811. );
  812. }
  813. [Fact]
  814. [SetupFakeApplication]
  815. public void TestTreeView_DrawLineEvent_WithScrolling ()
  816. {
  817. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  818. List<DrawTreeViewLineEventArgs<ITreeNode>> eventArgs = new ();
  819. tv.DrawLine += (s, e) => { eventArgs.Add (e); };
  820. tv.ScrollOffsetHorizontal = 3;
  821. tv.ScrollOffsetVertical = 1;
  822. var n1 = new TreeNode ("root one");
  823. var n1_1 = new TreeNode ("leaf 1");
  824. var n1_2 = new TreeNode ("leaf 2");
  825. n1.Children.Add (n1_1);
  826. n1.Children.Add (n1_2);
  827. var n2 = new TreeNode ("root two");
  828. tv.AddObject (n1);
  829. tv.AddObject (n2);
  830. tv.Expand (n1);
  831. tv.SetScheme (new Scheme ());
  832. tv.LayoutSubViews ();
  833. tv.Draw ();
  834. // Normal drawing of the tree view
  835. DriverAssert.AssertDriverContentsAre (
  836. @"
  837. ─leaf 1
  838. ─leaf 2
  839. oot two
  840. ",
  841. output
  842. );
  843. Assert.Equal (3, eventArgs.Count ());
  844. Assert.Equal (0, eventArgs [0].Y);
  845. Assert.Equal (1, eventArgs [1].Y);
  846. Assert.Equal (2, eventArgs [2].Y);
  847. Assert.All (eventArgs, ea => Assert.Equal (ea.Tree, tv));
  848. Assert.All (eventArgs, ea => Assert.False (ea.Handled));
  849. Assert.Equal ("─leaf 1", eventArgs [0].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  850. Assert.Equal ("─leaf 2", eventArgs [1].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  851. Assert.Equal ("oot two", eventArgs [2].Cells.Aggregate ("", (s, n) => s += n.Grapheme).TrimEnd ());
  852. Assert.Equal (0, eventArgs [0].IndexOfExpandCollapseSymbol);
  853. Assert.Equal (0, eventArgs [1].IndexOfExpandCollapseSymbol);
  854. Assert.Null (eventArgs [2].IndexOfExpandCollapseSymbol);
  855. Assert.Equal (1, eventArgs [0].IndexOfModelText);
  856. Assert.Equal (1, eventArgs [1].IndexOfModelText);
  857. Assert.Equal (-1, eventArgs [2].IndexOfModelText);
  858. Assert.Equal ("leaf 1", eventArgs [0].Model.Text);
  859. Assert.Equal ("leaf 2", eventArgs [1].Model.Text);
  860. Assert.Equal ("root two", eventArgs [2].Model.Text);
  861. }
  862. [Fact]
  863. [SetupFakeApplication]
  864. public void TestTreeView_Filter ()
  865. {
  866. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  867. var n1 = new TreeNode ("root one");
  868. var n1_1 = new TreeNode ("leaf 1");
  869. var n1_2 = new TreeNode ("leaf 2");
  870. n1.Children.Add (n1_1);
  871. n1.Children.Add (n1_2);
  872. var n2 = new TreeNode ("root two");
  873. tv.AddObject (n1);
  874. tv.AddObject (n2);
  875. tv.Expand (n1);
  876. tv.SetScheme (new Scheme ());
  877. tv.LayoutSubViews ();
  878. tv.Draw ();
  879. // Normal drawing of the tree view
  880. DriverAssert.AssertDriverContentsAre (
  881. @"
  882. ├-root one
  883. │ ├─leaf 1
  884. │ └─leaf 2
  885. └─root two
  886. ",
  887. output
  888. );
  889. TreeViewTextFilter<ITreeNode> filter = new (tv);
  890. tv.Filter = filter;
  891. // matches nothing
  892. filter.Text = "asdfjhasdf";
  893. tv.SetClipToScreen ();
  894. tv.Draw ();
  895. // Normal drawing of the tree view
  896. DriverAssert.AssertDriverContentsAre (
  897. @"",
  898. output
  899. );
  900. // Matches everything
  901. filter.Text = "root";
  902. tv.SetClipToScreen ();
  903. tv.Draw ();
  904. DriverAssert.AssertDriverContentsAre (
  905. @"
  906. ├-root one
  907. │ ├─leaf 1
  908. │ └─leaf 2
  909. └─root two
  910. ",
  911. output
  912. );
  913. // Matches 2 leaf nodes
  914. filter.Text = "leaf";
  915. tv.SetClipToScreen ();
  916. tv.Draw ();
  917. DriverAssert.AssertDriverContentsAre (
  918. @"
  919. ├-root one
  920. │ ├─leaf 1
  921. │ └─leaf 2
  922. ",
  923. output
  924. );
  925. // Matches 1 leaf nodes
  926. filter.Text = "leaf 1";
  927. tv.SetClipToScreen ();
  928. tv.Draw ();
  929. DriverAssert.AssertDriverContentsAre (
  930. @"
  931. ├-root one
  932. │ ├─leaf 1
  933. ",
  934. output
  935. );
  936. }
  937. [Fact]
  938. [SetupFakeApplication]
  939. public void TestTreeViewColor ()
  940. {
  941. var tv = new TreeView () { Driver = ApplicationImpl.Instance.Driver, Width = 20, Height = 10 };
  942. tv.BeginInit ();
  943. tv.EndInit ();
  944. var n1 = new TreeNode ("normal");
  945. var n1_1 = new TreeNode ("pink");
  946. var n1_2 = new TreeNode ("normal");
  947. n1.Children.Add (n1_1);
  948. n1.Children.Add (n1_2);
  949. var n2 = new TreeNode ("pink");
  950. tv.AddObject (n1);
  951. tv.AddObject (n2);
  952. tv.Expand (n1);
  953. tv.SetScheme (new Scheme ());
  954. tv.LayoutSubViews ();
  955. tv.Draw ();
  956. // create a new scheme
  957. var pink = new Attribute (Color.Magenta, Color.Black);
  958. var hotpink = new Attribute (Color.BrightMagenta, Color.Black);
  959. // Normal drawing of the tree view
  960. DriverAssert.AssertDriverContentsAre (
  961. @"
  962. ├-normal
  963. │ ├─pink
  964. │ └─normal
  965. └─pink
  966. ",
  967. output
  968. );
  969. // Should all be the same color
  970. DriverAssert.AssertDriverAttributesAre (
  971. @"
  972. 0000000000
  973. 0000000000
  974. 0000000000
  975. 0000000000
  976. ",
  977. output,
  978. Application.Driver,
  979. tv.GetScheme ().Normal,
  980. pink
  981. );
  982. var pinkScheme = new Scheme { Normal = pink, Focus = hotpink };
  983. // and a delegate that uses the pink scheme
  984. // for nodes "pink"
  985. tv.ColorGetter = n => n.Text.Equals ("pink") ? pinkScheme : null;
  986. // redraw now that the custom color
  987. // delegate is registered
  988. tv.SetNeedsDraw ();
  989. tv.SetClipToScreen ();
  990. tv.Draw ();
  991. // Same text
  992. DriverAssert.AssertDriverContentsAre (
  993. @"
  994. ├-normal
  995. │ ├─pink
  996. │ └─normal
  997. └─pink
  998. ",
  999. output
  1000. );
  1001. // but now the item (only not lines) appear
  1002. // in pink when they are the word "pink"
  1003. DriverAssert.AssertDriverAttributesAre (
  1004. @"
  1005. 00000000
  1006. 00001111
  1007. 0000000000
  1008. 001111
  1009. ",
  1010. output,
  1011. Application.Driver,
  1012. tv.GetScheme ().Normal,
  1013. pink
  1014. );
  1015. }
  1016. [Fact]
  1017. public void TreeNode_WorksWithoutDelegate ()
  1018. {
  1019. var tree = new TreeView ();
  1020. var root = new TreeNode ("Root");
  1021. root.Children.Add (new TreeNode ("Leaf1"));
  1022. root.Children.Add (new TreeNode ("Leaf2"));
  1023. tree.AddObject (root);
  1024. tree.Expand (root);
  1025. Assert.Equal (2, tree.GetChildren (root).Count ());
  1026. }
  1027. /// <summary>Test object which considers for equality only <see cref="Name"/></summary>
  1028. private class EqualityTestObject
  1029. {
  1030. public int Age { get; set; }
  1031. public string Name { get; set; }
  1032. public override bool Equals (object obj) { return obj is EqualityTestObject eto && Equals (Name, eto.Name); }
  1033. public override int GetHashCode () { return Name?.GetHashCode () ?? base.GetHashCode (); }
  1034. }
  1035. #region Test Setup Methods
  1036. private class Factory
  1037. {
  1038. public Car [] Cars { get; set; }
  1039. public override string ToString () { return "Factory"; }
  1040. }
  1041. private class Car
  1042. {
  1043. public string Name { get; set; }
  1044. public override string ToString () { return Name; }
  1045. }
  1046. private TreeView<object> CreateTree () { return CreateTree (out _, out _, out _); }
  1047. private TreeView<object> CreateTree (out Factory factory1, out Car car1, out Car car2)
  1048. {
  1049. car1 = new Car ();
  1050. car2 = new Car ();
  1051. factory1 = new Factory { Cars = new [] { car1, car2 } };
  1052. TreeView<object> tree = new (new DelegateTreeBuilder<object> (s => s is Factory f ? f.Cars : null));
  1053. tree.AddObject (factory1);
  1054. return tree;
  1055. }
  1056. #endregion
  1057. [Fact]
  1058. public void HotKey_Command_SetsFocus ()
  1059. {
  1060. var view = new TreeView ();
  1061. view.CanFocus = true;
  1062. Assert.False (view.HasFocus);
  1063. view.InvokeCommand (Command.HotKey);
  1064. Assert.True (view.HasFocus);
  1065. }
  1066. [Fact]
  1067. public void HotKey_Command_Does_Not_Accept ()
  1068. {
  1069. var treeView = new TreeView ();
  1070. var accepted = false;
  1071. treeView.Accepting += OnAccept;
  1072. treeView.InvokeCommand (Command.HotKey);
  1073. Assert.False (accepted);
  1074. return;
  1075. void OnAccept (object sender, CommandEventArgs e) { accepted = true; }
  1076. }
  1077. [Fact]
  1078. public void Accept_Command_Accepts_and_ActivatesObject ()
  1079. {
  1080. var treeView = CreateTree (out Factory f, out Car car1, out _);
  1081. Assert.NotNull (car1);
  1082. treeView.SelectedObject = car1;
  1083. var accepted = false;
  1084. var activated = false;
  1085. object selectedObject = null;
  1086. treeView.Accepting += Accept;
  1087. treeView.ObjectActivated += ObjectActivated;
  1088. treeView.InvokeCommand (Command.Accept);
  1089. Assert.True (accepted);
  1090. Assert.True (activated);
  1091. Assert.Equal (car1, selectedObject);
  1092. return;
  1093. void ObjectActivated (object sender, ObjectActivatedEventArgs<object> e)
  1094. {
  1095. activated = true;
  1096. selectedObject = e.ActivatedObject;
  1097. }
  1098. void Accept (object sender, CommandEventArgs e) { accepted = true; }
  1099. }
  1100. [Fact]
  1101. public void Accept_Cancel_Event_Prevents_ObjectActivated ()
  1102. {
  1103. var treeView = CreateTree (out Factory f, out Car car1, out _);
  1104. treeView.SelectedObject = car1;
  1105. var accepted = false;
  1106. var activated = false;
  1107. object selectedObject = null;
  1108. treeView.Accepting += Accept;
  1109. treeView.ObjectActivated += ObjectActivated;
  1110. treeView.InvokeCommand (Command.Accept);
  1111. Assert.True (accepted);
  1112. Assert.False (activated);
  1113. Assert.Null (selectedObject);
  1114. return;
  1115. void ObjectActivated (object sender, ObjectActivatedEventArgs<object> e)
  1116. {
  1117. activated = true;
  1118. selectedObject = e.ActivatedObject;
  1119. }
  1120. void Accept (object sender, CommandEventArgs e)
  1121. {
  1122. accepted = true;
  1123. e.Handled = true;
  1124. }
  1125. }
  1126. }