]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
compilation fixes for wxUniv (moved wxDlgProc back to toplevel.cpp)
[wxWidgets.git] / src / msw / treectrl.cpp
index 3ebf19f9e28a475ede3236af7111edd89cc44e5e..ffba0255fa063e8a837280b8d96e7c8f4a39001b 100644 (file)
@@ -97,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
 // ----------------------------------------------------------------------------
@@ -117,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;
@@ -292,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_;
@@ -299,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
@@ -346,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
@@ -459,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
@@ -517,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,
@@ -556,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 && \
@@ -583,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
@@ -595,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
 
@@ -673,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;
@@ -687,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"));
@@ -740,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;
 }
@@ -822,9 +885,26 @@ 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);
+
+    // when setting the text of the item being edited, the text control should
+    // be updated to reflect the new text as well, otherwise calling
+    // SetItemText() in the OnBeginLabelEdit() handler doesn't have any effect
+    //
+    // don't use GetEditControl() here because m_textCtrl is not set yet
+    HWND hwndEdit = TreeView_GetEditControl(GetHwnd());
+    if ( hwndEdit )
+    {
+        if ( item == GetSelection() )
+        {
+            ::SetWindowText(hwndEdit, text);
+        }
+    }
 }
 
 int wxTreeCtrl::DoGetItemImageFromData(const wxTreeItemId& item,
 }
 
 int wxTreeCtrl::DoGetItemImageFromData(const wxTreeItemId& item,
@@ -880,6 +960,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);
@@ -913,6 +999,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 )
     {
@@ -966,6 +1058,14 @@ 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);
+
+    // Hidden root may have data.
+    if ( IS_VIRTUAL_ROOT(item) )
+    {
+        return GET_VIRTUAL_ROOT()->GetData();
+    }
+
+    // Visible node.
     if ( !DoGetItem(&tvItem) )
     {
         return NULL;
     if ( !DoGetItem(&tvItem) )
     {
         return NULL;
@@ -982,6 +1082,11 @@ wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
 
 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 )
     {
@@ -1036,6 +1141,9 @@ bool wxTreeCtrl::HasIndirectData(const wxTreeItemId& item) const
 
 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);
@@ -1043,6 +1151,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);
@@ -1050,6 +1161,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);
@@ -1057,6 +1171,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) )
     {
@@ -1175,6 +1292,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()));
 }
 
@@ -1188,7 +1309,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,
@@ -1274,6 +1412,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;
 
@@ -1379,7 +1519,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);
 }
 
@@ -1468,6 +1617,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"));
@@ -1482,6 +1634,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
@@ -1498,17 +1654,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
 }
@@ -1621,26 +1775,8 @@ void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
     }
 }
 
     }
 }
 
-wxTextCtrlwxTreeCtrl::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;
 }
 
@@ -1670,20 +1806,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;
 }
 
@@ -2129,23 +2264,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;
             }
@@ -2156,13 +2294,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() &&
@@ -2383,6 +2520,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:
@@ -2404,10 +2567,26 @@ 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;
+                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
-//          if ( /* !processed && */ 1 )
+            //if ( /* !processed && */ 1 )
             {
                 wxTreeItemId item = event.m_item;
                 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
             {
                 wxTreeItemId item = event.m_item;
                 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
@@ -2431,7 +2610,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                                           : wxTreeItemIcon_Selected
                         );
                 }
                                           : wxTreeItemIcon_Selected
                         );
                 }
-                       }
+            }
             break;
 
         //default:
             break;
 
         //default: