]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/treectrl.cpp
don't declare inline function with dllexport declaration, this provokes mingw32 warni...
[wxWidgets.git] / src / msw / treectrl.cpp
index aeafd9e8ae1f7e15d8ca870c8cf28382cee726ad..d7df087c94a483f628266287fdbbc683f5aeb7eb 100644 (file)
@@ -95,11 +95,6 @@ static inline void UnselectItem(HWND hwndTV, HTREEITEM htItem)
     SelectItem(hwndTV, htItem, false);
 }
 
-static inline void ToggleItemSelection(HWND hwndTV, HTREEITEM htItem)
-{
-    SelectItem(hwndTV, htItem, !IsItemSelected(hwndTV, htItem));
-}
-
 // helper function which selects all items in a range and, optionally,
 // unselects all others
 static void SelectRange(HWND hwndTV,
@@ -168,57 +163,56 @@ static void SelectRange(HWND hwndTV,
 // helper function which tricks the standard control into changing the focused
 // item without changing anything else (if someone knows why Microsoft doesn't
 // allow to do it by just setting TVIS_FOCUSED flag, please tell me!)
-static void SetFocus(HWND hwndTV, HTREEITEM htItem)
+//
+// returns true if the focus was changed, false if the given item was already
+// the focused one
+static bool SetFocus(HWND hwndTV, HTREEITEM htItem)
 {
     // the current focus
     HTREEITEM htFocus = (HTREEITEM)TreeView_GetSelection(hwndTV);
 
+    if ( htItem == htFocus )
+        return false;
+
     if ( htItem )
     {
-        // set the focus
-        if ( htItem != htFocus )
-        {
-            // remember the selection state of the item
-            bool wasSelected = IsItemSelected(hwndTV, htItem);
+        // remember the selection state of the item
+        bool wasSelected = IsItemSelected(hwndTV, htItem);
 
-            if ( htFocus && IsItemSelected(hwndTV, htFocus) )
-            {
-                // prevent the tree from unselecting the old focus which it
-                // would do by default (TreeView_SelectItem unselects the
-                // focused item)
-                TreeView_SelectItem(hwndTV, 0);
-                SelectItem(hwndTV, htFocus);
-            }
+        if ( htFocus && IsItemSelected(hwndTV, htFocus) )
+        {
+            // prevent the tree from unselecting the old focus which it
+            // would do by default (TreeView_SelectItem unselects the
+            // focused item)
+            TreeView_SelectItem(hwndTV, 0);
+            SelectItem(hwndTV, htFocus);
+        }
 
-            TreeView_SelectItem(hwndTV, htItem);
+        TreeView_SelectItem(hwndTV, htItem);
 
-            if ( !wasSelected )
-            {
-                // need to clear the selection which TreeView_SelectItem() gave
-                // us
-                UnselectItem(hwndTV, htItem);
-            }
-            //else: was selected, still selected - ok
+        if ( !wasSelected )
+        {
+            // need to clear the selection which TreeView_SelectItem() gave
+            // us
+            UnselectItem(hwndTV, htItem);
         }
-        //else: nothing to do, focus already there
+        //else: was selected, still selected - ok
     }
-    else
+    else // reset focus
     {
-        if ( htFocus )
-        {
-            bool wasFocusSelected = IsItemSelected(hwndTV, htFocus);
+        bool wasFocusSelected = IsItemSelected(hwndTV, htFocus);
 
-            // just clear the focus
-            TreeView_SelectItem(hwndTV, 0);
+        // just clear the focus
+        TreeView_SelectItem(hwndTV, 0);
 
-            if ( wasFocusSelected )
-            {
-                // restore the selection state
-                SelectItem(hwndTV, htFocus);
-            }
+        if ( wasFocusSelected )
+        {
+            // restore the selection state
+            SelectItem(hwndTV, htFocus);
         }
-        //else: nothing to do, no focus already
     }
+
+    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -526,7 +520,9 @@ wxBEGIN_FLAGS( wxTreeCtrlStyle )
     wxFLAGS_MEMBER(wxTR_HAS_VARIABLE_ROW_HEIGHT)
     wxFLAGS_MEMBER(wxTR_SINGLE)
     wxFLAGS_MEMBER(wxTR_MULTIPLE)
+#if WXWIN_COMPATIBILITY_2_8
     wxFLAGS_MEMBER(wxTR_EXTENDED)
+#endif
     wxFLAGS_MEMBER(wxTR_DEFAULT_STYLE)
 
 wxEND_FLAGS( wxTreeCtrlStyle )
@@ -923,7 +919,7 @@ void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
         return;
 
     wxTreeViewItem tvItem(item, TVIF_TEXT);
-    tvItem.pszText = (wxChar *)text.c_str();  // conversion is ok
+    tvItem.pszText = (wxChar *)text.wx_str();  // conversion is ok
     DoSetItem(&tvItem);
 
     // when setting the text of the item being edited, the text control should
@@ -1434,7 +1430,7 @@ wxTreeItemId wxTreeCtrl::DoInsertAfter(const wxTreeItemId& parent,
     if ( !text.empty() )
     {
         mask |= TVIF_TEXT;
-        tvIns.item.pszText = (wxChar *)text.c_str();  // cast is ok
+        tvIns.item.pszText = (wxChar *)text.wx_str();  // cast is ok
     }
     else
     {
@@ -1481,9 +1477,10 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
                                  int image, int selectedImage,
                                  wxTreeItemData *data)
 {
-
     if ( HasFlag(wxTR_HIDE_ROOT) )
     {
+        wxASSERT_MSG( !m_pVirtualRoot, _T("tree can have only a single root") );
+
         // create a virtual root item, the parent for all the others
         wxTreeItemParam *param = new wxTreeItemParam;
         param->SetData(data);
@@ -1666,34 +1663,36 @@ void wxTreeCtrl::UnselectAll()
 
 void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select)
 {
-    if ( m_windowStyle & wxTR_MULTIPLE )
-    {
-        ::SelectItem(GetHwnd(), HITEM(item), select);
-    }
-    else
-    {
-        wxASSERT_MSG( select,
-                      _T("SelectItem(false) works only for multiselect") );
+    wxCHECK_RET( !IsHiddenRoot(item), _T("can't select hidden root item") );
 
-        // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
-        // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
-        // send them ourselves
+    wxASSERT_MSG( select || HasFlag(wxTR_MULTIPLE),
+                  _T("SelectItem(false) works only for multiselect") );
 
-        wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
-        if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
+    wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+    if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
+    {
+        if ( HasFlag(wxTR_MULTIPLE) )
         {
-            if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) )
+            if ( !::SelectItem(GetHwnd(), HITEM(item), select) )
             {
                 wxLogLastError(wxT("TreeView_SelectItem"));
+                return;
             }
-            else // ok
+        }
+        else // single selection
+        {
+            // use TreeView_SelectItem() to deselect the previous selection
+            if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) )
             {
-                event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
-                (void)GetEventHandler()->ProcessEvent(event);
+                wxLogLastError(wxT("TreeView_SelectItem"));
+                return;
             }
         }
-        //else: program vetoed the change
+
+        event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+        (void)GetEventHandler()->ProcessEvent(event);
     }
+    //else: program vetoed the change
 }
 
 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
@@ -2010,7 +2009,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                         SetFocus();
 
                         // toggle selected state
-                        ::ToggleItemSelection(GetHwnd(), htItem);
+                        ToggleItemSelection(htItem);
 
                         ::SetFocus(GetHwnd(), htItem);
 
@@ -2073,6 +2072,14 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                             ::SetFocus(GetHwnd(), htItem);
                             processed = true;
                         }
+                        else // click on a single selected item
+                        {
+                            // don't interfere with the default processing in
+                            // WM_MOUSEMOVE handler below as the default window
+                            // proc will start the drag itself if we let have
+                            // WM_LBUTTONDOWN
+                            m_htClickedItem.Unset();
+                        }
 
                         // reset on any click without Shift
                         m_htSelStart.Unset();
@@ -2087,35 +2094,44 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                     int cx = abs(m_ptClick.x - x);
                     int cy = abs(m_ptClick.y - y);
 
-                    if ( cx > GetSystemMetrics( SM_CXDRAG ) || cy > GetSystemMetrics( SM_CYDRAG ) )
+                    if ( cx > ::GetSystemMetrics(SM_CXDRAG) ||
+                            cy > ::GetSystemMetrics(SM_CYDRAG) )
                     {
-                        HWND pWnd = ::GetParent( GetHwnd() );
-                        if ( pWnd )
-                        {
-                            NM_TREEVIEW tv;
+                        NM_TREEVIEW tv;
+                        wxZeroMemory(tv);
 
-                            tv.hdr.hwndFrom = GetHwnd();
-                            tv.hdr.idFrom = ::GetWindowLong( GetHwnd(), GWL_ID );
-                            tv.hdr.code = TVN_BEGINDRAG;
+                        tv.hdr.hwndFrom = GetHwnd();
+                        tv.hdr.idFrom = ::GetWindowLong(GetHwnd(), GWL_ID);
+                        tv.hdr.code = TVN_BEGINDRAG;
 
-                            tv.itemNew.hItem = HITEM(m_htClickedItem);
+                        tv.itemNew.hItem = HITEM(m_htClickedItem);
 
-                            TVITEM tviAux;
-                            ZeroMemory(&tviAux, sizeof(tviAux));
-                            tviAux.hItem = HITEM(m_htClickedItem);
-                            tviAux.mask = TVIF_STATE | TVIF_PARAM;
-                            tviAux.stateMask = 0xffffffff;
-                            TreeView_GetItem( GetHwnd(), &tviAux );
 
-                            tv.itemNew.state = tviAux.state;
-                            tv.itemNew.lParam = tviAux.lParam;
+                        TVITEM tviAux;
+                        wxZeroMemory(tviAux);
 
-                            tv.ptDrag.x = x;
-                            tv.ptDrag.y = y;
+                        tviAux.hItem = HITEM(m_htClickedItem);
+                        tviAux.mask = TVIF_STATE | TVIF_PARAM;
+                        tviAux.stateMask = 0xffffffff;
+                        TreeView_GetItem(GetHwnd(), &tviAux);
 
-                            ::SendMessage( pWnd, WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );
-                        }
+                        tv.itemNew.state = tviAux.state;
+                        tv.itemNew.lParam = tviAux.lParam;
+
+                        tv.ptDrag.x = x;
+                        tv.ptDrag.y = y;
+
+                        // do it before SendMessage() call below to avoid
+                        // reentrancies here if there is another WM_MOUSEMOVE
+                        // in the queue already
                         m_htClickedItem.Unset();
+
+                        ::SendMessage(GetHwndOf(GetParent()), WM_NOTIFY,
+                                      tv.hdr.idFrom, (LPARAM)&tv );
+
+                        // don't pass it to the default window proc, it would
+                        // start dragging again
+                        processed = true;
                     }
                 }
 #endif // __WXWINCE__
@@ -2206,7 +2222,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
             case VK_SPACE:
                 if ( bCtrl )
                 {
-                    ::ToggleItemSelection(GetHwnd(), htSel);
+                    ToggleItemSelection(htSel);
                 }
                 else
                 {