1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: samples/treelist/treelist.cpp
3 // Purpose: Sample showing wxTreeListCtrl.
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 #include "wx/wxprec.h"
24 #if !wxUSE_TREELISTCTRL
25 #error "wxUSE_TREELISTCTRL must be 1 for this sample."
34 #include "wx/statusbr.h"
35 #include "wx/textctrl.h"
38 #include "wx/treelist.h"
40 #include "wx/aboutdlg.h"
41 #include "wx/artprov.h"
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 #ifndef wxHAS_IMAGES_IN_RESOURCES
48 #include "../sample.xpm"
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
62 Id_NoCheckboxes
= Id_Checkboxes_Start
,
65 Id_CheckboxesUser3State
,
83 // ----------------------------------------------------------------------------
84 // Custom comparator for tree list items comparison
85 // ----------------------------------------------------------------------------
87 // This is a toy class as in a real program you would have the original numeric
88 // data somewhere and wouldn't need to parse it back from strings presumably.
89 // Nevertheless it shows how to implement a custom comparator which is needed
90 // if you want to sort by a column with non-textual contents.
91 class MyComparator
: public wxTreeListItemComparator
95 Compare(wxTreeListCtrl
* treelist
,
100 wxString text1
= treelist
->GetItemText(item1
, column
),
101 text2
= treelist
->GetItemText(item2
, column
);
106 // Simple alphabetical comparison is fine for those.
107 return text1
.CmpNoCase(text2
);
110 // Compare strings as numbers.
111 return GetNumFilesFromText(text1
) - GetNumFilesFromText(text2
);
114 // Compare strings as numbers but also take care of "KiB" and
116 return GetSizeFromText(text1
) - GetSizeFromText(text2
);
119 wxFAIL_MSG( "Sorting on unknown column?" );
125 // Return the number of files handling special value "many". Notice that
126 // the returned value is signed to allow using it in subtraction above.
127 int GetNumFilesFromText(const wxString
& text
) const
130 if ( !text
.ToULong(&n
) )
132 if ( text
== "many" )
141 // Return the size in KiB from a string with either KiB or MiB suffix.
142 int GetSizeFromText(const wxString
& text
) const
146 if ( text
.EndsWith(" MiB", &size
) )
148 else if ( !text
.EndsWith(" KiB", &size
) )
158 // ----------------------------------------------------------------------------
160 // ----------------------------------------------------------------------------
162 class MyApp
: public wxApp
165 virtual bool OnInit();
168 // ----------------------------------------------------------------------------
170 // ----------------------------------------------------------------------------
172 class MyFrame
: public wxFrame
179 // Event handlers for the menu and wxTreeListCtrl events.
180 void OnMultiSelect(wxCommandEvent
& event
);
181 void OnFlatList(wxCommandEvent
& event
);
182 void OnCheckboxes(wxCommandEvent
& event
);
183 void OnDumpSelection(wxCommandEvent
& event
);
184 void OnCheckHTMLDocs(wxCommandEvent
& event
);
185 void OnSelectHTMLDocs(wxCommandEvent
& event
);
187 void OnAbout(wxCommandEvent
& event
);
188 void OnExit(wxCommandEvent
& event
);
190 void OnSelectionChanged(wxTreeListEvent
& event
);
191 void OnItemExpanding(wxTreeListEvent
& event
);
192 void OnItemExpanded(wxTreeListEvent
& event
);
193 void OnItemChecked(wxTreeListEvent
& event
);
194 void OnItemActivated(wxTreeListEvent
& event
);
195 void OnItemContextMenu(wxTreeListEvent
& event
);
205 // Create the image list, called once only. Should add images to it in the
206 // same order as they appear in the enum above.
207 void InitImageList();
209 // Create the control with the given styles.
210 wxTreeListCtrl
* CreateTreeListCtrl(long style
);
212 // Recreate an already existing control.
213 void RecreateTreeListCtrl(long style
);
215 // Helper: return the text of the item or "NONE" if the item is invalid.
216 wxString
DumpItem(wxTreeListItem item
) const;
218 // Another helper: just translate wxCheckBoxState to user-readable text.
219 static const char* CheckedStateString(wxCheckBoxState state
);
222 wxImageList
* m_imageList
;
224 wxTreeListCtrl
* m_treelist
;
226 MyComparator m_comparator
;
228 wxTreeListItem m_itemHTMLDocs
;
230 wxLog
* m_oldLogTarget
;
234 wxDECLARE_EVENT_TABLE();
237 // ============================================================================
239 // ============================================================================
241 // ----------------------------------------------------------------------------
243 // ----------------------------------------------------------------------------
245 wxIMPLEMENT_APP(MyApp
);
249 if ( !wxApp::OnInit() )
257 // ----------------------------------------------------------------------------
259 // ----------------------------------------------------------------------------
261 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
262 EVT_MENU(Id_MultiSelect
, MyFrame::OnMultiSelect
)
263 EVT_MENU(Id_FlatList
, MyFrame::OnFlatList
)
264 EVT_MENU_RANGE(Id_Checkboxes_Start
, Id_Checkboxes_End
,
265 MyFrame::OnCheckboxes
)
267 EVT_MENU(Id_DumpSelection
, MyFrame::OnDumpSelection
)
268 EVT_MENU_RANGE(Id_Check_HTMLDocs
, Id_Indet_HTMLDocs
,
269 MyFrame::OnCheckHTMLDocs
)
270 EVT_MENU(Id_Select_HTMLDocs
, MyFrame::OnSelectHTMLDocs
)
272 EVT_MENU(wxID_ABOUT
, MyFrame::OnAbout
)
273 EVT_MENU(wxID_EXIT
, MyFrame::OnExit
)
275 EVT_TREELIST_SELECTION_CHANGED(wxID_ANY
, MyFrame::OnSelectionChanged
)
276 EVT_TREELIST_ITEM_EXPANDING(wxID_ANY
, MyFrame::OnItemExpanding
)
277 EVT_TREELIST_ITEM_EXPANDED(wxID_ANY
, MyFrame::OnItemExpanded
)
278 EVT_TREELIST_ITEM_CHECKED(wxID_ANY
, MyFrame::OnItemChecked
)
279 EVT_TREELIST_ITEM_ACTIVATED(wxID_ANY
, MyFrame::OnItemActivated
)
280 EVT_TREELIST_ITEM_CONTEXT_MENU(wxID_ANY
, MyFrame::OnItemContextMenu
)
284 : wxFrame(NULL
, wxID_ANY
, "wxWidgets tree/list control sample",
285 wxDefaultPosition
, wxSize(600, 450))
289 // Create menus and status bar.
290 SetIcon(wxICON(sample
));
292 wxMenu
* fileMenu
= new wxMenu
;
293 fileMenu
->Append(wxID_EXIT
);
295 wxMenu
* treeStyle
= new wxMenu
;
296 treeStyle
->AppendCheckItem(Id_MultiSelect
, "&Multiple selections\tCtrl-M");
297 treeStyle
->AppendSeparator();
298 treeStyle
->AppendRadioItem(Id_NoCheckboxes
,
299 "&No checkboxes\tCtrl-1");
300 treeStyle
->AppendRadioItem(Id_Checkboxes2State
,
301 "&2-state checkboxes\tCtrl-2");
302 treeStyle
->AppendRadioItem(Id_Checkboxes3State
,
303 "&3-state checkboxes\tCtrl-3");
304 treeStyle
->AppendRadioItem(Id_CheckboxesUser3State
,
305 "&User-settable 3-state checkboxes\tCtrl-4");
306 treeStyle
->AppendSeparator();
307 treeStyle
->AppendCheckItem(Id_FlatList
, "&Flat list");
309 wxMenu
* treeOper
= new wxMenu
;
310 treeOper
->Append(Id_DumpSelection
, "&Dump selection\tCtrl-D");
311 treeOper
->AppendSeparator();
312 treeOper
->Append(Id_Check_HTMLDocs
, "&Check Doc/HTML item\tCtrl-C");
313 treeOper
->Append(Id_Uncheck_HTMLDocs
, "&Uncheck Doc/HTML item\tCtrl-U");
314 treeOper
->Append(Id_Indet_HTMLDocs
, "Make Doc/HTML &indeterminate\tCtrl-I");
315 treeOper
->Append(Id_Select_HTMLDocs
, "&Select Doc/HTML item\tCtrl-S");
317 wxMenu
* helpMenu
= new wxMenu
;
318 helpMenu
->Append(wxID_ABOUT
);
320 wxMenuBar
* menuBar
= new wxMenuBar();
321 menuBar
->Append(fileMenu
, "&File");
322 menuBar
->Append(treeStyle
, "&Style");
323 menuBar
->Append(treeOper
, "&Operations");
324 menuBar
->Append(helpMenu
, "&Help");
330 // Construct the image list with the standard images.
334 // Create and layout child controls.
335 m_treelist
= CreateTreeListCtrl(wxTL_DEFAULT_STYLE
);
337 wxTextCtrl
* textLog
= new wxTextCtrl(this, wxID_ANY
, "",
338 wxDefaultPosition
, wxDefaultSize
,
339 wxTE_READONLY
| wxTE_MULTILINE
);
340 m_oldLogTarget
= wxLog::SetActiveTarget(new wxLogTextCtrl(textLog
));
342 wxSizer
* sizer
= new wxBoxSizer(wxVERTICAL
);
343 sizer
->Add(m_treelist
, wxSizerFlags(2).Expand());
344 sizer
->Add(textLog
, wxSizerFlags(1).Expand());
348 // Finally show everything.
356 delete wxLog::SetActiveTarget(m_oldLogTarget
);
359 void MyFrame::InitImageList()
361 wxSize iconSize
= wxArtProvider::GetSizeHint(wxART_LIST
);
362 if ( iconSize
== wxDefaultSize
)
363 iconSize
= wxSize(16, 16);
365 m_imageList
= new wxImageList(iconSize
.x
, iconSize
.y
);
367 // The order should be the same as for the enum elements.
368 static const char* const icons
[] =
375 for ( unsigned n
= 0; n
< WXSIZEOF(icons
); n
++ )
379 wxArtProvider::GetIcon(icons
[n
], wxART_LIST
, iconSize
)
384 wxTreeListCtrl
* MyFrame::CreateTreeListCtrl(long style
)
386 wxTreeListCtrl
* const
387 tree
= new wxTreeListCtrl(this, wxID_ANY
,
388 wxDefaultPosition
, wxDefaultSize
,
390 tree
->SetImageList(m_imageList
);
392 tree
->AppendColumn("Component",
393 wxCOL_WIDTH_AUTOSIZE
,
395 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
396 tree
->AppendColumn("# Files",
397 tree
->WidthFor("1,000,000"),
399 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
400 tree
->AppendColumn("Size",
401 tree
->WidthFor("1,000,000 KiB"),
403 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
405 // Define a shortcut to save on typing here.
406 #define ADD_ITEM(item, parent, files, size) \
407 wxTreeListItem item = tree->AppendItem(m_isFlat ? root : parent, \
410 Icon_FolderOpened); \
411 tree->SetItemText(item, Col_Files, files); \
412 tree->SetItemText(item, Col_Size, size)
414 wxTreeListItem root
= tree
->GetRootItem();
415 ADD_ITEM(Code
, root
, "", "");
416 ADD_ITEM(wxMSW
, Code
, "313", "3.94 MiB");
417 ADD_ITEM(wxGTK
, Code
, "180", "1.66 MiB");
419 ADD_ITEM(wxOSX
, Code
, "265", "2.36 MiB");
420 ADD_ITEM(Core
, wxOSX
, "31", "347 KiB");
421 ADD_ITEM(Carbon
, wxOSX
, "91", "1.34 MiB");
422 ADD_ITEM(Cocoa
, wxOSX
, "46", "512 KiB");
424 ADD_ITEM(Documentation
, root
, "", "");
425 ADD_ITEM(HTML
, Documentation
, "many", "");
426 ADD_ITEM(CHM
, Documentation
, "1", "");
428 ADD_ITEM(Samples
, root
, "", "");
429 ADD_ITEM(minimal
, Samples
, "1", "7 KiB");
430 ADD_ITEM(widgets
, Samples
, "28", "419 KiB");
434 // Remember this one for subsequent tests.
435 m_itemHTMLDocs
= HTML
;
437 // Set a custom comparator to compare strings containing numbers correctly.
438 tree
->SetItemComparator(&m_comparator
);
443 void MyFrame::RecreateTreeListCtrl(long style
)
445 wxTreeListCtrl
* const treelist
= CreateTreeListCtrl(style
);
446 GetSizer()->Replace(m_treelist
, treelist
);
449 m_treelist
= treelist
;
454 void MyFrame::OnMultiSelect(wxCommandEvent
& event
)
456 long style
= m_treelist
->GetWindowStyle();
458 if ( event
.IsChecked() )
459 style
|= wxTL_MULTIPLE
;
461 style
&= ~wxTL_MULTIPLE
;
463 RecreateTreeListCtrl(style
);
466 void MyFrame::OnFlatList(wxCommandEvent
& event
)
468 m_isFlat
= event
.IsChecked();
470 RecreateTreeListCtrl(m_treelist
->GetWindowStyle());
473 void MyFrame::OnCheckboxes(wxCommandEvent
& event
)
475 long style
= m_treelist
->GetWindowStyle();
476 style
&= ~(wxTL_CHECKBOX
| wxTL_3STATE
| wxTL_USER_3STATE
);
478 switch ( event
.GetId() )
480 case Id_NoCheckboxes
:
483 case Id_Checkboxes2State
:
484 style
|= wxTL_CHECKBOX
;
487 case Id_Checkboxes3State
:
488 style
|= wxTL_3STATE
;
491 case Id_CheckboxesUser3State
:
492 style
|= wxTL_USER_3STATE
;
496 wxFAIL_MSG( "Unknown checkbox style" );
500 RecreateTreeListCtrl(style
);
503 void MyFrame::OnDumpSelection(wxCommandEvent
& WXUNUSED(event
))
505 if ( m_treelist
->HasFlag(wxTL_MULTIPLE
) )
507 wxTreeListItems selections
;
508 const unsigned numSelected
= m_treelist
->GetSelections(selections
);
510 switch ( numSelected
)
513 wxLogMessage("No items selected");
517 wxLogMessage("Single item selected: %s",
518 DumpItem(selections
[0]));
522 wxLogMessage("%u items selected:", numSelected
);
523 for ( unsigned n
= 0; n
< numSelected
; n
++ )
525 wxLogMessage("\t%s", DumpItem(selections
[n
]));
529 else // Single selection
531 wxLogMessage("Selection: %s", DumpItem(m_treelist
->GetSelection()));
535 void MyFrame::OnCheckHTMLDocs(wxCommandEvent
& event
)
537 wxCheckBoxState state
;
539 switch ( event
.GetId() )
541 case Id_Uncheck_HTMLDocs
:
542 state
= wxCHK_UNCHECKED
;
545 case Id_Check_HTMLDocs
:
546 state
= wxCHK_CHECKED
;
549 case Id_Indet_HTMLDocs
:
550 state
= wxCHK_UNDETERMINED
;
554 wxFAIL_MSG( "Unknown check state" );
558 m_treelist
->CheckItem(m_itemHTMLDocs
, state
);
561 void MyFrame::OnSelectHTMLDocs(wxCommandEvent
& WXUNUSED(event
))
563 m_treelist
->Select(m_itemHTMLDocs
);
566 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
568 wxAboutDialogInfo info
;
569 info
.SetDescription("wxTreeListCtrl wxWidgets sample.");
570 info
.SetCopyright("(C) 2011 Vadim Zeitlin <vadim@wxwidgets.org>");
575 void MyFrame::OnExit(wxCommandEvent
& WXUNUSED(event
))
580 wxString
MyFrame::DumpItem(wxTreeListItem item
) const
582 return item
.IsOk() ? m_treelist
->GetItemText(item
) : wxString("NONE");
586 const char* MyFrame::CheckedStateString(wxCheckBoxState state
)
590 case wxCHK_UNCHECKED
:
593 case wxCHK_UNDETERMINED
:
594 return "undetermined";
603 void MyFrame::OnSelectionChanged(wxTreeListEvent
& event
)
607 if ( m_treelist
->HasFlag(wxTL_MULTIPLE
) )
608 msg
= "Selection of the \"%s\" item changed.";
610 msg
= "Selection changed, now is \"%s\".";
612 wxLogMessage(msg
, DumpItem(event
.GetItem()));
615 void MyFrame::OnItemExpanding(wxTreeListEvent
& event
)
617 wxLogMessage("Item \"%s\" is expanding", DumpItem(event
.GetItem()));
620 void MyFrame::OnItemExpanded(wxTreeListEvent
& event
)
622 wxLogMessage("Item \"%s\" expanded", DumpItem(event
.GetItem()));
625 void MyFrame::OnItemChecked(wxTreeListEvent
& event
)
627 wxTreeListItem item
= event
.GetItem();
629 wxLogMessage("Item \"%s\" toggled, now %s (was %s)",
631 CheckedStateString(m_treelist
->GetCheckedState(item
)),
632 CheckedStateString(event
.GetOldCheckedState()));
635 void MyFrame::OnItemActivated(wxTreeListEvent
& event
)
637 wxLogMessage("Item \"%s\" activated", DumpItem(event
.GetItem()));
640 void MyFrame::OnItemContextMenu(wxTreeListEvent
& event
)
647 Id_Check_Recursively
,
652 menu
.Append(Id_Check_Item
, "&Check item");
653 menu
.Append(Id_Uncheck_Item
, "&Uncheck item");
654 if ( m_treelist
->HasFlag(wxTL_3STATE
) )
655 menu
.Append(Id_Indet_Item
, "Make item &indeterminate");
656 menu
.AppendSeparator();
657 menu
.Append(Id_Check_Recursively
, "Check &recursively");
658 menu
.Append(Id_Update_Parent
, "Update &parent");
660 const wxTreeListItem item
= event
.GetItem();
661 switch ( m_treelist
->GetPopupMenuSelectionFromUser(menu
) )
664 m_treelist
->CheckItem(item
);
667 case Id_Uncheck_Item
:
668 m_treelist
->UncheckItem(item
);
672 m_treelist
->CheckItem(item
, wxCHK_UNDETERMINED
);
675 case Id_Check_Recursively
:
676 m_treelist
->CheckItemRecursively(item
);
679 case Id_Update_Parent
:
680 m_treelist
->UpdateItemParentStateRecursively(item
);
684 wxFAIL_MSG( "Unexpected menu selection" );