]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
Typo fix
[wxWidgets.git] / src / msw / treectrl.cpp
index a0713416ab5ac9ad518d8d530fe84f9afbabc35e..84a8b01c20f42fdd61073a7b9593f7a5e9a14044 100644 (file)
     #define TVS_CHECKBOXES          0x0100
 #endif
 
     #define TVS_CHECKBOXES          0x0100
 #endif
 
+#ifndef TVS_FULLROWSELECT
+    #define TVS_FULLROWSELECT       0x1000
+#endif
+
 // old headers might miss these messages (comctl32.dll 4.71+ only)
 #ifndef TVM_SETBKCOLOR
     #define TVM_SETBKCOLOR          (TV_FIRST + 29)
 // old headers might miss these messages (comctl32.dll 4.71+ only)
 #ifndef TVM_SETBKCOLOR
     #define TVM_SETBKCOLOR          (TV_FIRST + 29)
@@ -93,7 +97,6 @@
 // looks quite ugly.
 #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
 
 // looks quite ugly.
 #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
 
-
 // ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
@@ -113,6 +116,7 @@ static HTREEITEM GetItemFromPoint(HWND hwndTV, int x, int y)
 // wrappers for TreeView_GetItem/TreeView_SetItem
 static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem)
 {
 // wrappers for TreeView_GetItem/TreeView_SetItem
 static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem)
 {
+
     TV_ITEM tvi;
     tvi.mask = TVIF_STATE | TVIF_HANDLE;
     tvi.stateMask = TVIS_SELECTED;
     TV_ITEM tvi;
     tvi.mask = TVIF_STATE | TVIF_HANDLE;
     tvi.stateMask = TVIS_SELECTED;
@@ -288,6 +292,8 @@ struct wxTreeViewItem : public TV_ITEM
                    UINT mask_,                  // fields which are valid
                    UINT stateMask_ = 0)         // for TVIF_STATE only
     {
                    UINT mask_,                  // fields which are valid
                    UINT stateMask_ = 0)         // for TVIF_STATE only
     {
+        wxZeroMemory(*this);
+
         // hItem member is always valid
         mask = mask_ | TVIF_HANDLE;
         stateMask = stateMask_;
         // hItem member is always valid
         mask = mask_ | TVIF_HANDLE;
         stateMask = stateMask_;
@@ -295,10 +301,39 @@ struct wxTreeViewItem : public TV_ITEM
     }
 };
 
     }
 };
 
+// wxVirutalNode is used in place of a single root when 'hidden' root is
+// specified.
+class wxVirtualNode : public wxTreeViewItem
+{
+public:
+    wxVirtualNode(wxTreeItemData *data)
+        : wxTreeViewItem(TVI_ROOT, 0)
+    {
+        m_data = data;
+    }
+
+    ~wxVirtualNode()
+    {
+        delete m_data;
+    }
+
+    wxTreeItemData *GetData() const { return m_data; }
+    void SetData(wxTreeItemData *data) { delete m_data; m_data = data; }
+
+private:
+    wxTreeItemData *m_data;
+};
+
 #ifdef __VISUALC__
 #pragma warning( default : 4097 )
 #endif
 
 #ifdef __VISUALC__
 #pragma warning( default : 4097 )
 #endif
 
+// a macro to get the virtual root, returns NULL if none
+#define GET_VIRTUAL_ROOT() ((wxVirtualNode *)m_pVirtualRoot)
+
+// returns TRUE if the item is the virtual root
+#define IS_VIRTUAL_ROOT(item) (HITEM(item) == TVI_ROOT)
+
 // a class which encapsulates the tree traversal logic: it vists all (unless
 // OnVisit() returns FALSE) items under the given one
 class wxTreeTraversal
 // a class which encapsulates the tree traversal logic: it vists all (unless
 // OnVisit() returns FALSE) items under the given one
 class wxTreeTraversal
@@ -342,6 +377,12 @@ public:
 
     virtual bool OnVisit(const wxTreeItemId& item)
     {
 
     virtual bool OnVisit(const wxTreeItemId& item)
     {
+        // can't visit a virtual node.
+        if ( (GetTree()->GetRootItem() == item) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT))
+        {
+            return TRUE;
+        }
+
 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
         if ( GetTree()->IsItemChecked(item) )
 #else
 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
         if ( GetTree()->IsItemChecked(item) )
 #else
@@ -397,11 +438,12 @@ private:
 //
 // There is only one problem with this: when we retrieve the item's data, we
 // don't know whether we get a pointer to wxTreeItemData or
 //
 // There is only one problem with this: when we retrieve the item's data, we
 // don't know whether we get a pointer to wxTreeItemData or
-// wxTreeItemIndirectData. So we have to maintain a list of all items which
-// have indirect data inside the listctrl itself.
+// wxTreeItemIndirectData. So we always set the item id to an invalid value
+// in this class and the code using the client data checks for it and retrieves
+// the real client data in this case.
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-class wxTreeItemIndirectData
+class wxTreeItemIndirectData : public wxTreeItemData
 {
 public:
     // ctor associates this data with the item and the real item data becomes
 {
 public:
     // ctor associates this data with the item and the real item data becomes
@@ -418,10 +460,13 @@ public:
 
         // and set ourselves as the new one
         tree->SetIndirectItemData(item, this);
 
         // and set ourselves as the new one
         tree->SetIndirectItemData(item, this);
+
+        // we must have the invalid value for the item
+        m_pItem = 0l;
     }
 
     // dtor deletes the associated data as well
     }
 
     // dtor deletes the associated data as well
-    ~wxTreeItemIndirectData() { delete m_data; }
+    virtual ~wxTreeItemIndirectData() { delete m_data; }
 
     // accessors
         // get the real data associated with the item
 
     // accessors
         // get the real data associated with the item
@@ -440,6 +485,7 @@ private:
     // all the images associated with the item
     int m_images[wxTreeItemIcon_Max];
 
     // all the images associated with the item
     int m_images[wxTreeItemIcon_Max];
 
+    // the real client data
     wxTreeItemData *m_data;
 };
 
     wxTreeItemData *m_data;
 };
 
@@ -450,15 +496,36 @@ private:
 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
 
 // ----------------------------------------------------------------------------
 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
 
 // ----------------------------------------------------------------------------
-// variables
+// constants
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-// handy table for sending events
-static wxEventType g_events[2][2] =
+// indices in gs_expandEvents table below
+enum
+{
+    IDX_COLLAPSE,
+    IDX_EXPAND,
+    IDX_WHAT_MAX
+};
+
+enum
+{
+    IDX_DONE,
+    IDX_DOING,
+    IDX_HOW_MAX
+};
+
+// handy table for sending events - it has to be initialized during run-time
+// now so can't be const any more
+static /* const */ wxEventType gs_expandEvents[IDX_WHAT_MAX][IDX_HOW_MAX];
+
+/*
+   but logically it's a const table with the following entries:
+=
 {
     { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
     { wxEVT_COMMAND_TREE_ITEM_EXPANDED,  wxEVT_COMMAND_TREE_ITEM_EXPANDING  }
 };
 {
     { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
     { wxEVT_COMMAND_TREE_ITEM_EXPANDED,  wxEVT_COMMAND_TREE_ITEM_EXPANDING  }
 };
+*/
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -508,14 +575,14 @@ void wxTreeCtrl::Init()
     m_hasAnyAttr = FALSE;
     m_dragImage = NULL;
     m_htSelStart = 0;
     m_hasAnyAttr = FALSE;
     m_dragImage = NULL;
     m_htSelStart = 0;
+    m_pVirtualRoot = NULL;
 
 
-    // Initialize static array of events, because with the new event system,
-    // they may not be initialized yet.
-
-    g_events[0][0] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED;
-    g_events[0][1] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING;
-    g_events[1][0] = wxEVT_COMMAND_TREE_ITEM_EXPANDED;
-    g_events[1][1] = wxEVT_COMMAND_TREE_ITEM_EXPANDING;
+    // initialize the global array of events now as it can't be done statically
+    // with the wxEVT_XXX values being allocated during run-time only
+    gs_expandEvents[IDX_COLLAPSE][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED;
+    gs_expandEvents[IDX_COLLAPSE][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING;
+    gs_expandEvents[IDX_EXPAND][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_EXPANDED;
+    gs_expandEvents[IDX_EXPAND][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_EXPANDING;
 }
 
 bool wxTreeCtrl::Create(wxWindow *parent,
 }
 
 bool wxTreeCtrl::Create(wxWindow *parent,
@@ -547,14 +614,13 @@ bool wxTreeCtrl::Create(wxWindow *parent,
 
     if ( m_windowStyle & wxTR_LINES_AT_ROOT )
         wstyle |= TVS_LINESATROOT;
 
     if ( m_windowStyle & wxTR_LINES_AT_ROOT )
         wstyle |= TVS_LINESATROOT;
-    
+
     if ( m_windowStyle & wxTR_FULL_ROW_HIGHLIGHT )
     if ( m_windowStyle & wxTR_FULL_ROW_HIGHLIGHT )
-    {    
+    {
         if ( wxTheApp->GetComCtl32Version() >= 471 )
             wstyle |= TVS_FULLROWSELECT;
     }
 
         if ( wxTheApp->GetComCtl32Version() >= 471 )
             wstyle |= TVS_FULLROWSELECT;
     }
 
-
     // using TVS_CHECKBOXES for emulation of a multiselection tree control
     // doesn't work without the new enough headers
 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \
     // using TVS_CHECKBOXES for emulation of a multiselection tree control
     // doesn't work without the new enough headers
 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \
@@ -574,10 +640,10 @@ bool wxTreeCtrl::Create(wxWindow *parent,
         return FALSE;
 
 #if wxUSE_COMCTL32_SAFELY
         return FALSE;
 
 #if wxUSE_COMCTL32_SAFELY
-    wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+    wxWindow::SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
     wxWindow::SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #elif 1
     wxWindow::SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #elif 1
-    SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #else
     // This works around a bug in the Windows tree control whereby for some versions
     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #else
     // This works around a bug in the Windows tree control whereby for some versions
@@ -586,7 +652,7 @@ bool wxTreeCtrl::Create(wxWindow *parent,
     // THIS FIX NOW REVERTED since it caused problems on _other_ systems.
     // Assume the user has an updated comctl32.dll.
     ::SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0,-1);
     // THIS FIX NOW REVERTED since it caused problems on _other_ systems.
     // Assume the user has an updated comctl32.dll.
     ::SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0,-1);
-    wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+    wxWindow::SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #endif
 
     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
 #endif
 
@@ -664,6 +730,7 @@ wxTreeCtrl::~wxTreeCtrl()
     DeleteTextCtrl();
 
     // delete user data to prevent memory leaks
     DeleteTextCtrl();
 
     // delete user data to prevent memory leaks
+    // also deletes hidden root node storage.
     DeleteAllItems();
 
     if (m_ownsImageListNormal) delete m_imageListNormal;
     DeleteAllItems();
 
     if (m_ownsImageListNormal) delete m_imageListNormal;
@@ -678,6 +745,9 @@ wxTreeCtrl::~wxTreeCtrl()
 
 bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
 {
 
 bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
 {
+    wxCHECK_MSG( tvItem->hItem != TVI_ROOT, FALSE,
+                 _T("can't retrieve virtual root item") );
+
     if ( !TreeView_GetItem(GetHwnd(), tvItem) )
     {
         wxLogLastError(wxT("TreeView_GetItem"));
     if ( !TreeView_GetItem(GetHwnd(), tvItem) )
     {
         wxLogLastError(wxT("TreeView_GetItem"));
@@ -731,7 +801,9 @@ void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
 
 void wxTreeCtrl::SetImageList(wxImageList *imageList)
 {
 
 void wxTreeCtrl::SetImageList(wxImageList *imageList)
 {
-    if (m_ownsImageListNormal) delete m_imageListNormal;
+    if (m_ownsImageListNormal)
+        delete m_imageListNormal;
+
     SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
     m_ownsImageListNormal = FALSE;
 }
     SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
     m_ownsImageListNormal = FALSE;
 }
@@ -813,6 +885,9 @@ wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
 
 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
 {
 
 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+        return;
+
     wxTreeViewItem tvItem(item, TVIF_TEXT);
     tvItem.pszText = (wxChar *)text.c_str();  // conversion is ok
     DoSetItem(&tvItem);
     wxTreeViewItem tvItem(item, TVIF_TEXT);
     tvItem.pszText = (wxChar *)text.c_str();  // conversion is ok
     DoSetItem(&tvItem);
@@ -871,6 +946,12 @@ void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item,
                              wxTreeItemIcon which) const
 {
 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item,
                              wxTreeItemIcon which) const
 {
+    if ( (HITEM(item) == TVI_ROOT) && (m_windowStyle & wxTR_HIDE_ROOT) )
+    {
+        // TODO: Maybe a hidden root can still provide images?
+        return -1;
+    }
+
     if ( HasIndirectData(item) )
     {
         return DoGetItemImageFromData(item, which);
     if ( HasIndirectData(item) )
     {
         return DoGetItemImageFromData(item, which);
@@ -904,6 +985,12 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item,
 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image,
                               wxTreeItemIcon which)
 {
 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image,
                               wxTreeItemIcon which)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+    {
+        // TODO: Maybe a hidden root can still store images?
+        return;
+    }
+
     int imageNormal, imageSel;
     switch ( which )
     {
     int imageNormal, imageSel;
     switch ( which )
     {
@@ -957,23 +1044,35 @@ void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image,
 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
 {
     wxTreeViewItem tvItem(item, TVIF_PARAM);
 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
 {
     wxTreeViewItem tvItem(item, TVIF_PARAM);
-    if ( !DoGetItem(&tvItem) )
+
+    // Hidden root may have data.
+    if ( IS_VIRTUAL_ROOT(item) )
     {
     {
-        return NULL;
+        return GET_VIRTUAL_ROOT()->GetData();
     }
 
     }
 
-    if ( HasIndirectData(item) )
+    // Visible node.
+    if ( !DoGetItem(&tvItem) )
     {
     {
-        return ((wxTreeItemIndirectData *)tvItem.lParam)->GetData();
+        return NULL;
     }
     }
-    else
+
+    wxTreeItemData *data = (wxTreeItemData *)tvItem.lParam;
+    if ( IsDataIndirect(data) )
     {
     {
-        return (wxTreeItemData *)tvItem.lParam;
+        data = ((wxTreeItemIndirectData *)data)->GetData();
     }
     }
+
+    return data;
 }
 
 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
 {
 }
 
 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+    {
+        GET_VIRTUAL_ROOT()->SetData(data);
+    }
+
     // first, associate this piece of data with this item
     if ( data )
     {
     // first, associate this piece of data with this item
     if ( data )
     {
@@ -1009,18 +1108,28 @@ void wxTreeCtrl::SetIndirectItemData(const wxTreeItemId& item,
     // wxTreeItemIndirectData as well
     wxASSERT_MSG( !HasIndirectData(item), wxT("setting indirect data twice?") );
 
     // wxTreeItemIndirectData as well
     wxASSERT_MSG( !HasIndirectData(item), wxT("setting indirect data twice?") );
 
-    SetItemData(item, (wxTreeItemData *)data);
-
-    m_itemsWithIndirectData.Add(item);
+    SetItemData(item, data);
 }
 
 bool wxTreeCtrl::HasIndirectData(const wxTreeItemId& item) const
 {
 }
 
 bool wxTreeCtrl::HasIndirectData(const wxTreeItemId& item) const
 {
-    return m_itemsWithIndirectData.Index(item) != wxNOT_FOUND;
+    // query the item itself
+    wxTreeViewItem tvItem(item, TVIF_PARAM);
+    if ( !DoGetItem(&tvItem) )
+    {
+        return FALSE;
+    }
+
+    wxTreeItemData *data = (wxTreeItemData *)tvItem.lParam;
+
+    return data && IsDataIndirect(data);
 }
 
 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
 {
 }
 
 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+        return;
+
     wxTreeViewItem tvItem(item, TVIF_CHILDREN);
     tvItem.cChildren = (int)has;
     DoSetItem(&tvItem);
     wxTreeViewItem tvItem(item, TVIF_CHILDREN);
     tvItem.cChildren = (int)has;
     DoSetItem(&tvItem);
@@ -1028,6 +1137,9 @@ void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
 
 void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
 {
 
 void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+        return;
+
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
     tvItem.state = bold ? TVIS_BOLD : 0;
     DoSetItem(&tvItem);
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
     tvItem.state = bold ? TVIS_BOLD : 0;
     DoSetItem(&tvItem);
@@ -1035,6 +1147,9 @@ void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
 
 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
 {
 
 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+        return;
+
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
     tvItem.state = highlight ? TVIS_DROPHILITED : 0;
     DoSetItem(&tvItem);
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
     tvItem.state = highlight ? TVIS_DROPHILITED : 0;
     DoSetItem(&tvItem);
@@ -1042,6 +1157,9 @@ void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
 
 void wxTreeCtrl::RefreshItem(const wxTreeItemId& item)
 {
 
 void wxTreeCtrl::RefreshItem(const wxTreeItemId& item)
 {
+    if ( IS_VIRTUAL_ROOT(item) )
+        return;
+
     wxRect rect;
     if ( GetBoundingRect(item, rect) )
     {
     wxRect rect;
     if ( GetBoundingRect(item, rect) )
     {
@@ -1160,6 +1278,10 @@ bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
 
 wxTreeItemId wxTreeCtrl::GetRootItem() const
 {
 
 wxTreeItemId wxTreeCtrl::GetRootItem() const
 {
+    // Root may be real (visible) or virtual (hidden).
+    if ( GET_VIRTUAL_ROOT() )
+        return TVI_ROOT;
+
     return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(GetHwnd()));
 }
 
     return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(GetHwnd()));
 }
 
@@ -1173,7 +1295,24 @@ wxTreeItemId wxTreeCtrl::GetSelection() const
 
 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
 {
 
 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
 {
-    return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(GetHwnd(), HITEM(item)));
+    HTREEITEM hItem;
+
+    if ( IS_VIRTUAL_ROOT(item) )
+    {
+        // no parent for the virtual root
+        hItem = 0;
+    }
+    else // normal item
+    {
+        hItem = TreeView_GetParent(GetHwnd(), HITEM(item));
+        if ( !hItem && HasFlag(wxTR_HIDE_ROOT) )
+        {
+            // the top level items should have the virtual root as their parent
+            hItem = TVI_ROOT;
+        }
+    }
+
+    return wxTreeItemId((WXHTREEITEM)hItem);
 }
 
 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
 }
 
 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
@@ -1259,6 +1398,8 @@ void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
     // receive the desired information.
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
 
     // receive the desired information.
     wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
 
+    DoGetItem(&tvItem);
+
     // state images are one-based
     tvItem.state = (check ? 2 : 1) << 12;
 
     // state images are one-based
     tvItem.state = (check ? 2 : 1) << 12;
 
@@ -1364,7 +1505,16 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
                                  int image, int selectedImage,
                                  wxTreeItemData *data)
 {
                                  int image, int selectedImage,
                                  wxTreeItemData *data)
 {
-    return DoInsertItem(wxTreeItemId((long) (WXHTREEITEM) 0), (long)(WXHTREEITEM) 0,
+
+    if ( m_windowStyle & wxTR_HIDE_ROOT )
+    {
+        // create a virtual root item, the parent for all the others
+        m_pVirtualRoot = new wxVirtualNode(data);
+
+        return TVI_ROOT;
+    }
+
+    return DoInsertItem(wxTreeItemId((long)(WXHTREEITEM) 0), (long)(WXHTREEITEM) 0,
                         text, image, selectedImage, data);
 }
 
                         text, image, selectedImage, data);
 }
 
@@ -1453,6 +1603,9 @@ void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
 
 void wxTreeCtrl::DeleteAllItems()
 {
 
 void wxTreeCtrl::DeleteAllItems()
 {
+    // delete stored root item.
+    delete GET_VIRTUAL_ROOT();
+
     if ( !TreeView_DeleteAllItems(GetHwnd()) )
     {
         wxLogLastError(wxT("TreeView_DeleteAllItems"));
     if ( !TreeView_DeleteAllItems(GetHwnd()) )
     {
         wxLogLastError(wxT("TreeView_DeleteAllItems"));
@@ -1467,6 +1620,10 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
                   flag == TVE_TOGGLE,
                   wxT("Unknown flag in wxTreeCtrl::DoExpand") );
 
                   flag == TVE_TOGGLE,
                   wxT("Unknown flag in wxTreeCtrl::DoExpand") );
 
+    // A hidden root can be neither expanded nor collapsed.
+    wxCHECK_RET( !(m_windowStyle & wxTR_HIDE_ROOT) || (HITEM(item) != TVI_ROOT),
+                 wxT("Can't expand/collapse hidden root node!") )
+
     // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
     // emulate them. This behaviour has changed slightly with comctl32.dll
     // v 4.70 - now it does send them but only the first time. To maintain
     // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
     // emulate them. This behaviour has changed slightly with comctl32.dll
     // v 4.70 - now it does send them but only the first time. To maintain
@@ -1483,17 +1640,15 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
     {
         wxTreeEvent event(wxEVT_NULL, m_windowId);
         event.m_item = item;
     {
         wxTreeEvent event(wxEVT_NULL, m_windowId);
         event.m_item = item;
-
-        bool isExpanded = IsExpanded(item);
-
         event.SetEventObject(this);
 
         event.SetEventObject(this);
 
-        // FIXME return value of {EXPAND|COLLAPS}ING event handler is discarded
-        event.SetEventType(g_events[isExpanded][TRUE]);
-        GetEventHandler()->ProcessEvent(event);
+        // note that the {EXPAND|COLLAPS}ING event is sent by TreeView_Expand()
+        // itself
+        event.SetEventType(gs_expandEvents[IsExpanded(item) ? IDX_EXPAND
+                                                            : IDX_COLLAPSE]
+                                          [IDX_DONE]);
 
 
-        event.SetEventType(g_events[isExpanded][FALSE]);
-        GetEventHandler()->ProcessEvent(event);
+        (void)GetEventHandler()->ProcessEvent(event);
     }
     //else: change didn't took place, so do nothing at all
 }
     }
     //else: change didn't took place, so do nothing at all
 }
@@ -1608,24 +1763,6 @@ void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
 
 wxTextCtrl* wxTreeCtrl::GetEditControl() const
 {
 
 wxTextCtrl* wxTreeCtrl::GetEditControl() const
 {
-    // normally, we could try to do something like this to return something
-    // even when the editing was started by the user and not by calling
-    // EditLabel() - but as nobody has asked for this so far and there might be
-    // problems in the code below, I leave it disabled for now (VZ)
-#if 0
-    if ( !m_textCtrl )
-    {
-        HWND hwndText = TreeView_GetEditControl(GetHwnd());
-        if ( hwndText )
-        {
-            m_textCtrl = new wxTextCtrl(this, -1);
-            m_textCtrl->Hide();
-            m_textCtrl->SetHWND((WXHWND)hwndText);
-        }
-        //else: not editing label right now
-    }
-#endif // 0
-
     return m_textCtrl;
 }
 
     return m_textCtrl;
 }
 
@@ -1655,20 +1792,19 @@ wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
 
     DeleteTextCtrl();
 
 
     DeleteTextCtrl();
 
+    m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
     HWND hWnd = (HWND) TreeView_EditLabel(GetHwnd(), HITEM(item));
 
     // this is not an error - the TVN_BEGINLABELEDIT handler might have
     // returned FALSE
     if ( !hWnd )
     {
     HWND hWnd = (HWND) TreeView_EditLabel(GetHwnd(), HITEM(item));
 
     // this is not an error - the TVN_BEGINLABELEDIT handler might have
     // returned FALSE
     if ( !hWnd )
     {
+        delete m_textCtrl;
+        m_textCtrl = NULL;
         return NULL;
     }
 
         return NULL;
     }
 
-    m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
-    m_textCtrl->SetParent(this);
-    m_textCtrl->SetHWND((WXHWND)hWnd);
-    m_textCtrl->SubclassWin((WXHWND)hWnd);
-
+    // textctrl is subclassed in MSWOnNotify
     return m_textCtrl;
 }
 
     return m_textCtrl;
 }
 
@@ -1734,14 +1870,37 @@ bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
 // sorting stuff
 // ----------------------------------------------------------------------------
 
 // sorting stuff
 // ----------------------------------------------------------------------------
 
-static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
-                                             wxTreeItemData *pItem2,
-                                             wxTreeCtrl *tree)
+// this is just a tiny namespace which is friend to wxTreeCtrl and so can use
+// functions such as IsDataIndirect()
+class wxTreeSortHelper
+{
+public:
+    static int CALLBACK Compare(LPARAM data1, LPARAM data2, LPARAM tree);
+
+private:
+    static wxTreeItemId GetIdFromData(wxTreeCtrl *tree, LPARAM item)
+    {
+        wxTreeItemData *data = (wxTreeItemData *)item;
+        if ( tree->IsDataIndirect(data) )
+        {
+            data = ((wxTreeItemIndirectData *)data)->GetData();
+        }
+
+        return data->GetId();
+    }
+};
+
+int CALLBACK wxTreeSortHelper::Compare(LPARAM pItem1,
+                                       LPARAM pItem2,
+                                       LPARAM htree)
 {
     wxCHECK_MSG( pItem1 && pItem2, 0,
                  wxT("sorting tree without data doesn't make sense") );
 
 {
     wxCHECK_MSG( pItem1 && pItem2, 0,
                  wxT("sorting tree without data doesn't make sense") );
 
-    return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
+    wxTreeCtrl *tree = (wxTreeCtrl *)htree;
+
+    return tree->OnCompareItems(GetIdFromData(tree, pItem1),
+                                GetIdFromData(tree, pItem2));
 }
 
 int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
 }
 
 int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
@@ -1763,7 +1922,7 @@ void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
     {
         TV_SORTCB tvSort;
         tvSort.hParent = HITEM(item);
     {
         TV_SORTCB tvSort;
         tvSort.hParent = HITEM(item);
-        tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
+        tvSort.lpfnCompare = wxTreeSortHelper::Compare;
         tvSort.lParam = (LPARAM)this;
         TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */);
     }
         tvSort.lParam = (LPARAM)this;
         TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */);
     }
@@ -2091,23 +2250,26 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             {
                 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
 
             {
                 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
 
-                bool expand = FALSE;
+                int what;
                 switch ( tv->action )
                 {
                 switch ( tv->action )
                 {
+                    default:
+                        wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv->action);
+                        // fall through
+
                     case TVE_EXPAND:
                     case TVE_EXPAND:
-                        expand = TRUE;
+                        what = IDX_EXPAND;
                         break;
 
                     case TVE_COLLAPSE:
                         break;
 
                     case TVE_COLLAPSE:
-                        expand = FALSE;
+                        what = IDX_COLLAPSE;
                         break;
                         break;
-
-                    default:
-                        wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv->action);
                 }
 
                 }
 
-                bool ing = ((int)hdr->code == TVN_ITEMEXPANDING);
-                eventType = g_events[expand][ing];
+                int how = (int)hdr->code == TVN_ITEMEXPANDING ? IDX_DOING
+                                                              : IDX_DONE;
+
+                eventType = gs_expandEvents[what][how];
 
                 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
             }
 
                 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
             }
@@ -2118,13 +2280,12 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
                 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
 
                 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
                 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
 
-                // we pass 0 as last CreateKeyEvent() parameter because we
+                // we pass 0 as 2 last CreateKeyEvent() parameters because we
                 // don't have access to the real key press flags here - but as
                 // it is only used to determin wxKeyEvent::m_altDown flag it's
                 // not too bad
                 event.m_evtKey = CreateKeyEvent(wxEVT_KEY_DOWN,
                 // don't have access to the real key press flags here - but as
                 // it is only used to determin wxKeyEvent::m_altDown flag it's
                 // not too bad
                 event.m_evtKey = CreateKeyEvent(wxEVT_KEY_DOWN,
-                                                wxCharCodeMSWToWX(info->wVKey),
-                                                0);
+                                                wxCharCodeMSWToWX(info->wVKey));
 
                 // a separate event for Space/Return
                 if ( !wxIsCtrlDown() && !wxIsShiftDown() &&
 
                 // a separate event for Space/Return
                 if ( !wxIsCtrlDown() && !wxIsShiftDown() &&
@@ -2331,13 +2492,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     wxTreeItemIndirectData *data = (wxTreeItemIndirectData *)
                                                         tv->itemOld.lParam;
                     delete data; // can't be NULL here
                     wxTreeItemIndirectData *data = (wxTreeItemIndirectData *)
                                                         tv->itemOld.lParam;
                     delete data; // can't be NULL here
-
-                    m_itemsWithIndirectData.Remove(item);
-#if 0
-                    int iIndex = m_itemsWithIndirectData.Index(item);
-                    wxASSERT( iIndex != wxNOT_FOUND) ;
-                    m_itemsWithIndirectData.wxBaseArray::RemoveAt((size_t)iIndex);
-#endif
                 }
                 else
                 {
                 }
                 else
                 {
@@ -2352,6 +2506,32 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         case TVN_BEGINLABELEDIT:
             // return TRUE to cancel label editing
             *result = !event.IsAllowed();
         case TVN_BEGINLABELEDIT:
             // return TRUE to cancel label editing
             *result = !event.IsAllowed();
+            // set ES_WANTRETURN ( like we do in BeginLabelEdit )
+            if(event.IsAllowed())
+            {
+                HWND hText = TreeView_GetEditControl(GetHwnd());
+                if(hText != NULL)
+                {
+                    // MBN: if m_textCtrl already has an HWND, it is a stale 
+                    // pointer from a previous edit (because the user
+                    // didn't modify the label before dismissing the control,
+                    // and TVN_ENDLABELEDIT was not sent), so delete it
+                    if(m_textCtrl && m_textCtrl->GetHWND() != 0)
+                        DeleteTextCtrl();
+                    if(!m_textCtrl)
+                        m_textCtrl = new wxTextCtrl();
+                    m_textCtrl->SetParent(this);
+                    m_textCtrl->SetHWND((WXHWND)hText);
+                    m_textCtrl->SubclassWin((WXHWND)hText);
+
+                    // set wxTE_PROCESS_ENTER style for the text control to
+                    // force it to process the Enter presses itself, otherwise
+                    // they could be stolen from it by the dialog
+                    // navigation code
+                    m_textCtrl->SetWindowStyle(m_textCtrl->GetWindowStyle()
+                                               | wxTE_PROCESS_ENTER);
+                }
+            }
             break;
 
         case TVN_ENDLABELEDIT:
             break;
 
         case TVN_ENDLABELEDIT:
@@ -2373,6 +2553,25 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             *result = !event.IsAllowed();
             break;
 
             *result = !event.IsAllowed();
             break;
 
+        case TVN_ITEMEXPANDED:
+            // the item is not refreshed properly after expansion when it has
+            // an image depending on the expanded/collapsed state - bug in
+            // comctl32.dll or our code?
+            {
+                NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
+                if ( tv->action == TVE_EXPAND )
+                {
+                    wxTreeItemId id = (WXHTREEITEM)tv->itemNew.hItem;
+
+                    int image = GetItemImage(id, wxTreeItemIcon_Expanded);
+                    if ( image != -1 )
+                    {
+                        RefreshItem(id);
+                    }
+                }
+            }
+            break;
+
         case TVN_GETDISPINFO:
             // NB: so far the user can't set the image himself anyhow, so do it
             //     anyway - but this may change later
         case TVN_GETDISPINFO:
             // NB: so far the user can't set the image himself anyhow, so do it
             //     anyway - but this may change later
@@ -2400,7 +2599,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                                           : wxTreeItemIcon_Selected
                         );
                 }
                                           : wxTreeItemIcon_Selected
                         );
                 }
-                       }
+            }
             break;
 
         //default:
             break;
 
         //default: