1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/controls/treectrltest.cpp
3 // Purpose: wxTreeCtrl unit test
4 // Author: Vadim Zeitlin
5 // Created: 2008-11-26
6 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
7 // (c) 2010 Steven Lamerton
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 #include "testprec.h"
15
16 #if wxUSE_TREECTRL
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #ifndef WX_PRECOMP
23 #include "wx/app.h"
24 #endif // WX_PRECOMP
25
26 #include "wx/artprov.h"
27 #include "wx/imaglist.h"
28 #include "wx/treectrl.h"
29 #include "wx/uiaction.h"
30 #include "testableframe.h"
31
32 // ----------------------------------------------------------------------------
33 // test class
34 // ----------------------------------------------------------------------------
35
36 class TreeCtrlTestCase : public CppUnit::TestCase
37 {
38 public:
TreeCtrlTestCase()39 TreeCtrlTestCase() { }
40
41 virtual void setUp();
42 virtual void tearDown();
43
44 private:
45 CPPUNIT_TEST_SUITE( TreeCtrlTestCase );
46 WXUISIM_TEST( ItemClick );
47 CPPUNIT_TEST( DeleteItem );
48 WXUISIM_TEST( LabelEdit );
49 WXUISIM_TEST( KeyDown );
50 #ifndef __WXGTK__
51 WXUISIM_TEST( CollapseExpandEvents );
52 WXUISIM_TEST( SelectionChange );
53 #endif // !__WXGTK__
54 WXUISIM_TEST( Menu );
55 CPPUNIT_TEST( ItemData );
56 CPPUNIT_TEST( Iteration );
57 CPPUNIT_TEST( Parent );
58 CPPUNIT_TEST( CollapseExpand );
59 CPPUNIT_TEST( AssignImageList );
60 CPPUNIT_TEST( Focus );
61 CPPUNIT_TEST( Bold );
62 CPPUNIT_TEST( Visible );
63 CPPUNIT_TEST( Sort );
64 WXUISIM_TEST( KeyNavigation );
65 CPPUNIT_TEST( HasChildren );
66 CPPUNIT_TEST( SelectItemSingle );
67 CPPUNIT_TEST( PseudoTest_MultiSelect );
68 CPPUNIT_TEST( SelectItemMulti );
69 CPPUNIT_TEST( PseudoTest_SetHiddenRoot );
70 CPPUNIT_TEST( HasChildren );
71 CPPUNIT_TEST_SUITE_END();
72
73 void ItemClick();
74 void DeleteItem();
75 void LabelEdit();
76 void KeyDown();
77 #ifndef __WXGTK__
78 void CollapseExpandEvents();
79 void SelectionChange();
80 #endif // !__WXGTK__
81 void Menu();
82 void ItemData();
83 void Iteration();
84 void Parent();
85 void CollapseExpand();
86 void AssignImageList();
87 void Focus();
88 void Bold();
89 void Visible();
90 void Sort();
91 void KeyNavigation();
92 void HasChildren();
93 void SelectItemSingle();
94 void SelectItemMulti();
PseudoTest_MultiSelect()95 void PseudoTest_MultiSelect() { ms_multiSelect = true; }
PseudoTest_SetHiddenRoot()96 void PseudoTest_SetHiddenRoot() { ms_hiddenRoot = true; }
97
98 static bool ms_multiSelect;
99 static bool ms_hiddenRoot;
100
101 // the tree control itself
102 wxTreeCtrl *m_tree;
103
104 // and some of its items
105 wxTreeItemId m_root,
106 m_child1,
107 m_child2,
108 m_grandchild;
109
110 DECLARE_NO_COPY_CLASS(TreeCtrlTestCase)
111 };
112
113 // register in the unnamed registry so that these tests are run by default
114 CPPUNIT_TEST_SUITE_REGISTRATION( TreeCtrlTestCase );
115
116 // also include in its own registry so that these tests can be run alone
117 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TreeCtrlTestCase, "TreeCtrlTestCase" );
118
119 // ----------------------------------------------------------------------------
120 // test initialization
121 // ----------------------------------------------------------------------------
122
123 bool TreeCtrlTestCase::ms_multiSelect = false;
124 bool TreeCtrlTestCase::ms_hiddenRoot = false;
125
setUp()126 void TreeCtrlTestCase::setUp()
127 {
128 m_tree = new wxTreeCtrl(wxTheApp->GetTopWindow(),
129 wxID_ANY,
130 wxDefaultPosition,
131 wxSize(400, 200),
132 wxTR_DEFAULT_STYLE | wxTR_EDIT_LABELS);
133
134 if ( ms_multiSelect )
135 m_tree->ToggleWindowStyle(wxTR_MULTIPLE);
136
137 if ( ms_hiddenRoot )
138 m_tree->ToggleWindowStyle(wxTR_HIDE_ROOT); // actually set it
139
140 m_root = m_tree->AddRoot("root");
141 m_child1 = m_tree->AppendItem(m_root, "child1");
142 m_child2 = m_tree->AppendItem(m_root, "child2");
143 m_grandchild = m_tree->AppendItem(m_child1, "grandchild");
144
145 m_tree->SetSize(400, 200);
146 m_tree->ExpandAll();
147 m_tree->Refresh();
148 m_tree->Update();
149 }
150
tearDown()151 void TreeCtrlTestCase::tearDown()
152 {
153 delete m_tree;
154 m_tree = NULL;
155
156 m_root =
157 m_child1 =
158 m_child2 =
159 m_grandchild = wxTreeItemId();
160 }
161
162 // ----------------------------------------------------------------------------
163 // the tests themselves
164 // ----------------------------------------------------------------------------
165
HasChildren()166 void TreeCtrlTestCase::HasChildren()
167 {
168 CPPUNIT_ASSERT( m_tree->HasChildren(m_root) );
169 CPPUNIT_ASSERT( m_tree->HasChildren(m_child1) );
170 CPPUNIT_ASSERT( !m_tree->HasChildren(m_child2) );
171 CPPUNIT_ASSERT( !m_tree->HasChildren(m_grandchild) );
172 }
173
SelectItemSingle()174 void TreeCtrlTestCase::SelectItemSingle()
175 {
176 // this test should be only ran in single-selection control
177 CPPUNIT_ASSERT( !m_tree->HasFlag(wxTR_MULTIPLE) );
178
179 // initially nothing is selected
180 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
181
182 // selecting an item should make it selected
183 m_tree->SelectItem(m_child1);
184 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
185
186 // selecting it again shouldn't change anything
187 m_tree->SelectItem(m_child1);
188 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
189
190 // selecting another item should switch the selection to it
191 m_tree->SelectItem(m_child2);
192 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
193 CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) );
194
195 // selecting it again still shouldn't change anything
196 m_tree->SelectItem(m_child2);
197 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
198 CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) );
199
200 // deselecting an item should remove the selection entirely
201 m_tree->UnselectItem(m_child2);
202 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
203 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child2) );
204 }
205
SelectItemMulti()206 void TreeCtrlTestCase::SelectItemMulti()
207 {
208 // this test should be only ran in multi-selection control
209 CPPUNIT_ASSERT( m_tree->HasFlag(wxTR_MULTIPLE) );
210
211 // initially nothing is selected
212 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
213
214 // selecting an item should make it selected
215 m_tree->SelectItem(m_child1);
216 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
217
218 // selecting it again shouldn't change anything
219 m_tree->SelectItem(m_child1);
220 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
221
222 // selecting another item shouldn't deselect the previously selected one
223 m_tree->SelectItem(m_child2);
224 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
225 CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) );
226
227 // selecting it again still shouldn't change anything
228 m_tree->SelectItem(m_child2);
229 CPPUNIT_ASSERT( m_tree->IsSelected(m_child1) );
230 CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) );
231
232 // deselecting one of the items should leave the others selected
233 m_tree->UnselectItem(m_child1);
234 CPPUNIT_ASSERT( !m_tree->IsSelected(m_child1) );
235 CPPUNIT_ASSERT( m_tree->IsSelected(m_child2) );
236 }
237
ItemClick()238 void TreeCtrlTestCase::ItemClick()
239 {
240 #if wxUSE_UIACTIONSIMULATOR
241 EventCounter activated(m_tree, wxEVT_TREE_ITEM_ACTIVATED);
242 EventCounter rclick(m_tree, wxEVT_TREE_ITEM_RIGHT_CLICK);
243
244 wxUIActionSimulator sim;
245
246 wxRect pos;
247 m_tree->GetBoundingRect(m_child1, pos, true);
248
249 // We move in slightly so we are not on the edge
250 wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4);
251
252 sim.MouseMove(point);
253 wxYield();
254
255 sim.MouseDblClick();
256 wxYield();
257
258 sim.MouseClick(wxMOUSE_BTN_RIGHT);
259 wxYield();
260
261 CPPUNIT_ASSERT_EQUAL(1, activated.GetCount());
262 CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount());
263 #endif // wxUSE_UIACTIONSIMULATOR
264 }
265
DeleteItem()266 void TreeCtrlTestCase::DeleteItem()
267 {
268 EventCounter deleteitem(m_tree, wxEVT_TREE_DELETE_ITEM);
269
270 wxTreeItemId todelete = m_tree->AppendItem(m_root, "deleteme");
271 m_tree->Delete(todelete);
272 // We do not test DeleteAllItems() as under some versions of Windows events
273 // are not generated.
274
275 CPPUNIT_ASSERT_EQUAL(1, deleteitem.GetCount());
276 }
277
278 #if wxUSE_UIACTIONSIMULATOR
279
LabelEdit()280 void TreeCtrlTestCase::LabelEdit()
281 {
282 EventCounter beginedit(m_tree, wxEVT_TREE_BEGIN_LABEL_EDIT);
283 EventCounter endedit(m_tree, wxEVT_TREE_END_LABEL_EDIT);
284
285 wxUIActionSimulator sim;
286
287 m_tree->SetFocusedItem(m_tree->GetRootItem());
288 m_tree->EditLabel(m_tree->GetRootItem());
289
290 sim.Text("newroottext");
291 wxYield();
292
293 CPPUNIT_ASSERT_EQUAL(1, beginedit.GetCount());
294
295 sim.Char(WXK_RETURN);
296 wxYield();
297
298 CPPUNIT_ASSERT_EQUAL(1, endedit.GetCount());
299 }
300
KeyDown()301 void TreeCtrlTestCase::KeyDown()
302 {
303 EventCounter keydown(m_tree, wxEVT_TREE_KEY_DOWN);
304
305 wxUIActionSimulator sim;
306
307 m_tree->SetFocus();
308 sim.Text("aAbB");
309 wxYield();
310
311 CPPUNIT_ASSERT_EQUAL(6, keydown.GetCount());
312 }
313
314 #if !defined(__WXGTK__)
315
CollapseExpandEvents()316 void TreeCtrlTestCase::CollapseExpandEvents()
317 {
318 m_tree->CollapseAll();
319
320 EventCounter collapsed(m_tree, wxEVT_TREE_ITEM_COLLAPSED);
321 EventCounter collapsing(m_tree, wxEVT_TREE_ITEM_COLLAPSING);
322 EventCounter expanded(m_tree, wxEVT_TREE_ITEM_EXPANDED);
323 EventCounter expanding(m_tree, wxEVT_TREE_ITEM_EXPANDING);
324
325 wxUIActionSimulator sim;
326
327 wxRect pos;
328 m_tree->GetBoundingRect(m_root, pos, true);
329
330 // We move in slightly so we are not on the edge
331 wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4);
332
333 sim.MouseMove(point);
334 wxYield();
335
336 sim.MouseDblClick();
337 wxYield();
338
339 CPPUNIT_ASSERT_EQUAL(1, expanding.GetCount());
340 CPPUNIT_ASSERT_EQUAL(1, expanded.GetCount());
341
342 sim.MouseDblClick();
343 wxYield();
344
345 CPPUNIT_ASSERT_EQUAL(1, collapsing.GetCount());
346 CPPUNIT_ASSERT_EQUAL(1, collapsed.GetCount());
347 }
348
SelectionChange()349 void TreeCtrlTestCase::SelectionChange()
350 {
351 m_tree->ExpandAll();
352
353 // This is currently needed to work around a problem under wxMSW: clicking
354 // on an item in an unfocused control generates two selection change events
355 // because of the SetFocus() call in TVN_SELCHANGED handler in wxMSW code.
356 // This is, of course, wrong on its own, but fixing it without breaking
357 // anything else is non-obvious, so for now at least work around this
358 // problem in the test.
359 m_tree->SetFocus();
360
361 EventCounter changed(m_tree, wxEVT_TREE_SEL_CHANGED);
362 EventCounter changing(m_tree, wxEVT_TREE_SEL_CHANGING);
363
364 wxUIActionSimulator sim;
365
366 wxRect poschild1, poschild2;
367 m_tree->GetBoundingRect(m_child1, poschild1, true);
368 m_tree->GetBoundingRect(m_child2, poschild2, true);
369
370 // We move in slightly so we are not on the edge
371 wxPoint point1 = m_tree->ClientToScreen(poschild1.GetPosition()) + wxPoint(4, 4);
372 wxPoint point2 = m_tree->ClientToScreen(poschild2.GetPosition()) + wxPoint(4, 4);
373
374 sim.MouseMove(point1);
375 wxYield();
376
377 sim.MouseClick();
378 wxYield();
379
380 CPPUNIT_ASSERT_EQUAL(1, changed.GetCount());
381 CPPUNIT_ASSERT_EQUAL(1, changing.GetCount());
382
383 sim.MouseMove(point2);
384 wxYield();
385
386 sim.MouseClick();
387 wxYield();
388
389 CPPUNIT_ASSERT_EQUAL(2, changed.GetCount());
390 CPPUNIT_ASSERT_EQUAL(2, changing.GetCount());
391 }
392
393 #endif // !__WXGTK__
394
Menu()395 void TreeCtrlTestCase::Menu()
396 {
397 EventCounter menu(m_tree, wxEVT_TREE_ITEM_MENU);
398 wxUIActionSimulator sim;
399
400 wxRect pos;
401 m_tree->GetBoundingRect(m_child1, pos, true);
402
403 // We move in slightly so we are not on the edge
404 wxPoint point = m_tree->ClientToScreen(pos.GetPosition()) + wxPoint(4, 4);
405
406 sim.MouseMove(point);
407 wxYield();
408
409 sim.MouseClick(wxMOUSE_BTN_RIGHT);
410 wxYield();
411
412 CPPUNIT_ASSERT_EQUAL(1, menu.GetCount());
413 }
414
415 #endif // wxUSE_UIACTIONSIMULATOR
416
ItemData()417 void TreeCtrlTestCase::ItemData()
418 {
419 wxTreeItemData* child1data = new wxTreeItemData();
420 wxTreeItemData* appenddata = new wxTreeItemData();
421 wxTreeItemData* insertdata = new wxTreeItemData();
422
423 m_tree->SetItemData(m_child1, child1data);
424
425 CPPUNIT_ASSERT_EQUAL(child1data, m_tree->GetItemData(m_child1));
426 CPPUNIT_ASSERT_EQUAL(m_child1, child1data->GetId());
427
428 wxTreeItemId append = m_tree->AppendItem(m_root, "new", -1, -1, appenddata);
429
430 CPPUNIT_ASSERT_EQUAL(appenddata, m_tree->GetItemData(append));
431 CPPUNIT_ASSERT_EQUAL(append, appenddata->GetId());
432
433 wxTreeItemId insert = m_tree->InsertItem(m_root, m_child1, "new", -1, -1,
434 insertdata);
435
436 CPPUNIT_ASSERT_EQUAL(insertdata, m_tree->GetItemData(insert));
437 CPPUNIT_ASSERT_EQUAL(insert, insertdata->GetId());
438 }
439
Iteration()440 void TreeCtrlTestCase::Iteration()
441 {
442 // Get first / next / last child
443 wxTreeItemIdValue cookie;
444 CPPUNIT_ASSERT_EQUAL(m_tree->GetFirstChild(m_root, cookie), m_child1);
445 CPPUNIT_ASSERT_EQUAL(m_tree->GetNextChild(m_root, cookie),
446 m_tree->GetLastChild(m_root));
447 CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetLastChild(m_root));
448
449 // Get next / previous sibling
450 CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextSibling(m_child1));
451 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetPrevSibling(m_child2));
452 }
453
Parent()454 void TreeCtrlTestCase::Parent()
455 {
456 CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetRootItem());
457 CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetItemParent(m_child1));
458 CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetItemParent(m_child2));
459 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetItemParent(m_grandchild));
460 }
461
CollapseExpand()462 void TreeCtrlTestCase::CollapseExpand()
463 {
464 m_tree->ExpandAll();
465
466 CPPUNIT_ASSERT(m_tree->IsExpanded(m_root));
467 CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1));
468
469 m_tree->CollapseAll();
470
471 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root));
472 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_child1));
473
474 m_tree->ExpandAllChildren(m_root);
475
476 CPPUNIT_ASSERT(m_tree->IsExpanded(m_root));
477 CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1));
478
479 m_tree->CollapseAllChildren(m_child1);
480
481 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_child1));
482
483 m_tree->Expand(m_child1);
484
485 CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1));
486
487 m_tree->Collapse(m_root);
488
489 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root));
490 CPPUNIT_ASSERT(m_tree->IsExpanded(m_child1));
491
492 m_tree->CollapseAndReset(m_root);
493
494 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root));
495 }
496
AssignImageList()497 void TreeCtrlTestCase::AssignImageList()
498 {
499 wxSize size(16, 16);
500
501 wxImageList *imagelist = new wxImageList(size.x, size.y);
502 imagelist->Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, size));
503
504 wxImageList *statelist = new wxImageList(size.x, size.y);
505 statelist->Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, size));
506
507 m_tree->AssignImageList(imagelist);
508 m_tree->AssignStateImageList(statelist);
509
510 CPPUNIT_ASSERT_EQUAL(imagelist, m_tree->GetImageList());
511 CPPUNIT_ASSERT_EQUAL(statelist, m_tree->GetStateImageList());
512 }
513
Focus()514 void TreeCtrlTestCase::Focus()
515 {
516 #if !defined(__WXGTK__) && !defined(__WXOSX__)
517 m_tree->SetFocusedItem(m_child1);
518
519 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetFocusedItem());
520
521 m_tree->ClearFocusedItem();
522
523 CPPUNIT_ASSERT(!m_tree->GetFocusedItem());
524 #endif
525 }
526
Bold()527 void TreeCtrlTestCase::Bold()
528 {
529 CPPUNIT_ASSERT(!m_tree->IsBold(m_child1));
530
531 m_tree->SetItemBold(m_child1);
532
533 CPPUNIT_ASSERT(m_tree->IsBold(m_child1));
534
535 m_tree->SetItemBold(m_child1, false);
536
537 CPPUNIT_ASSERT(!m_tree->IsBold(m_child1));
538 }
539
Visible()540 void TreeCtrlTestCase::Visible()
541 {
542 m_tree->CollapseAll();
543
544 CPPUNIT_ASSERT(m_tree->IsVisible(m_root));
545 CPPUNIT_ASSERT(!m_tree->IsVisible(m_child1));
546
547 m_tree->EnsureVisible(m_grandchild);
548
549 CPPUNIT_ASSERT(m_tree->IsVisible(m_grandchild));
550
551 m_tree->ExpandAll();
552
553 CPPUNIT_ASSERT_EQUAL(m_root, m_tree->GetFirstVisibleItem());
554 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetNextVisible(m_root));
555 CPPUNIT_ASSERT_EQUAL(m_grandchild, m_tree->GetNextVisible(m_child1));
556 CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextVisible(m_grandchild));
557
558 CPPUNIT_ASSERT(!m_tree->GetNextVisible(m_child2));
559 CPPUNIT_ASSERT(!m_tree->GetPrevVisible(m_root));
560 }
561
Sort()562 void TreeCtrlTestCase::Sort()
563 {
564 wxTreeItemId zitem = m_tree->AppendItem(m_root, "zzzz");
565 wxTreeItemId aitem = m_tree->AppendItem(m_root, "aaaa");
566
567 m_tree->SortChildren(m_root);
568
569 wxTreeItemIdValue cookie;
570
571 CPPUNIT_ASSERT_EQUAL(aitem, m_tree->GetFirstChild(m_root, cookie));
572 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetNextChild(m_root, cookie));
573 CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetNextChild(m_root, cookie));
574 CPPUNIT_ASSERT_EQUAL(zitem, m_tree->GetNextChild(m_root, cookie));
575 }
576
KeyNavigation()577 void TreeCtrlTestCase::KeyNavigation()
578 {
579 #if wxUSE_UIACTIONSIMULATOR && !defined(__WXGTK__)
580 wxUIActionSimulator sim;
581
582 m_tree->CollapseAll();
583
584 m_tree->SelectItem(m_root);
585
586 m_tree->SetFocus();
587 sim.Char(WXK_RIGHT);
588 wxYield();
589
590 CPPUNIT_ASSERT(m_tree->IsExpanded(m_root));
591
592 sim.Char(WXK_LEFT);
593 wxYield();
594
595 CPPUNIT_ASSERT(!m_tree->IsExpanded(m_root));
596
597 sim.Char(WXK_RIGHT);
598 sim.Char(WXK_DOWN);
599 wxYield();
600
601 CPPUNIT_ASSERT_EQUAL(m_child1, m_tree->GetSelection());
602
603 sim.Char(WXK_DOWN);
604 wxYield();
605
606 CPPUNIT_ASSERT_EQUAL(m_child2, m_tree->GetSelection());
607 #endif
608 }
609
610 #endif //wxUSE_TREECTRL
611