Bug in wx.TreeListCtrl.DeleteChildren?

Hi Robin et al,

I think I may have discovered a bug in wx.TreeListCtrl.DeleteChildren,
or rather wxTreeListItem::DeleteChildren.
wxTreeListCtrl::DeleteChildren invokes
wx.TreeListMainWindow::DeleteChildren:

void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
{ m_main_win->DeleteChildren(item); }

wxTreeListMainWindow::DeleteChildren in turn calls
wxTreeListItem::DeleteChildren:

void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
    wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
    m_dirty = true; // do this first so stuff below doesn't cause flicker

    item->DeleteChildren (this);
}

Note how wxTreeListItem::DeleteChildren makes sure m_selectItem stays
valid, but never touches tree->m_curItem:

void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
    size_t count = m_children.Count();
    for (size_t n = 0; n < count; n++) {
        wxTreeListItem *child = m_children[n];
        if (tree) {
            tree->SendDeleteEvent (child);
            if (tree->m_selectItem == child) tree->m_selectItem =
(wxTreeListItem*)NULL;
        }
        child->DeleteChildren (tree);
        delete child;
    }
    m_children.Empty();
}

If I next delete another item in the tree with wxTreeListCtrl::Delete,
wxTreeListMainWindow::Delete is invoked:

void wxTreeListCtrl::Delete(const wxTreeItemId& item)
{ m_main_win->Delete(item); }

wxTreeListMainWindow::Delete in turn calls wxTreeListItem::Delete,
which tries to check whether item is a descendant of m_curItem:

void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
    ....
    if ( IsDescendantOf(item, m_curItem) )
    {
    ......

But m_curItem may point to a deleted item with a crash as result.

Correct analysis?

Cheers, Frank

Hi Robin,

Frank Niessink wrote:

> But m_curItem may point to a deleted item with a crash as result.
>
> Correct analysis?

Yes, it looks correct to me. So do you think that m_curItem should
also be set to NULL in wxTreeListItem::DeleteChildren if there is a
matching child being deleted, or does it always need to point to a valid
item?

I'm not sure. I'm not even sure I understand why TreeListCtrl needs
both the concept of a current item and a selected item. I don't think
the TreeCtrl makes that distinction. In my code I worked around this
bug by setting the current item to the (hidden) root item of the tree
before each update. That seems to work.

I guess the best solution is to deal with the current item in a
similar vein as the selected item is dealt with, i.e. when the current
item is about to be deleted make its parent item the new current item.

Cheers, Frank

···

2007/12/10, Robin Dunn <robin@alldunn.com>: