Fix crash when auto-sizing a wxDataViewCtrl column.
[wxWidgets.git] / tests / controls / listbasetest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/controls/listbasetest.cpp
3 // Purpose: Base class for wxListCtrl and wxListView tests
4 // Author: Steven Lamerton
5 // Created: 2010-07-20
6 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>,
7 // (c) 2010 Steven Lamerton
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "testprec.h"
11
12 #if wxUSE_LISTCTRL
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #ifndef WX_PRECOMP
19 #include "wx/app.h"
20 #endif // WX_PRECOMP
21
22 #include "wx/listctrl.h"
23 #include "listbasetest.h"
24 #include "testableframe.h"
25 #include "asserthelper.h"
26 #include "wx/uiaction.h"
27 #include "wx/imaglist.h"
28 #include "wx/artprov.h"
29
30 void ListBaseTestCase::ColumnsOrder()
31 {
32 #ifdef wxHAS_LISTCTRL_COLUMN_ORDER
33 wxListCtrl* const list = GetList();
34
35 int n;
36 wxListItem li;
37 li.SetMask(wxLIST_MASK_TEXT);
38
39 // first set up some columns
40 static const int NUM_COLS = 3;
41
42 list->InsertColumn(0, "Column 0");
43 list->InsertColumn(1, "Column 1");
44 list->InsertColumn(2, "Column 2");
45
46 // and a couple of test items too
47 list->InsertItem(0, "Item 0");
48 list->SetItem(0, 1, "first in first");
49
50 list->InsertItem(1, "Item 1");
51 list->SetItem(1, 2, "second in second");
52
53
54 // check that the order is natural in the beginning
55 const wxArrayInt orderOrig = list->GetColumnsOrder();
56 for ( n = 0; n < NUM_COLS; n++ )
57 CPPUNIT_ASSERT_EQUAL( n, orderOrig[n] );
58
59 // then rearrange them: using { 2, 0, 1 } order means that column 2 is
60 // shown first, then column 0 and finally column 1
61 wxArrayInt order(3);
62 order[0] = 2;
63 order[1] = 0;
64 order[2] = 1;
65 list->SetColumnsOrder(order);
66
67 // check that we get back the same order as we set
68 const wxArrayInt orderNew = list->GetColumnsOrder();
69 for ( n = 0; n < NUM_COLS; n++ )
70 CPPUNIT_ASSERT_EQUAL( order[n], orderNew[n] );
71
72 // and the order -> index mappings for individual columns
73 for ( n = 0; n < NUM_COLS; n++ )
74 CPPUNIT_ASSERT_EQUAL( order[n], list->GetColumnIndexFromOrder(n) );
75
76 // and also the reverse mapping
77 CPPUNIT_ASSERT_EQUAL( 1, list->GetColumnOrder(0) );
78 CPPUNIT_ASSERT_EQUAL( 2, list->GetColumnOrder(1) );
79 CPPUNIT_ASSERT_EQUAL( 0, list->GetColumnOrder(2) );
80
81
82 // finally check that accessors still use indices, not order
83 CPPUNIT_ASSERT( list->GetColumn(0, li) );
84 CPPUNIT_ASSERT_EQUAL( "Column 0", li.GetText() );
85
86 li.SetId(0);
87 li.SetColumn(1);
88 CPPUNIT_ASSERT( list->GetItem(li) );
89 CPPUNIT_ASSERT_EQUAL( "first in first", li.GetText() );
90
91 li.SetId(1);
92 li.SetColumn(2);
93 CPPUNIT_ASSERT( list->GetItem(li) );
94 CPPUNIT_ASSERT_EQUAL( "second in second", li.GetText() );
95
96 //tidy up when we are finished
97 list->ClearAll();
98 #endif // wxHAS_LISTCTRL_COLUMN_ORDER
99 }
100
101
102
103 void ListBaseTestCase::ItemRect()
104 {
105 wxListCtrl* const list = GetList();
106
107 // set up for the test
108 list->InsertColumn(0, "Column 0", wxLIST_FORMAT_LEFT, 60);
109 list->InsertColumn(1, "Column 1", wxLIST_FORMAT_LEFT, 50);
110 list->InsertColumn(2, "Column 2", wxLIST_FORMAT_LEFT, 40);
111
112 list->InsertItem(0, "Item 0");
113 list->SetItem(0, 1, "first column");
114 list->SetItem(0, 1, "second column");
115
116 // do test
117 wxRect r;
118 WX_ASSERT_FAILS_WITH_ASSERT( list->GetItemRect(1, r) );
119 CPPUNIT_ASSERT( list->GetItemRect(0, r) );
120 CPPUNIT_ASSERT_EQUAL( 150, r.GetWidth() );
121
122 CPPUNIT_ASSERT( list->GetSubItemRect(0, 0, r) );
123 CPPUNIT_ASSERT_EQUAL( 60, r.GetWidth() );
124
125 CPPUNIT_ASSERT( list->GetSubItemRect(0, 1, r) );
126 CPPUNIT_ASSERT_EQUAL( 50, r.GetWidth() );
127
128 CPPUNIT_ASSERT( list->GetSubItemRect(0, 2, r) );
129 CPPUNIT_ASSERT_EQUAL( 40, r.GetWidth() );
130
131 WX_ASSERT_FAILS_WITH_ASSERT( list->GetSubItemRect(0, 3, r) );
132
133
134 // As we have a header, the top item shouldn't be at (0, 0), but somewhere
135 // below the header.
136 //
137 // Notice that we consider that the header can't be less than 10 pixels
138 // because we don't know its exact height.
139 CPPUNIT_ASSERT( list->GetItemRect(0, r) );
140 CPPUNIT_ASSERT( r.y >= 10 );
141
142 // However if we remove the header now, the item should be at (0, 0).
143 list->SetWindowStyle(wxLC_REPORT | wxLC_NO_HEADER);
144 CPPUNIT_ASSERT( list->GetItemRect(0, r) );
145 CPPUNIT_ASSERT_EQUAL( 0, r.y );
146
147
148 //tidy up when we are finished
149 list->ClearAll();
150 }
151
152 void ListBaseTestCase::ItemText()
153 {
154 wxListCtrl* const list = GetList();
155
156 list->InsertColumn(0, "First");
157 list->InsertColumn(1, "Second");
158
159 list->InsertItem(0, "0,0");
160 CPPUNIT_ASSERT_EQUAL( "0,0", list->GetItemText(0) );
161 CPPUNIT_ASSERT_EQUAL( "", list->GetItemText(0, 1) );
162
163 list->SetItem(0, 1, "0,1");
164 CPPUNIT_ASSERT_EQUAL( "0,1", list->GetItemText(0, 1) );
165 }
166
167 void ListBaseTestCase::ChangeMode()
168 {
169 wxListCtrl* const list = GetList();
170
171 list->InsertColumn(0, "Header");
172 list->InsertItem(0, "First");
173 list->InsertItem(1, "Second");
174 CPPUNIT_ASSERT_EQUAL( 2, list->GetItemCount() );
175
176 // check that switching the mode preserves the items
177 list->SetWindowStyle(wxLC_ICON);
178 CPPUNIT_ASSERT_EQUAL( 2, list->GetItemCount() );
179 CPPUNIT_ASSERT_EQUAL( "First", list->GetItemText(0) );
180
181 // and so does switching back
182 list->SetWindowStyle(wxLC_REPORT);
183 CPPUNIT_ASSERT_EQUAL( 2, list->GetItemCount() );
184 CPPUNIT_ASSERT_EQUAL( "First", list->GetItemText(0) );
185
186 //tidy up when we are finished
187 list->ClearAll();
188 }
189
190 void ListBaseTestCase::ItemClick()
191 {
192 #if wxUSE_UIACTIONSIMULATOR
193
194 #ifdef __WXMSW__
195 // FIXME: This test fails on MSW buildbot slaves although works fine on
196 // development machine, no idea why. It seems to be a problem with
197 // wxUIActionSimulator rather the wxListCtrl control itself however.
198 if ( IsAutomaticTest() )
199 return;
200 #endif // __WXMSW__
201
202 wxListCtrl* const list = GetList();
203
204 list->InsertColumn(0, "Column 0", wxLIST_FORMAT_LEFT, 60);
205 list->InsertColumn(1, "Column 1", wxLIST_FORMAT_LEFT, 50);
206 list->InsertColumn(2, "Column 2", wxLIST_FORMAT_LEFT, 40);
207
208 list->InsertItem(0, "Item 0");
209 list->SetItem(0, 1, "first column");
210 list->SetItem(0, 2, "second column");
211
212 EventCounter selected(list, wxEVT_LIST_ITEM_SELECTED);
213 EventCounter focused(list, wxEVT_LIST_ITEM_FOCUSED);
214 EventCounter activated(list, wxEVT_LIST_ITEM_ACTIVATED);
215 EventCounter rclick(list, wxEVT_LIST_ITEM_RIGHT_CLICK);
216
217 wxUIActionSimulator sim;
218
219 wxRect pos;
220 list->GetItemRect(0, pos);
221
222 //We move in slightly so we are not on the edge
223 wxPoint point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 5);
224
225 sim.MouseMove(point);
226 wxYield();
227
228 sim.MouseClick();
229 wxYield();
230
231 sim.MouseDblClick();
232 wxYield();
233
234 sim.MouseClick(wxMOUSE_BTN_RIGHT);
235 wxYield();
236
237 // when the first item was selected the focus changes to it, but not
238 // on subsequent clicks
239
240 // FIXME: This test fail under wxGTK & wxOSX because we get 3 FOCUSED events and
241 // 2 SELECTED ones instead of the one of each we expect for some
242 // reason, this needs to be debugged as it may indicate a bug in the
243 // generic wxListCtrl implementation.
244 #ifndef _WX_GENERIC_LISTCTRL_H_
245 CPPUNIT_ASSERT_EQUAL(1, focused.GetCount());
246 CPPUNIT_ASSERT_EQUAL(1, selected.GetCount());
247 #endif
248 CPPUNIT_ASSERT_EQUAL(1, activated.GetCount());
249 CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount());
250
251 //tidy up when we are finished
252 list->ClearAll();
253 #endif // wxUSE_UIACTIONSIMULATOR
254 }
255
256 void ListBaseTestCase::KeyDown()
257 {
258 #if wxUSE_UIACTIONSIMULATOR
259 wxListCtrl* const list = GetList();
260
261 EventCounter keydown(list, wxEVT_LIST_KEY_DOWN);
262
263 wxUIActionSimulator sim;
264
265 list->SetFocus();
266 sim.Text("aAbB");
267 wxYield();
268
269 CPPUNIT_ASSERT_EQUAL(6, keydown.GetCount());
270 #endif
271 }
272
273 void ListBaseTestCase::DeleteItems()
274 {
275 #ifndef __WXOSX__
276 wxListCtrl* const list = GetList();
277
278 EventCounter deleteitem(list, wxEVT_LIST_DELETE_ITEM);
279 EventCounter deleteall(list, wxEVT_LIST_DELETE_ALL_ITEMS);
280
281
282 list->InsertColumn(0, "Column 0", wxLIST_FORMAT_LEFT, 60);
283 list->InsertColumn(1, "Column 1", wxLIST_FORMAT_LEFT, 50);
284 list->InsertColumn(2, "Column 2", wxLIST_FORMAT_LEFT, 40);
285
286 list->InsertItem(0, "Item 0");
287 list->InsertItem(1, "Item 1");
288 list->InsertItem(2, "Item 1");
289
290 list->DeleteItem(0);
291 list->DeleteItem(0);
292 list->DeleteAllItems();
293
294 //Add some new items to tests ClearAll with
295 list->InsertColumn(0, "Column 0");
296 list->InsertItem(0, "Item 0");
297 list->InsertItem(1, "Item 1");
298
299 //Check that ClearAll actually sends a DELETE_ALL_ITEMS event
300 list->ClearAll();
301
302 //ClearAll and DeleteAllItems shouldn't send an event if there was nothing
303 //to clear
304 list->ClearAll();
305 list->DeleteAllItems();
306
307 CPPUNIT_ASSERT_EQUAL(2, deleteitem.GetCount());
308 CPPUNIT_ASSERT_EQUAL(2, deleteall.GetCount());
309 #endif
310 }
311
312 void ListBaseTestCase::InsertItem()
313 {
314 wxListCtrl* const list = GetList();
315
316 EventCounter insert(list, wxEVT_LIST_INSERT_ITEM);
317
318 list->InsertColumn(0, "Column 0", wxLIST_FORMAT_LEFT, 60);
319
320 wxListItem item;
321 item.SetId(0);
322 item.SetText("some text");
323
324 list->InsertItem(item);
325 list->InsertItem(1, "more text");
326
327 CPPUNIT_ASSERT_EQUAL(2, insert.GetCount());
328 }
329
330 void ListBaseTestCase::Find()
331 {
332 wxListCtrl* const list = GetList();
333
334 // set up for the test
335 list->InsertColumn(0, "Column 0");
336 list->InsertColumn(1, "Column 1");
337
338 list->InsertItem(0, "Item 0");
339 list->SetItem(0, 1, "first column");
340
341 list->InsertItem(1, "Item 1");
342 list->SetItem(1, 1, "first column");
343
344 list->InsertItem(2, "Item 40");
345 list->SetItem(2, 1, "first column");
346
347 list->InsertItem(3, "ITEM 01");
348 list->SetItem(3, 1, "first column");
349
350 CPPUNIT_ASSERT_EQUAL(1, list->FindItem(-1, "Item 1"));
351 CPPUNIT_ASSERT_EQUAL(2, list->FindItem(-1, "Item 4", true));
352 CPPUNIT_ASSERT_EQUAL(2, list->FindItem(1, "Item 40"));
353 CPPUNIT_ASSERT_EQUAL(3, list->FindItem(2, "Item 0", true));
354 }
355
356 void ListBaseTestCase::Visible()
357 {
358 wxListCtrl* const list = GetList();
359
360 list->InsertColumn(0, "Column 0");
361
362 int count = list->GetCountPerPage();
363
364 for( int i = 0; i < count + 10; i++ )
365 {
366 list->InsertItem(i, wxString::Format("string %d", i));
367 }
368
369 CPPUNIT_ASSERT_EQUAL(count + 10, list->GetItemCount());
370 CPPUNIT_ASSERT_EQUAL(0, list->GetTopItem());
371
372 list->EnsureVisible(count + 9);
373
374 CPPUNIT_ASSERT(list->GetTopItem() != 0);
375 }
376
377 void ListBaseTestCase::ItemFormatting()
378 {
379 wxListCtrl* const list = GetList();
380
381 list->InsertColumn(0, "Column 0");
382
383 list->InsertItem(0, "Item 0");
384 list->InsertItem(1, "Item 1");
385 list->InsertItem(2, "Item 2");
386
387 list->SetTextColour(*wxYELLOW);
388 list->SetBackgroundColour(*wxGREEN);
389 list->SetItemTextColour(0, *wxRED);
390 list->SetItemBackgroundColour(1, *wxBLUE);
391
392 CPPUNIT_ASSERT_EQUAL(*wxGREEN, list->GetBackgroundColour());
393 CPPUNIT_ASSERT_EQUAL(*wxBLUE,list->GetItemBackgroundColour(1));
394
395 CPPUNIT_ASSERT_EQUAL(*wxYELLOW, list->GetTextColour());
396 CPPUNIT_ASSERT_EQUAL(*wxRED, list->GetItemTextColour(0));
397 }
398
399 void ListBaseTestCase::EditLabel()
400 {
401 #if wxUSE_UIACTIONSIMULATOR
402 wxListCtrl* const list = GetList();
403
404 list->SetWindowStyleFlag(wxLC_REPORT | wxLC_EDIT_LABELS);
405
406 list->InsertColumn(0, "Column 0");
407
408 list->InsertItem(0, "Item 0");
409 list->InsertItem(1, "Item 1");
410
411 EventCounter beginedit(list, wxEVT_LIST_BEGIN_LABEL_EDIT);
412 EventCounter endedit(list, wxEVT_LIST_END_LABEL_EDIT);
413
414 wxUIActionSimulator sim;
415
416 list->EditLabel(0);
417
418 sim.Text("sometext");
419 sim.Char(WXK_RETURN);
420
421 wxYield();
422
423 CPPUNIT_ASSERT_EQUAL(1, beginedit.GetCount());
424 CPPUNIT_ASSERT_EQUAL(1, endedit.GetCount());
425 #endif
426 }
427
428 void ListBaseTestCase::ImageList()
429 {
430 wxListCtrl* const list = GetList();
431
432 wxSize size(32, 32);
433
434 wxImageList* imglist = new wxImageList(size.x, size.y);
435 imglist->Add(wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, size));
436 imglist->Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, size));
437 imglist->Add(wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, size));
438
439 list->AssignImageList(imglist, wxIMAGE_LIST_NORMAL);
440
441 CPPUNIT_ASSERT_EQUAL(imglist, list->GetImageList(wxIMAGE_LIST_NORMAL));
442 }
443
444 namespace
445 {
446 //From the sample but fixed so it actually inverts
447 int wxCALLBACK
448 MyCompareFunction(long item1, long item2, wxIntPtr WXUNUSED(sortData))
449 {
450 // inverse the order
451 if (item1 < item2)
452 return 1;
453 if (item1 > item2)
454 return -1;
455
456 return 0;
457 }
458
459 }
460
461 void ListBaseTestCase::Sort()
462 {
463 wxListCtrl* const list = GetList();
464
465 list->InsertColumn(0, "Column 0");
466
467 list->InsertItem(0, "Item 0");
468 list->SetItemData(0, 0);
469 list->InsertItem(1, "Item 1");
470 list->SetItemData(1, 1);
471
472 list->SortItems(MyCompareFunction, 0);
473
474 CPPUNIT_ASSERT_EQUAL("Item 1", list->GetItemText(0));
475 CPPUNIT_ASSERT_EQUAL("Item 0", list->GetItemText(1));
476 }
477
478 #endif //wxUSE_LISTCTRL