]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
fix order of initializiton of rootless treectrl
[wxWidgets.git] / src / msw / treectrl.cpp
index 8c2580a1d734f14585e0d1995fef65d66281e7f8..3ebf19f9e28a475ede3236af7111edd89cc44e5e 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        treectrl.cpp
+// Name:        src/msw/treectrl.cpp
 // Purpose:     wxTreeCtrl
 // Author:      Julian Smart
 // Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
@@ -16,6 +16,7 @@
 // ----------------------------------------------------------------------------
 // headers
 // ----------------------------------------------------------------------------
+
 #ifdef __GNUG__
     #pragma implementation "treectrl.h"
 #endif
     #pragma hdrstop
 #endif
 
+#if wxUSE_TREECTRL
+
 #include "wx/msw/private.h"
 
-// Set this to 1 to be _absolutely_ sure that repainting will work for all comctl32.dll versions
+// Set this to 1 to be _absolutely_ sure that repainting will work for all
+// comctl32.dll versions
 #define wxUSE_COMCTL32_SAFELY 0
 
 // Mingw32 is a bit mental even though this is done in winundef
@@ -43,6 +47,7 @@
 
 #if defined(__WIN95__)
 
+#include "wx/app.h"
 #include "wx/log.h"
 #include "wx/dynarray.h"
 #include "wx/imaglist.h"
@@ -54,7 +59,7 @@
     #include "wx/msw/gnuwin32/extra.h"
 #endif
 
-#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) || defined(__TWIN32__))
+#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) && !defined(__CYGWIN10__))
     #include <commctrl.h>
 #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)
 // looks quite ugly.
 #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
 
-// ----------------------------------------------------------------------------
-// events
-// ----------------------------------------------------------------------------
-
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
 
 // ----------------------------------------------------------------------------
 // private functions
@@ -391,7 +378,7 @@ public:
             DoTraverse(root, recursively);
         }
 
-    virtual bool OnVisit(const wxTreeItemId& item)
+    virtual bool OnVisit(const wxTreeItemId& WXUNUSED(item))
     {
         m_count++;
 
@@ -414,11 +401,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
-// 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
@@ -435,10 +423,13 @@ public:
 
         // 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
-    ~wxTreeItemIndirectData() { delete m_data; }
+    virtual ~wxTreeItemIndirectData() { delete m_data; }
 
     // accessors
         // get the real data associated with the item
@@ -457,6 +448,7 @@ private:
     // all the images associated with the item
     int m_images[wxTreeItemIcon_Max];
 
+    // the real client data
     wxTreeItemData *m_data;
 };
 
@@ -471,7 +463,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
 // ----------------------------------------------------------------------------
 
 // handy table for sending events
-static const wxEventType g_events[2][2] =
+static wxEventType g_events[2][2] =
 {
     { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
     { wxEVT_COMMAND_TREE_ITEM_EXPANDED,  wxEVT_COMMAND_TREE_ITEM_EXPANDING  }
@@ -524,8 +516,15 @@ void wxTreeCtrl::Init()
     m_textCtrl = NULL;
     m_hasAnyAttr = FALSE;
     m_dragImage = NULL;
-
     m_htSelStart = 0;
+
+    // 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;
 }
 
 bool wxTreeCtrl::Create(wxWindow *parent,
@@ -542,7 +541,10 @@ bool wxTreeCtrl::Create(wxWindow *parent,
         return FALSE;
 
     DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
-                   TVS_SHOWSELALWAYS /* | WS_CLIPSIBLINGS */;
+                   TVS_SHOWSELALWAYS;
+
+    if ( m_windowStyle & wxCLIP_SIBLINGS )
+        wstyle |= WS_CLIPSIBLINGS;
 
     if ((m_windowStyle & wxTR_NO_LINES) == 0)
         wstyle |= TVS_HASLINES;
@@ -554,6 +556,13 @@ bool wxTreeCtrl::Create(wxWindow *parent,
 
     if ( m_windowStyle & wxTR_LINES_AT_ROOT )
         wstyle |= TVS_LINESATROOT;
+    
+    if ( m_windowStyle & wxTR_FULL_ROW_HIGHLIGHT )
+    {    
+        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
@@ -665,7 +674,7 @@ wxTreeCtrl::~wxTreeCtrl()
 
     // delete user data to prevent memory leaks
     DeleteAllItems();
-    
+
     if (m_ownsImageListNormal) delete m_imageListNormal;
     if (m_ownsImageListState) delete m_imageListState;
 }
@@ -962,14 +971,13 @@ wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
         return NULL;
     }
 
-    if ( HasIndirectData(item) )
-    {
-        return ((wxTreeItemIndirectData *)tvItem.lParam)->GetData();
-    }
-    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)
@@ -1009,14 +1017,21 @@ void wxTreeCtrl::SetIndirectItemData(const wxTreeItemId& item,
     // 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
 {
-    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)
@@ -1040,6 +1055,15 @@ void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
     DoSetItem(&tvItem);
 }
 
+void wxTreeCtrl::RefreshItem(const wxTreeItemId& item)
+{
+    wxRect rect;
+    if ( GetBoundingRect(item, rect) )
+    {
+        RefreshRect(rect);
+    }
+}
+
 void wxTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
                                    const wxColour& col)
 {
@@ -1054,6 +1078,8 @@ void wxTreeCtrl::SetItemTextColour(const wxTreeItemId& item,
     }
 
     attr->SetTextColour(col);
+
+    RefreshItem(item);
 }
 
 void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
@@ -1070,6 +1096,8 @@ void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
     }
 
     attr->SetBackgroundColour(col);
+
+    RefreshItem(item);
 }
 
 void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
@@ -1085,6 +1113,8 @@ void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font)
     }
 
     attr->SetFont(font);
+
+    RefreshItem(item);
 }
 
 // ----------------------------------------------------------------------------
@@ -1102,7 +1132,6 @@ bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
 
     // FALSE means get item rect for the whole item, not only text
     return SendMessage(GetHwnd(), TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
-
 }
 
 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
@@ -1651,6 +1680,7 @@ wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
     }
 
     m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
+    m_textCtrl->SetParent(this);
     m_textCtrl->SetHWND((WXHWND)hWnd);
     m_textCtrl->SubclassWin((WXHWND)hWnd);
 
@@ -1658,7 +1688,7 @@ wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
 }
 
 // End label editing, optionally cancelling the edit
-void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
+void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool discardChanges)
 {
     TreeView_EndEditLabelNow(GetHwnd(), discardChanges);
 
@@ -1719,14 +1749,37 @@ bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
 // 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") );
 
-    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,
@@ -1748,7 +1801,7 @@ void wxTreeCtrl::SortChildren(const wxTreeItemId& 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 */);
     }
@@ -1790,7 +1843,6 @@ long wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
     bool processed = FALSE;
     long rc = 0;
-
     bool isMultiple = (GetWindowStyle() & wxTR_MULTIPLE) != 0;
 
     if ( (nMsg >= WM_MOUSEFIRST) && (nMsg <= WM_MOUSELAST) )
@@ -1982,7 +2034,6 @@ long wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
         }
     }
 #endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE
-
     if ( !processed )
         rc = wxControl::MSWWindowProc(nMsg, wParam, lParam);
 
@@ -2074,9 +2125,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             }
 
         case TVN_ITEMEXPANDING:
-            event.m_code = FALSE;
-            // fall through
-
         case TVN_ITEMEXPANDED:
             {
                 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
@@ -2108,7 +2156,13 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
                 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
 
-                event.m_code = wxCharCodeMSWToWX(info->wVKey);
+                // we pass 0 as last CreateKeyEvent() parameter 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,
+                                                wxCharCodeMSWToWX(info->wVKey),
+                                                0);
 
                 // a separate event for Space/Return
                 if ( !wxIsCtrlDown() && !wxIsShiftDown() &&
@@ -2145,19 +2199,19 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             }
             break;
 
-#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 && !wxUSE_COMCTL32_SAFELY
+#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 && !wxUSE_COMCTL32_SAFELY && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
         case NM_CUSTOMDRAW:
             {
                 LPNMTVCUSTOMDRAW lptvcd = (LPNMTVCUSTOMDRAW)lParam;
                 NMCUSTOMDRAW& nmcd = lptvcd->nmcd;
-                switch( nmcd.dwDrawStage )
+                switch ( nmcd.dwDrawStage )
                 {
                     case CDDS_PREPAINT:
                         // if we've got any items with non standard attributes,
                         // notify us before painting each item
                         *result = m_hasAnyAttr ? CDRF_NOTIFYITEMDRAW
                                                : CDRF_DODEFAULT;
-                        return TRUE;
+                        break;
 
                     case CDDS_ITEMPREPAINT:
                         {
@@ -2167,7 +2221,8 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                             if ( !attr )
                             {
                                 // nothing to do for this item
-                                return CDRF_DODEFAULT;
+                                *result = CDRF_DODEFAULT;
+                                break;
                             }
 
                             HFONT hFont;
@@ -2230,16 +2285,16 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                             {
                                 *result = CDRF_DODEFAULT;
                             }
-
-                            return TRUE;
                         }
+                        break;
 
                     default:
                         *result = CDRF_DODEFAULT;
-                        return TRUE;
                 }
             }
-            break;
+
+            // we always process it
+            return TRUE;
 #endif // _WIN32_IE >= 0x300
 
         case NM_DBLCLK:
@@ -2314,13 +2369,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     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
                 {
@@ -2359,7 +2407,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         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;
@@ -2383,16 +2431,16 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                                           : wxTreeItemIcon_Selected
                         );
                 }
-            }
+                       }
             break;
 
         //default:
             // for the other messages the return value is ignored and there is
             // nothing special to do
     }
-
     return processed;
 }
 
 #endif // __WIN95__
 
+#endif // wxUSE_TREECTRL