]> git.saurik.com Git - wxWidgets.git/commitdiff
Implement sorting in wxTreeListCtrl.
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 21 Sep 2011 15:07:53 +0000 (15:07 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 21 Sep 2011 15:07:53 +0000 (15:07 +0000)
Allow the user to sort the control contents by clicking on the columns with
wxCOL_SORTABLE flag and also provide SetSortColumn() method to sort the
control programmatically.

Also add wxTreeListItemComparator class and SetItemComparator() method to
allow customizing the way the items are compared.

Update the sample to show how to define a custom comparator.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69176 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/treelist.h
interface/wx/treelist.h
samples/treelist/treelist.cpp
src/generic/treelist.cpp

index 9b315c57de8956fe2296dc99ef9b6b8bbf71d915..1b33b5abccf4f07020700491f4fec279fea7d1fc 100644 (file)
@@ -28,6 +28,7 @@ class WXDLLIMPEXP_FWD_ADV wxDataViewEvent;
 
 extern WXDLLIMPEXP_DATA_CORE(const char) wxTreeListCtrlNameStr[];
 
+class wxTreeListCtrl;
 class wxTreeListModel;
 class wxTreeListModelNode;
 
@@ -77,6 +78,33 @@ typedef wxVector<wxTreeListItem> wxTreeListItems;
 extern WXDLLIMPEXP_DATA_ADV(const wxTreeListItem) wxTLI_FIRST;
 extern WXDLLIMPEXP_DATA_ADV(const wxTreeListItem) wxTLI_LAST;
 
+// ----------------------------------------------------------------------------
+// wxTreeListItemComparator: defines order of wxTreeListCtrl items.
+// ----------------------------------------------------------------------------
+
+class wxTreeListItemComparator
+{
+public:
+    wxTreeListItemComparator() { }
+
+    // The comparison function should return negative, null or positive value
+    // depending on whether the first item is less than, equal to or greater
+    // than the second one. The items should be compared using their values for
+    // the given column.
+    virtual int
+    Compare(wxTreeListCtrl* treelist,
+            unsigned column,
+            wxTreeListItem first,
+            wxTreeListItem second) = 0;
+
+    // Although this class is not used polymorphically by wxWidgets itself,
+    // provide virtual dtor in case it's used like this in the user code.
+    virtual ~wxTreeListItemComparator() { }
+
+private:
+    wxDECLARE_NO_COPY_CLASS(wxTreeListItemComparator);
+};
+
 // ----------------------------------------------------------------------------
 // wxTreeListCtrl: a control combining wxTree- and wxListCtrl features.
 // ----------------------------------------------------------------------------
@@ -323,6 +351,34 @@ public:
 
 
 
+    // Sorting.
+    // --------
+
+    // Sort by the given column, either in ascending (default) or descending
+    // sort order.
+    //
+    // By default, simple alphabetical sorting is done by this column contents
+    // but SetItemComparator() may be called to perform comparison in some
+    // other way.
+    void SetSortColumn(unsigned col, bool ascendingOrder = true);
+
+    // If the control contents is sorted, return true and fill the output
+    // parameters with the column which is currently used for sorting and
+    // whether we sort using ascending or descending order. Otherwise, i.e. if
+    // the control contents is unsorted, simply return false.
+    bool GetSortColumn(unsigned* col, bool* ascendingOrder = NULL);
+
+    // Set the object to use for comparing the items. It will be called when
+    // the control is being sorted because the user clicked on a sortable
+    // column.
+    //
+    // The provided pointer is stored by the control so the object it points to
+    // must have a life-time equal or greater to that of the control itself. In
+    // addition, the pointer can be NULL to stop using custom comparator and
+    // revert to the default alphabetical comparison.
+    void SetItemComparator(wxTreeListItemComparator* comparator);
+
+
     // View window functions.
     // ----------------------
 
@@ -356,10 +412,14 @@ private:
                                 int imageOpened,
                                 wxClientData* data);
 
-    // Send wxTreeListEvent corresponding to the given wxDataViewEvent.
+    // Send wxTreeListEvent corresponding to the given wxDataViewEvent for an
+    // item (as opposed for column-oriented events).
     //
     // Also updates the original event "skipped" and "vetoed" flags.
-    void SendEvent(wxEventType evt, wxDataViewEvent& event);
+    void SendItemEvent(wxEventType evt, wxDataViewEvent& event);
+
+    // Send wxTreeListEvent corresponding to the given column wxDataViewEvent.
+    void SendColumnEvent(wxEventType evt, wxDataViewEvent& event);
 
 
     // Called by wxTreeListModel when an item is toggled by the user.
@@ -371,6 +431,7 @@ private:
     void OnItemExpanded(wxDataViewEvent& event);
     void OnItemActivated(wxDataViewEvent& event);
     void OnItemContextMenu(wxDataViewEvent& event);
+    void OnColumnSorted(wxDataViewEvent& event);
     void OnSize(wxSizeEvent& event);
 
     wxDECLARE_EVENT_TABLE();
@@ -379,6 +440,8 @@ private:
     wxDataViewCtrl* m_view;
     wxTreeListModel* m_model;
 
+    wxTreeListItemComparator* m_comparator;
+
 
     // It calls our inherited protected wxWithImages::GetImage() method.
     friend class wxTreeListModel;
@@ -393,12 +456,16 @@ private:
 class wxTreeListEvent : public wxNotifyEvent
 {
 public:
-    // The item affected by the event.
+    // The item affected by the event. Valid for all events except
+    // column-specific ones such as COLUMN_SORTED.
     wxTreeListItem GetItem() const { return m_item; }
 
     // The previous state of the item checkbox for ITEM_CHECKED events only.
     wxCheckBoxState GetOldCheckedState() const { return m_oldCheckedState; }
 
+    // The index of the column affected by the event. Currently only used by
+    // COLUMN_SORTED event.
+    unsigned GetColumn() const { return m_column; }
 
     virtual wxEvent* Clone() const { return new wxTreeListEvent(*this); }
 
@@ -411,6 +478,10 @@ private:
           m_item(item)
     {
         SetEventObject(treelist);
+
+        m_column = static_cast<unsigned>(-1);
+
+        m_oldCheckedState = wxCHK_UNDETERMINED;
     }
 
     // Set the checkbox state before this event for ITEM_CHECKED events.
@@ -419,11 +490,19 @@ private:
         m_oldCheckedState = state;
     }
 
+    // Set the column affected by this event for COLUMN_SORTED events.
+    void SetColumn(unsigned column)
+    {
+        m_column = column;
+    }
+
 
     const wxTreeListItem m_item;
 
     wxCheckBoxState m_oldCheckedState;
 
+    unsigned m_column;
+
     friend class wxTreeListCtrl;
 
     wxDECLARE_ABSTRACT_CLASS(wxTreeListEvent);
@@ -468,6 +547,10 @@ wxDECLARE_TREELIST_EVENT(ITEM_CONTEXT_MENU);
 #define EVT_TREELIST_ITEM_CONTEXT_MENU(id, fn) \
     wxEVT_TREELIST_GENERIC(ITEM_CONTEXT_MENU, id, fn)
 
+wxDECLARE_TREELIST_EVENT(COLUMN_SORTED);
+#define EVT_TREELIST_COLUMN_SORTED(id, fn) \
+    wxEVT_TREELIST_GENERIC(COLUMN_SORTED, id, fn)
+
 #undef wxDECLARE_TREELIST_EVENT
 
 #endif // wxUSE_TREELISTCTRL
index 5a70301d0ae429fc6139c751b82b50e47a4f0e9a..dc8f4cc675b9b26b75ead497f7da19eb4cce497d 100644 (file)
@@ -38,6 +38,64 @@ public:
     bool IsOk() const;
 };
 
+/**
+    Class defining sort order for the items in wxTreeListCtrl.
+
+    @see wxTreeListCtrl
+
+    @library{wxadv}
+    @category{ctrl}
+
+    @since 2.9.3
+ */
+class wxTreeListItemComparator
+{
+public:
+    /**
+        Default constructor.
+
+        Notice that this class is not copyable, comparators are not passed by
+        value.
+     */
+    wxTreeListItemComparator();
+
+    /**
+        Pure virtual function which must be overridden to define sort order.
+
+        The comparison function should return negative, null or positive value
+        depending on whether the first item is less than, equal to or greater
+        than the second one. The items should be compared using their values
+        for the given column.
+
+        @param treelist
+            The control whose contents is being sorted.
+        @param column
+            The column of this control used for sorting.
+        @param first
+            First item to compare.
+        @param second
+            Second item to compare.
+        @return
+            A negative value if the first item is less than (i.e. should appear
+            above) the second one, zero if the two items are equal or a
+            positive value if the first item is greater than (i.e. should
+            appear below) the second one.
+     */
+    virtual int
+    Compare(wxTreeListCtrl* treelist,
+            unsigned column,
+            wxTreeListItem first,
+            wxTreeListItem second) = 0;
+
+    /**
+        Trivial but virtual destructor.
+
+        Although this class is not used polymorphically by wxWidgets itself,
+        provide virtual dtor in case it's used like this in the user code.
+     */
+    virtual ~wxTreeListItemComparator();
+};
+
 /**
     Container of multiple items.
  */
@@ -81,6 +139,19 @@ extern const wxTreeListItem wxTLI_LAST;
     the other columns.
 
 
+    Unlike wxTreeCtrl or wxListCtrl this control can sort its items on its own.
+    To allow user to sort the control contents by clicking on some column you
+    should use wxCOL_SORTABLE flag when adding that column to the control. When
+    a column with this flag is clicked, the control resorts itself using the
+    values in this column. By default the sort is done using alphabetical order
+    comparison of the items text, which is not always correct (e.g. this
+    doesn't work for the numeric columns). To change this you may use
+    SetItemComparator() method to provide a custom comparator, i.e. simply an
+    object that implements comparison between the two items. The treelist
+    sample shows an example of doing this. And if you need to sort the control
+    programmatically, you can call SetSortColumn() method.
+
+
     Here are the styles supported by this control. Notice that using
     wxTL_USER_3STATE implies wxTL_3STATE and wxTL_3STATE in turn implies
     wxTL_CHECKBOX.
@@ -132,6 +203,11 @@ extern const wxTreeListItem wxTLI_LAST;
     @event{EVT_TREELIST_ITEM_CONTEXT_MENU(id, func)}
         Process @c wxEVT_COMMAND_TREELIST_ITEM_CONTEXT_MENU event indicating
         that the popup menu for the given item should be displayed.
+    @event{EVT_TREELIST_COLUMN_SORTED(id, func)}
+        Process @c wxEVT_COMMAND_TREELIST_COLUMN_SORTED event indicating that
+        the control contents has just been resorted using the specified column.
+        The event doesn't carry the sort direction, use GetSortColumn() method
+        if you need to know it.
     @endEventTable
 
     @library{wxadv}
@@ -247,8 +323,9 @@ public:
         @param align
             Alignment of both the column header and its items.
         @param flags
-            Column flags, currently can only include wxCOL_RESIZABLE to allow
-            the user to resize the column.
+            Column flags, currently can include wxCOL_RESIZABLE to allow the
+            user to resize the column and wxCOL_SORTABLE to allow the user to
+            resort the control contents by clicking on this column.
         @return
             Index of the new column or -1 on failure.
      */
@@ -665,6 +742,71 @@ public:
 
     //@}
 
+    /**
+        Sorting.
+
+        If some control columns were added with wxCOL_SORTABLE flag, clicking
+        on them will automatically resort the control using the custom
+        comparator set by SetItemComparator() or by doing alphabetical
+        comparison by default.
+
+        In any case, i.e. even if the user can't sort the control by clicking
+        on its header, you may call SetSortColumn() to sort it programmatically
+        and call GetSortColumn() to determine whether it's sorted now and, if
+        so, by which column and in which order.
+     */
+    //@{
+
+    /**
+        Set the column to use for sorting and the order in which to sort.
+
+        Calling this method resorts the control contents using the values of
+        the items in the specified column. Sorting uses custom comparator set
+        with SetItemComparator() or alphabetical comparison of items texts if
+        none was specified.
+
+        Notice that currently there is no way to reset sort order.
+
+        @param col
+            A valid column index.
+        @param ascendingOrder
+            Indicates whether the items should be sorted in ascending (A to Z)
+            or descending (Z to A) order.
+     */
+    void SetSortColumn(unsigned col, bool ascendingOrder = true);
+
+    /**
+        Return the column currently used for sorting, if any.
+
+        If the control is currently unsorted, the function simply returns
+        @false and doesn't modify any of its output parameters.
+
+        @param col
+            Receives the index of the column used for sorting if non-@NULL.
+        @param ascendingOrder
+            Receives @true or @false depending on whether the items are sorted
+            in ascending or descending order.
+        @return
+            @true if the control is sorted or @false if it isn't sorted at all.
+     */
+    bool GetSortColumn(unsigned* col, bool* ascendingOrder = NULL);
+
+    /**
+        Set the object to use for comparing the items.
+
+        This object will be used when the control is being sorted because the
+        user clicked on a sortable column or SetSortColumn() was called.
+
+        The provided pointer is stored by the control so the object it points
+        to must have a life-time equal or greater to that of the control
+        itself. In addition, the pointer can be @NULL to stop using custom
+        comparator and revert to the default alphabetical comparison.
+     */
+    void SetItemComparator(wxTreeListItemComparator* comparator);
+
+    //@}
+
+
     /**
         View window.
 
@@ -722,6 +864,14 @@ public:
         wxTreeListCtrl::GetCheckedState().
      */
     wxCheckBoxState GetOldCheckedState() const;
+
+    /**
+        Return the column affected by the event.
+
+        This is currently only used with @c wxEVT_COMMAND_TREELIST_COLUMN_SORTED
+        event.
+     */
+    unsigned GetColumn() const;
 };
 
 
index 13894529afed999003fcfaf152a2b8c6ea3f05fa..d7b5dc9527766babe94751a9b28a0a9902d5e355 100644 (file)
 #endif
 
 // ----------------------------------------------------------------------------
-// Constants for menu items
+// Constants
 // ----------------------------------------------------------------------------
 
+// Menu items.
 enum
 {
     Id_MultiSelect = 100,
@@ -72,6 +73,89 @@ enum
     Id_Select_HTMLDocs
 };
 
+// Tree list columns.
+enum
+{
+    Col_Component,
+    Col_Files,
+    Col_Size
+};
+
+// ----------------------------------------------------------------------------
+// Custom comparator for tree list items comparison
+// ----------------------------------------------------------------------------
+
+// This is a toy class as in a real program you would have the original numeric
+// data somewhere and wouldn't need to parse it back from strings presumably.
+// Nevertheless it shows how to implement a custom comparator which is needed
+// if you want to sort by a column with non-textual contents.
+class MyComparator : public wxTreeListItemComparator
+{
+public:
+    virtual int
+    Compare(wxTreeListCtrl* treelist,
+            unsigned column,
+            wxTreeListItem item1,
+            wxTreeListItem item2)
+    {
+        wxString text1 = treelist->GetItemText(item1, column),
+                 text2 = treelist->GetItemText(item2, column);
+
+        switch ( column )
+        {
+            case Col_Component:
+                // Simple alphabetical comparison is fine for those.
+                return text1.CmpNoCase(text2);
+
+            case Col_Files:
+                // Compare strings as numbers.
+                return GetNumFilesFromText(text1) - GetNumFilesFromText(text2);
+
+            case Col_Size:
+                // Compare strings as numbers but also take care of "KiB" and
+                // "MiB" suffixes.
+                return GetSizeFromText(text1) - GetSizeFromText(text2);
+        }
+
+        wxFAIL_MSG( "Sorting on unknown column?" );
+
+        return 0;
+    }
+
+private:
+    // Return the number of files handling special value "many". Notice that
+    // the returned value is signed to allow using it in subtraction above.
+    int GetNumFilesFromText(const wxString& text) const
+    {
+        unsigned long n;
+        if ( !text.ToULong(&n) )
+        {
+            if ( text == "many" )
+                n = 9999;
+            else
+                n = 0;
+        }
+
+        return n;
+    }
+
+    // Return the size in KiB from a string with either KiB or MiB suffix.
+    int GetSizeFromText(const wxString& text) const
+    {
+        wxString size;
+        unsigned factor = 1;
+        if ( text.EndsWith(" MiB", &size) )
+            factor = 1024;
+        else if ( !text.EndsWith(" KiB", &size) )
+            return 0;
+
+        unsigned long n = 0;
+        size.ToULong(&n);
+
+        return n*factor;
+    }
+};
+
 // ----------------------------------------------------------------------------
 // Application class
 // ----------------------------------------------------------------------------
@@ -140,6 +224,8 @@ private:
 
     wxTreeListCtrl* m_treelist;
 
+    MyComparator m_comparator;
+
     wxTreeListItem m_itemHTMLDocs;
 
     wxLog* m_oldLogTarget;
@@ -304,20 +390,18 @@ wxTreeListCtrl* MyFrame::CreateTreeListCtrl(long style)
                                   style);
     tree->SetImageList(m_imageList);
 
-    enum
-    {
-        Col_Component,
-        Col_Files,
-        Col_Size
-    };
-
-    tree->AppendColumn("Component");
+    tree->AppendColumn("Component",
+                       wxCOL_WIDTH_AUTOSIZE,
+                       wxALIGN_LEFT,
+                       wxCOL_RESIZABLE | wxCOL_SORTABLE);
     tree->AppendColumn("# Files",
                        tree->WidthFor("1,000,000"),
-                       wxALIGN_RIGHT);
+                       wxALIGN_RIGHT,
+                       wxCOL_RESIZABLE | wxCOL_SORTABLE);
     tree->AppendColumn("Size",
                        tree->WidthFor("1,000,000 KiB"),
-                       wxALIGN_RIGHT);
+                       wxALIGN_RIGHT,
+                       wxCOL_RESIZABLE | wxCOL_SORTABLE);
 
     // Define a shortcut to save on typing here.
     #define ADD_ITEM(item, parent, files, size) \
@@ -351,6 +435,9 @@ wxTreeListCtrl* MyFrame::CreateTreeListCtrl(long style)
     // Remember this one for subsequent tests.
     m_itemHTMLDocs = HTML;
 
+    // Set a custom comparator to compare strings containing numbers correctly.
+    tree->SetItemComparator(&m_comparator);
+
     return tree;
 }
 
index 69245fd31dddb97873b211e35159a1b446fda81d..68ee06f333bcccb5193d1c7461d788d4274b8c9f 100644 (file)
@@ -378,6 +378,10 @@ public:
     virtual unsigned GetChildren(const wxDataViewItem& item,
                                  wxDataViewItemArray& children) const;
     virtual bool IsListModel() const { return m_isFlat; }
+    virtual int Compare(const wxDataViewItem& item1,
+                        const wxDataViewItem& item2,
+                        unsigned col,
+                        bool ascending) const;
 
 private:
     // The control we're associated with.
@@ -953,6 +957,27 @@ wxTreeListModel::GetChildren(const wxDataViewItem& item,
     return numChildren;
 }
 
+int
+wxTreeListModel::Compare(const wxDataViewItem& item1,
+                         const wxDataViewItem& item2,
+                         unsigned col,
+                         bool ascending) const
+{
+    // Compare using default alphabetical order if no custom comparator.
+    wxTreeListItemComparator* const comp = m_treelist->m_comparator;
+    if ( !comp )
+        return wxDataViewModel::Compare(item1, item2, col, ascending);
+
+    // Forward comparison to the comparator:
+    int result = comp->Compare(m_treelist, col, FromDVI(item1), FromDVI(item2));
+
+    // And adjust by the sort order if necessary.
+    if ( !ascending )
+        result = -result;
+
+    return result;
+}
+
 // ============================================================================
 // wxTreeListCtrl implementation
 // ============================================================================
@@ -963,6 +988,7 @@ BEGIN_EVENT_TABLE(wxTreeListCtrl, wxWindow)
     EVT_DATAVIEW_ITEM_EXPANDED(wxID_ANY, wxTreeListCtrl::OnItemExpanded)
     EVT_DATAVIEW_ITEM_ACTIVATED(wxID_ANY, wxTreeListCtrl::OnItemActivated)
     EVT_DATAVIEW_ITEM_CONTEXT_MENU(wxID_ANY, wxTreeListCtrl::OnItemContextMenu)
+    EVT_DATAVIEW_COLUMN_SORTED(wxID_ANY, wxTreeListCtrl::OnColumnSorted)
 
     EVT_SIZE(wxTreeListCtrl::OnSize)
 END_EVENT_TABLE()
@@ -975,6 +1001,7 @@ void wxTreeListCtrl::Init()
 {
     m_view = NULL;
     m_model = NULL;
+    m_comparator = NULL;
 }
 
 bool wxTreeListCtrl::Create(wxWindow* parent,
@@ -1454,11 +1481,48 @@ wxTreeListCtrl::AreAllChildrenInState(wxTreeListItem item,
     return true;
 }
 
+// ----------------------------------------------------------------------------
+// Sorting
+// ----------------------------------------------------------------------------
+
+void wxTreeListCtrl::SetSortColumn(unsigned col, bool ascendingOrder)
+{
+    wxCHECK_RET( col < m_view->GetColumnCount(), "Invalid column index" );
+
+    m_view->GetColumn(col)->SetSortOrder(ascendingOrder);
+}
+
+bool wxTreeListCtrl::GetSortColumn(unsigned* col, bool* ascendingOrder)
+{
+    const unsigned numColumns = m_view->GetColumnCount();
+    for ( unsigned n = 0; n < numColumns; n++ )
+    {
+        wxDataViewColumn* const column = m_view->GetColumn(n);
+        if ( column->IsSortKey() )
+        {
+            if ( col )
+                *col = n;
+
+            if ( ascendingOrder )
+                *ascendingOrder = column->IsSortOrderAscending();
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void wxTreeListCtrl::SetItemComparator(wxTreeListItemComparator* comparator)
+{
+    m_comparator = comparator;
+}
+
 // ----------------------------------------------------------------------------
 // Events
 // ----------------------------------------------------------------------------
 
-void wxTreeListCtrl::SendEvent(wxEventType evt, wxDataViewEvent& eventDV)
+void wxTreeListCtrl::SendItemEvent(wxEventType evt, wxDataViewEvent& eventDV)
 {
     wxTreeListEvent eventTL(evt, this, m_model->FromDVI(eventDV.GetItem()));
 
@@ -1474,6 +1538,23 @@ void wxTreeListCtrl::SendEvent(wxEventType evt, wxDataViewEvent& eventDV)
     }
 }
 
+void wxTreeListCtrl::SendColumnEvent(wxEventType evt, wxDataViewEvent& eventDV)
+{
+    wxTreeListEvent eventTL(evt, this, wxTreeListItem());
+    eventTL.SetColumn(eventDV.GetColumn());
+
+    if ( !ProcessWindowEvent(eventTL) )
+    {
+        eventDV.Skip();
+        return;
+    }
+
+    if ( !eventTL.IsAllowed() )
+    {
+        eventDV.Veto();
+    }
+}
+
 void
 wxTreeListCtrl::OnItemToggled(wxTreeListItem item, wxCheckBoxState stateOld)
 {
@@ -1485,27 +1566,32 @@ wxTreeListCtrl::OnItemToggled(wxTreeListItem item, wxCheckBoxState stateOld)
 
 void wxTreeListCtrl::OnSelectionChanged(wxDataViewEvent& event)
 {
-    SendEvent(wxEVT_COMMAND_TREELIST_SELECTION_CHANGED, event);
+    SendItemEvent(wxEVT_COMMAND_TREELIST_SELECTION_CHANGED, event);
 }
 
 void wxTreeListCtrl::OnItemExpanding(wxDataViewEvent& event)
 {
-    SendEvent(wxEVT_COMMAND_TREELIST_ITEM_EXPANDING, event);
+    SendItemEvent(wxEVT_COMMAND_TREELIST_ITEM_EXPANDING, event);
 }
 
 void wxTreeListCtrl::OnItemExpanded(wxDataViewEvent& event)
 {
-    SendEvent(wxEVT_COMMAND_TREELIST_ITEM_EXPANDED, event);
+    SendItemEvent(wxEVT_COMMAND_TREELIST_ITEM_EXPANDED, event);
 }
 
 void wxTreeListCtrl::OnItemActivated(wxDataViewEvent& event)
 {
-    SendEvent(wxEVT_COMMAND_TREELIST_ITEM_ACTIVATED, event);
+    SendItemEvent(wxEVT_COMMAND_TREELIST_ITEM_ACTIVATED, event);
 }
 
 void wxTreeListCtrl::OnItemContextMenu(wxDataViewEvent& event)
 {
-    SendEvent(wxEVT_COMMAND_TREELIST_ITEM_CONTEXT_MENU, event);
+    SendItemEvent(wxEVT_COMMAND_TREELIST_ITEM_CONTEXT_MENU, event);
+}
+
+void wxTreeListCtrl::OnColumnSorted(wxDataViewEvent& event)
+{
+    SendColumnEvent(wxEVT_COMMAND_TREELIST_COLUMN_SORTED, event);
 }
 
 // ----------------------------------------------------------------------------
@@ -1572,6 +1658,7 @@ wxDEFINE_TREELIST_EVENT(ITEM_EXPANDED);
 wxDEFINE_TREELIST_EVENT(ITEM_CHECKED);
 wxDEFINE_TREELIST_EVENT(ITEM_ACTIVATED);
 wxDEFINE_TREELIST_EVENT(ITEM_CONTEXT_MENU);
+wxDEFINE_TREELIST_EVENT(COLUMN_SORTED);
 
 #undef wxDEFINE_TREELIST_EVENT