TreeViewTests.cs 44 KB

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