1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: samples/treelist/treelist.cpp
3 // Purpose: Sample showing wxTreeListCtrl.
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
25 #if !wxUSE_TREELISTCTRL
26 #error "wxUSE_TREELISTCTRL must be 1 for this sample."
35 #include "wx/statusbr.h"
36 #include "wx/textctrl.h"
39 #include "wx/treelist.h"
41 #include "wx/aboutdlg.h"
42 #include "wx/artprov.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 #if !defined(__WXMSW__) && !defined(__WXPM__)
49 #include "../sample.xpm"
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
63 Id_NoCheckboxes
= Id_Checkboxes_Start
,
66 Id_CheckboxesUser3State
,
84 // ----------------------------------------------------------------------------
85 // Custom comparator for tree list items comparison
86 // ----------------------------------------------------------------------------
88 // This is a toy class as in a real program you would have the original numeric
89 // data somewhere and wouldn't need to parse it back from strings presumably.
90 // Nevertheless it shows how to implement a custom comparator which is needed
91 // if you want to sort by a column with non-textual contents.
92 class MyComparator
: public wxTreeListItemComparator
96 Compare(wxTreeListCtrl
* treelist
,
101 wxString text1
= treelist
->GetItemText(item1
, column
),
102 text2
= treelist
->GetItemText(item2
, column
);
107 // Simple alphabetical comparison is fine for those.
108 return text1
.CmpNoCase(text2
);
111 // Compare strings as numbers.
112 return GetNumFilesFromText(text1
) - GetNumFilesFromText(text2
);
115 // Compare strings as numbers but also take care of "KiB" and
117 return GetSizeFromText(text1
) - GetSizeFromText(text2
);
120 wxFAIL_MSG( "Sorting on unknown column?" );
126 // Return the number of files handling special value "many". Notice that
127 // the returned value is signed to allow using it in subtraction above.
128 int GetNumFilesFromText(const wxString
& text
) const
131 if ( !text
.ToULong(&n
) )
133 if ( text
== "many" )
142 // Return the size in KiB from a string with either KiB or MiB suffix.
143 int GetSizeFromText(const wxString
& text
) const
147 if ( text
.EndsWith(" MiB", &size
) )
149 else if ( !text
.EndsWith(" KiB", &size
) )
159 // ----------------------------------------------------------------------------
161 // ----------------------------------------------------------------------------
163 class MyApp
: public wxApp
166 virtual bool OnInit();
169 // ----------------------------------------------------------------------------
171 // ----------------------------------------------------------------------------
173 class MyFrame
: public wxFrame
180 // Event handlers for the menu and wxTreeListCtrl events.
181 void OnMultiSelect(wxCommandEvent
& event
);
182 void OnFlatList(wxCommandEvent
& event
);
183 void OnCheckboxes(wxCommandEvent
& event
);
184 void OnDumpSelection(wxCommandEvent
& event
);
185 void OnCheckHTMLDocs(wxCommandEvent
& event
);
186 void OnSelectHTMLDocs(wxCommandEvent
& event
);
188 void OnAbout(wxCommandEvent
& event
);
189 void OnExit(wxCommandEvent
& event
);
191 void OnSelectionChanged(wxTreeListEvent
& event
);
192 void OnItemExpanding(wxTreeListEvent
& event
);
193 void OnItemExpanded(wxTreeListEvent
& event
);
194 void OnItemChecked(wxTreeListEvent
& event
);
195 void OnItemActivated(wxTreeListEvent
& event
);
196 void OnItemContextMenu(wxTreeListEvent
& event
);
206 // Create the image list, called once only. Should add images to it in the
207 // same order as they appear in the enum above.
208 void InitImageList();
210 // Create the control with the given styles.
211 wxTreeListCtrl
* CreateTreeListCtrl(long style
);
213 // Recreate an already existing control.
214 void RecreateTreeListCtrl(long style
);
216 // Helper: return the text of the item or "NONE" if the item is invalid.
217 wxString
DumpItem(wxTreeListItem item
) const;
219 // Another helper: just translate wxCheckBoxState to user-readable text.
220 static const char* CheckedStateString(wxCheckBoxState state
);
223 wxImageList
* m_imageList
;
225 wxTreeListCtrl
* m_treelist
;
227 MyComparator m_comparator
;
229 wxTreeListItem m_itemHTMLDocs
;
231 wxLog
* m_oldLogTarget
;
235 wxDECLARE_EVENT_TABLE();
238 // ============================================================================
240 // ============================================================================
242 // ----------------------------------------------------------------------------
244 // ----------------------------------------------------------------------------
246 wxIMPLEMENT_APP(MyApp
);
250 if ( !wxApp::OnInit() )
258 // ----------------------------------------------------------------------------
260 // ----------------------------------------------------------------------------
262 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
263 EVT_MENU(Id_MultiSelect
, MyFrame::OnMultiSelect
)
264 EVT_MENU(Id_FlatList
, MyFrame::OnFlatList
)
265 EVT_MENU_RANGE(Id_Checkboxes_Start
, Id_Checkboxes_End
,
266 MyFrame::OnCheckboxes
)
268 EVT_MENU(Id_DumpSelection
, MyFrame::OnDumpSelection
)
269 EVT_MENU_RANGE(Id_Check_HTMLDocs
, Id_Indet_HTMLDocs
,
270 MyFrame::OnCheckHTMLDocs
)
271 EVT_MENU(Id_Select_HTMLDocs
, MyFrame::OnSelectHTMLDocs
)
273 EVT_MENU(wxID_ABOUT
, MyFrame::OnAbout
)
274 EVT_MENU(wxID_EXIT
, MyFrame::OnExit
)
276 EVT_TREELIST_SELECTION_CHANGED(wxID_ANY
, MyFrame::OnSelectionChanged
)
277 EVT_TREELIST_ITEM_EXPANDING(wxID_ANY
, MyFrame::OnItemExpanding
)
278 EVT_TREELIST_ITEM_EXPANDED(wxID_ANY
, MyFrame::OnItemExpanded
)
279 EVT_TREELIST_ITEM_CHECKED(wxID_ANY
, MyFrame::OnItemChecked
)
280 EVT_TREELIST_ITEM_ACTIVATED(wxID_ANY
, MyFrame::OnItemActivated
)
281 EVT_TREELIST_ITEM_CONTEXT_MENU(wxID_ANY
, MyFrame::OnItemContextMenu
)
285 : wxFrame(NULL
, wxID_ANY
, "wxWidgets tree/list control sample",
286 wxDefaultPosition
, wxSize(600, 450))
290 // Create menus and status bar.
291 SetIcon(wxICON(sample
));
293 wxMenu
* fileMenu
= new wxMenu
;
294 fileMenu
->Append(wxID_EXIT
);
296 wxMenu
* treeStyle
= new wxMenu
;
297 treeStyle
->AppendCheckItem(Id_MultiSelect
, "&Multiple selections\tCtrl-M");
298 treeStyle
->AppendSeparator();
299 treeStyle
->AppendRadioItem(Id_NoCheckboxes
,
300 "&No checkboxes\tCtrl-1");
301 treeStyle
->AppendRadioItem(Id_Checkboxes2State
,
302 "&2-state checkboxes\tCtrl-2");
303 treeStyle
->AppendRadioItem(Id_Checkboxes3State
,
304 "&3-state checkboxes\tCtrl-3");
305 treeStyle
->AppendRadioItem(Id_CheckboxesUser3State
,
306 "&User-settable 3-state checkboxes\tCtrl-4");
307 treeStyle
->AppendSeparator();
308 treeStyle
->AppendCheckItem(Id_FlatList
, "&Flat list");
310 wxMenu
* treeOper
= new wxMenu
;
311 treeOper
->Append(Id_DumpSelection
, "&Dump selection\tCtrl-D");
312 treeOper
->AppendSeparator();
313 treeOper
->Append(Id_Check_HTMLDocs
, "&Check Doc/HTML item\tCtrl-C");
314 treeOper
->Append(Id_Uncheck_HTMLDocs
, "&Uncheck Doc/HTML item\tCtrl-U");
315 treeOper
->Append(Id_Indet_HTMLDocs
, "Make Doc/HTML &indeterminate\tCtrl-I");
316 treeOper
->Append(Id_Select_HTMLDocs
, "&Select Doc/HTML item\tCtrl-S");
318 wxMenu
* helpMenu
= new wxMenu
;
319 helpMenu
->Append(wxID_ABOUT
);
321 wxMenuBar
* menuBar
= new wxMenuBar();
322 menuBar
->Append(fileMenu
, "&File");
323 menuBar
->Append(treeStyle
, "&Style");
324 menuBar
->Append(treeOper
, "&Operations");
325 menuBar
->Append(helpMenu
, "&Help");
331 // Construct the image list with the standard images.
335 // Create and layout child controls.
336 m_treelist
= CreateTreeListCtrl(wxTL_DEFAULT_STYLE
);
338 wxTextCtrl
* textLog
= new wxTextCtrl(this, wxID_ANY
, "",
339 wxDefaultPosition
, wxDefaultSize
,
340 wxTE_READONLY
| wxTE_MULTILINE
);
341 m_oldLogTarget
= wxLog::SetActiveTarget(new wxLogTextCtrl(textLog
));
343 wxSizer
* sizer
= new wxBoxSizer(wxVERTICAL
);
344 sizer
->Add(m_treelist
, wxSizerFlags(2).Expand());
345 sizer
->Add(textLog
, wxSizerFlags(1).Expand());
349 // Finally show everything.
357 delete wxLog::SetActiveTarget(m_oldLogTarget
);
360 void MyFrame::InitImageList()
362 wxSize iconSize
= wxArtProvider::GetSizeHint(wxART_LIST
);
363 if ( iconSize
== wxDefaultSize
)
364 iconSize
= wxSize(16, 16);
366 m_imageList
= new wxImageList(iconSize
.x
, iconSize
.y
);
368 // The order should be the same as for the enum elements.
369 static const char* const icons
[] =
376 for ( unsigned n
= 0; n
< WXSIZEOF(icons
); n
++ )
380 wxArtProvider::GetIcon(icons
[n
], wxART_LIST
, iconSize
)
385 wxTreeListCtrl
* MyFrame::CreateTreeListCtrl(long style
)
387 wxTreeListCtrl
* const
388 tree
= new wxTreeListCtrl(this, wxID_ANY
,
389 wxDefaultPosition
, wxDefaultSize
,
391 tree
->SetImageList(m_imageList
);
393 tree
->AppendColumn("Component",
394 wxCOL_WIDTH_AUTOSIZE
,
396 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
397 tree
->AppendColumn("# Files",
398 tree
->WidthFor("1,000,000"),
400 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
401 tree
->AppendColumn("Size",
402 tree
->WidthFor("1,000,000 KiB"),
404 wxCOL_RESIZABLE
| wxCOL_SORTABLE
);
406 // Define a shortcut to save on typing here.
407 #define ADD_ITEM(item, parent, files, size) \
408 wxTreeListItem item = tree->AppendItem(m_isFlat ? root : parent, \
411 Icon_FolderOpened); \
412 tree->SetItemText(item, Col_Files, files); \
413 tree->SetItemText(item, Col_Size, size)
415 wxTreeListItem root
= tree
->GetRootItem();
416 ADD_ITEM(Code
, root
, "", "");
417 ADD_ITEM(wxMSW
, Code
, "313", "3.94 MiB");
418 ADD_ITEM(wxGTK
, Code
, "180", "1.66 MiB");
420 ADD_ITEM(wxOSX
, Code
, "265", "2.36 MiB");
421 ADD_ITEM(Core
, wxOSX
, "31", "347 KiB");
422 ADD_ITEM(Carbon
, wxOSX
, "91", "1.34 MiB");
423 ADD_ITEM(Cocoa
, wxOSX
, "46", "512 KiB");
425 ADD_ITEM(Documentation
, root
, "", "");
426 ADD_ITEM(HTML
, Documentation
, "many", "");
427 ADD_ITEM(CHM
, Documentation
, "1", "");
429 ADD_ITEM(Samples
, root
, "", "");
430 ADD_ITEM(minimal
, Samples
, "1", "7 KiB");
431 ADD_ITEM(widgets
, Samples
, "28", "419 KiB");
435 // Remember this one for subsequent tests.
436 m_itemHTMLDocs
= HTML
;
438 // Set a custom comparator to compare strings containing numbers correctly.
439 tree
->SetItemComparator(&m_comparator
);
444 void MyFrame::RecreateTreeListCtrl(long style
)
446 wxTreeListCtrl
* const treelist
= CreateTreeListCtrl(style
);
447 GetSizer()->Replace(m_treelist
, treelist
);
450 m_treelist
= treelist
;
455 void MyFrame::OnMultiSelect(wxCommandEvent
& event
)
457 long style
= m_treelist
->GetWindowStyle();
459 if ( event
.IsChecked() )
460 style
|= wxTL_MULTIPLE
;
462 style
&= ~wxTL_MULTIPLE
;
464 RecreateTreeListCtrl(style
);
467 void MyFrame::OnFlatList(wxCommandEvent
& event
)
469 m_isFlat
= event
.IsChecked();
471 RecreateTreeListCtrl(m_treelist
->GetWindowStyle());
474 void MyFrame::OnCheckboxes(wxCommandEvent
& event
)
476 long style
= m_treelist
->GetWindowStyle();
477 style
&= ~(wxTL_CHECKBOX
| wxTL_3STATE
| wxTL_USER_3STATE
);
479 switch ( event
.GetId() )
481 case Id_NoCheckboxes
:
484 case Id_Checkboxes2State
:
485 style
|= wxTL_CHECKBOX
;
488 case Id_Checkboxes3State
:
489 style
|= wxTL_3STATE
;
492 case Id_CheckboxesUser3State
:
493 style
|= wxTL_USER_3STATE
;
497 wxFAIL_MSG( "Unknown checkbox style" );
501 RecreateTreeListCtrl(style
);
504 void MyFrame::OnDumpSelection(wxCommandEvent
& WXUNUSED(event
))
506 if ( m_treelist
->HasFlag(wxTL_MULTIPLE
) )
508 wxTreeListItems selections
;
509 const unsigned numSelected
= m_treelist
->GetSelections(selections
);
511 switch ( numSelected
)
514 wxLogMessage("No items selected");
518 wxLogMessage("Single item selected: %s",
519 DumpItem(selections
[0]));
523 wxLogMessage("%u items selected:", numSelected
);
524 for ( unsigned n
= 0; n
< numSelected
; n
++ )
526 wxLogMessage("\t%s", DumpItem(selections
[n
]));
530 else // Single selection
532 wxLogMessage("Selection: %s", DumpItem(m_treelist
->GetSelection()));
536 void MyFrame::OnCheckHTMLDocs(wxCommandEvent
& event
)
538 wxCheckBoxState state
;
540 switch ( event
.GetId() )
542 case Id_Uncheck_HTMLDocs
:
543 state
= wxCHK_UNCHECKED
;
546 case Id_Check_HTMLDocs
:
547 state
= wxCHK_CHECKED
;
550 case Id_Indet_HTMLDocs
:
551 state
= wxCHK_UNDETERMINED
;
555 wxFAIL_MSG( "Unknown check state" );
559 m_treelist
->CheckItem(m_itemHTMLDocs
, state
);
562 void MyFrame::OnSelectHTMLDocs(wxCommandEvent
& WXUNUSED(event
))
564 m_treelist
->Select(m_itemHTMLDocs
);
567 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
569 wxAboutDialogInfo info
;
570 info
.SetDescription("wxTreeListCtrl wxWidgets sample.");
571 info
.SetCopyright("(C) 2011 Vadim Zeitlin <vadim@wxwidgets.org>");
576 void MyFrame::OnExit(wxCommandEvent
& WXUNUSED(event
))
581 wxString
MyFrame::DumpItem(wxTreeListItem item
) const
583 return item
.IsOk() ? m_treelist
->GetItemText(item
) : wxString("NONE");
587 const char* MyFrame::CheckedStateString(wxCheckBoxState state
)
591 case wxCHK_UNCHECKED
:
594 case wxCHK_UNDETERMINED
:
595 return "undetermined";
604 void MyFrame::OnSelectionChanged(wxTreeListEvent
& event
)
608 if ( m_treelist
->HasFlag(wxTL_MULTIPLE
) )
609 msg
= "Selection of the \"%s\" item changed.";
611 msg
= "Selection changed, now is \"%s\".";
613 wxLogMessage(msg
, DumpItem(event
.GetItem()));
616 void MyFrame::OnItemExpanding(wxTreeListEvent
& event
)
618 wxLogMessage("Item \"%s\" is expanding", DumpItem(event
.GetItem()));
621 void MyFrame::OnItemExpanded(wxTreeListEvent
& event
)
623 wxLogMessage("Item \"%s\" expanded", DumpItem(event
.GetItem()));
626 void MyFrame::OnItemChecked(wxTreeListEvent
& event
)
628 wxTreeListItem item
= event
.GetItem();
630 wxLogMessage("Item \"%s\" toggled, now %s (was %s)",
632 CheckedStateString(m_treelist
->GetCheckedState(item
)),
633 CheckedStateString(event
.GetOldCheckedState()));
636 void MyFrame::OnItemActivated(wxTreeListEvent
& event
)
638 wxLogMessage("Item \"%s\" activated", DumpItem(event
.GetItem()));
641 void MyFrame::OnItemContextMenu(wxTreeListEvent
& event
)
648 Id_Check_Recursively
,
653 menu
.Append(Id_Check_Item
, "&Check item");
654 menu
.Append(Id_Uncheck_Item
, "&Uncheck item");
655 if ( m_treelist
->HasFlag(wxTL_3STATE
) )
656 menu
.Append(Id_Indet_Item
, "Make item &indeterminate");
657 menu
.AppendSeparator();
658 menu
.Append(Id_Check_Recursively
, "Check &recursively");
659 menu
.Append(Id_Update_Parent
, "Update &parent");
661 const wxTreeListItem item
= event
.GetItem();
662 switch ( m_treelist
->GetPopupMenuSelectionFromUser(menu
) )
665 m_treelist
->CheckItem(item
);
668 case Id_Uncheck_Item
:
669 m_treelist
->UncheckItem(item
);
673 m_treelist
->CheckItem(item
, wxCHK_UNDETERMINED
);
676 case Id_Check_Recursively
:
677 m_treelist
->CheckItemRecursively(item
);
680 case Id_Update_Parent
:
681 m_treelist
->UpdateItemParentStateRecursively(item
);
685 wxFAIL_MSG( "Unexpected menu selection" );