X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fbdcff4a78e03963d750546b8a74752247b38d40..51072df23ffcf5bdd4651dbe0ad5143b1e360119:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 2d692a9a85..f6dab4428b 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -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 @@ -27,8 +28,14 @@ #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 +#define wxUSE_COMCTL32_SAFELY 0 + // Mingw32 is a bit mental even though this is done in winundef #ifdef GetFirstChild #undef GetFirstChild @@ -43,16 +50,15 @@ #include "wx/log.h" #include "wx/dynarray.h" #include "wx/imaglist.h" -#include "wx/treectrl.h" #include "wx/settings.h" - +#include "wx/msw/treectrl.h" #include "wx/msw/dragimag.h" #ifdef __GNUWIN32_OLD__ #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 #endif @@ -86,6 +92,7 @@ // looks quite ugly. #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 + // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -112,7 +119,7 @@ static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem) if ( !TreeView_GetItem(hwndTV, &tvi) ) { - wxLogLastError("TreeView_GetItem"); + wxLogLastError(wxT("TreeView_GetItem")); } return (tvi.state & TVIS_SELECTED) != 0; @@ -128,7 +135,7 @@ static void SelectItem(HWND hwndTV, HTREEITEM hItem, bool select = TRUE) if ( TreeView_SetItem(hwndTV, &tvi) == -1 ) { - wxLogLastError("TreeView_SetItem"); + wxLogLastError(wxT("TreeView_SetItem")); } } @@ -366,7 +373,7 @@ public: DoTraverse(root, recursively); } - virtual bool OnVisit(const wxTreeItemId& item) + virtual bool OnVisit(const wxTreeItemId& WXUNUSED(item)) { m_count++; @@ -446,7 +453,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 } @@ -495,11 +502,19 @@ void wxTreeCtrl::Init() { m_imageListNormal = NULL; m_imageListState = NULL; + m_ownsImageListNormal = m_ownsImageListState = FALSE; 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, @@ -516,8 +531,13 @@ bool wxTreeCtrl::Create(wxWindow *parent, return FALSE; DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | - TVS_HASLINES | TVS_SHOWSELALWAYS; + TVS_SHOWSELALWAYS; + + if ( m_windowStyle & wxCLIP_SIBLINGS ) + wstyle |= WS_CLIPSIBLINGS; + if ((m_windowStyle & wxTR_NO_LINES) == 0) + wstyle |= TVS_HASLINES; if ( m_windowStyle & wxTR_HAS_BUTTONS ) wstyle |= TVS_HASBUTTONS; @@ -545,17 +565,23 @@ bool wxTreeCtrl::Create(wxWindow *parent, if ( !MSWCreateControl(WC_TREEVIEW, wstyle) ) return FALSE; -#if 0 +#if wxUSE_COMCTL32_SAFELY + wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + wxWindow::SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); +#elif 1 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); #else // This works around a bug in the Windows tree control whereby for some versions // of comctrl32, setting any colour actually draws the background in black. // This will initialise the background to the system colour. + // 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)); + SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); #endif - SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); // VZ: this is some experimental code which may be used to get the // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71. @@ -631,6 +657,9 @@ wxTreeCtrl::~wxTreeCtrl() // delete user data to prevent memory leaks DeleteAllItems(); + + if (m_ownsImageListNormal) delete m_imageListNormal; + if (m_ownsImageListState) delete m_imageListState; } // ---------------------------------------------------------------------------- @@ -643,7 +672,7 @@ bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const { if ( !TreeView_GetItem(GetHwnd(), tvItem) ) { - wxLogLastError("TreeView_GetItem"); + wxLogLastError(wxT("TreeView_GetItem")); return FALSE; } @@ -655,7 +684,7 @@ void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem) { if ( TreeView_SetItem(GetHwnd(), tvItem) == -1 ) { - wxLogLastError("TreeView_SetItem"); + wxLogLastError(wxT("TreeView_SetItem")); } } @@ -694,12 +723,28 @@ void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which) void wxTreeCtrl::SetImageList(wxImageList *imageList) { + if (m_ownsImageListNormal) delete m_imageListNormal; SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL); + m_ownsImageListNormal = FALSE; } void wxTreeCtrl::SetStateImageList(wxImageList *imageList) { + if (m_ownsImageListState) delete m_imageListState; SetAnyImageList(m_imageListState = imageList, TVSIL_STATE); + m_ownsImageListState = FALSE; +} + +void wxTreeCtrl::AssignImageList(wxImageList *imageList) +{ + SetImageList(imageList); + m_ownsImageListNormal = TRUE; +} + +void wxTreeCtrl::AssignStateImageList(wxImageList *imageList) +{ + SetStateImageList(imageList); + m_ownsImageListState = TRUE; } size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, @@ -716,20 +761,24 @@ size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool wxTreeCtrl::SetBackgroundColour(const wxColour &colour) { +#if !wxUSE_COMCTL32_SAFELY if ( !wxWindowBase::SetBackgroundColour(colour) ) return FALSE; SendMessage(GetHwnd(), TVM_SETBKCOLOR, 0, colour.GetPixel()); +#endif return TRUE; } bool wxTreeCtrl::SetForegroundColour(const wxColour &colour) { +#if !wxUSE_COMCTL32_SAFELY if ( !wxWindowBase::SetForegroundColour(colour) ) return FALSE; SendMessage(GetHwnd(), TVM_SETTEXTCOLOR, 0, colour.GetPixel()); +#endif return TRUE; } @@ -917,6 +966,12 @@ wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) { + // first, associate this piece of data with this item + if ( data ) + { + data->SetId(item); + } + wxTreeViewItem tvItem(item, TVIF_PARAM); if ( HasIndirectData(item) ) @@ -991,6 +1046,7 @@ void wxTreeCtrl::SetItemTextColour(const wxTreeItemId& item, } attr->SetTextColour(col); + Refresh(); } void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, @@ -1007,6 +1063,7 @@ void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, } attr->SetBackgroundColour(col); + Refresh(); } void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) @@ -1022,6 +1079,7 @@ void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) } attr->SetFont(font); + Refresh(); } // ---------------------------------------------------------------------------- @@ -1088,7 +1146,7 @@ wxTreeItemId wxTreeCtrl::GetRootItem() const wxTreeItemId wxTreeCtrl::GetSelection() const { - wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0, + wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (long)(WXHTREEITEM)0, wxT("this only works with single selection controls") ); return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd())); @@ -1151,16 +1209,14 @@ wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const { - wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() " - "for must be visible itself!")); + wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() for must be visible itself!")); return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(GetHwnd(), HITEM(item))); } wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const { - wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() " - "for must be visible itself!")); + wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() for must be visible itself!")); return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), HITEM(item))); } @@ -1228,6 +1284,11 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, mask |= TVIF_TEXT; tvIns.item.pszText = (wxChar *)text.c_str(); // cast is ok } + else + { + tvIns.item.pszText = NULL; + tvIns.item.cchTextMax = 0; + } if ( image != -1 ) { @@ -1258,7 +1319,7 @@ wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent, HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns); if ( id == 0 ) { - wxLogLastError("TreeView_InsertItem"); + wxLogLastError(wxT("TreeView_InsertItem")); } if ( data != NULL ) @@ -1284,7 +1345,7 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, int image, int selectedImage, wxTreeItemData *data) { - return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0, + return DoInsertItem(wxTreeItemId((long) (WXHTREEITEM) 0), (long)(WXHTREEITEM) 0, text, image, selectedImage, data); } @@ -1343,7 +1404,7 @@ void wxTreeCtrl::Delete(const wxTreeItemId& item) { if ( !TreeView_DeleteItem(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_DeleteItem"); + wxLogLastError(wxT("TreeView_DeleteItem")); } } @@ -1366,7 +1427,7 @@ void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item) { if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)children[n]) ) { - wxLogLastError("TreeView_DeleteItem"); + wxLogLastError(wxT("TreeView_DeleteItem")); } } } @@ -1375,7 +1436,7 @@ void wxTreeCtrl::DeleteAllItems() { if ( !TreeView_DeleteAllItems(GetHwnd()) ) { - wxLogLastError("TreeView_DeleteAllItems"); + wxLogLastError(wxT("TreeView_DeleteAllItems")); } } @@ -1449,7 +1510,7 @@ void wxTreeCtrl::Unselect() wxT("doesn't make sense, may be you want UnselectAll()?") ); // just remove the selection - SelectItem(wxTreeItemId((WXHTREEITEM) 0)); + SelectItem(wxTreeItemId((long) (WXHTREEITEM) 0)); } void wxTreeCtrl::UnselectAll() @@ -1500,7 +1561,7 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item) { if ( !TreeView_SelectItem(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_SelectItem"); + wxLogLastError(wxT("TreeView_SelectItem")); } else { @@ -1522,7 +1583,7 @@ void wxTreeCtrl::ScrollTo(const wxTreeItemId& item) { if ( !TreeView_SelectSetFirstVisible(GetHwnd(), HITEM(item)) ) { - wxLogLastError("TreeView_SelectSetFirstVisible"); + wxLogLastError(wxT("TreeView_SelectSetFirstVisible")); } } @@ -1553,6 +1614,14 @@ void wxTreeCtrl::DeleteTextCtrl() { if ( m_textCtrl ) { + // the HWND corresponding to this control is deleted by the tree + // control itself and we don't know when exactly this happens, so check + // if the window still exists before calling UnsubclassWin() + if ( !::IsWindow(GetHwndOf(m_textCtrl)) ) + { + m_textCtrl->SetHWND(0); + } + m_textCtrl->UnsubclassWin(); m_textCtrl->SetHWND(0); delete m_textCtrl; @@ -1577,6 +1646,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); @@ -1584,7 +1654,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); @@ -1924,25 +1994,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) switch ( hdr->code ) { - case NM_RCLICK: - { - if ( wxControl::MSWOnNotify(idCtrl, lParam, result) ) - return TRUE; - - TV_HITTESTINFO tvhti; - ::GetCursorPos(&(tvhti.pt)); - ::ScreenToClient(GetHwnd(),&(tvhti.pt)); - if ( TreeView_HitTest(GetHwnd(),&tvhti) ) - { - if( tvhti.flags & TVHT_ONITEM ) - { - event.m_item = (WXHTREEITEM) tvhti.hItem; - eventType = wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK; - } - } - } - break; - case TVN_BEGINDRAG: eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG; // fall through @@ -2019,9 +2070,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; @@ -2038,8 +2086,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; default: - wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND " - "message"), tv->action); + wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv->action); } bool ing = ((int)hdr->code == TVN_ITEMEXPANDING); @@ -2054,7 +2101,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() && @@ -2091,19 +2144,19 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) } break; -#if defined(_WIN32_IE) && _WIN32_IE >= 0x300 +#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: { @@ -2113,7 +2166,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; @@ -2176,18 +2230,42 @@ 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: + case NM_RCLICK: + { + TV_HITTESTINFO tvhti; + ::GetCursorPos(&tvhti.pt); + ::ScreenToClient(GetHwnd(), &tvhti.pt); + if ( TreeView_HitTest(GetHwnd(), &tvhti) ) + { + if ( tvhti.flags & TVHT_ONITEM ) + { + event.m_item = (WXHTREEITEM) tvhti.hItem; + eventType = (int)hdr->code == NM_DBLCLK + ? wxEVT_COMMAND_TREE_ITEM_ACTIVATED + : wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK; + + event.m_pointDrag.x = tvhti.pt.x; + event.m_pointDrag.y = tvhti.pt.y; + } + + break; + } + } + // fall through + default: return wxControl::MSWOnNotify(idCtrl, lParam, result); } @@ -2200,6 +2278,14 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // post processing switch ( hdr->code ) { + case NM_DBLCLK: + // we translate NM_DBLCLK into ACTIVATED event, so don't interpret + // the return code of this event handler as the return value for + // NM_DBLCLK - otherwise, double clicking the item to toggle its + // expanded status would never work + *result = FALSE; + break; + case TVN_BEGINDRAG: case TVN_BEGINRDRAG: if ( event.IsAllowed() ) @@ -2230,6 +2316,11 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) 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 { @@ -2247,8 +2338,12 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; case TVN_ENDLABELEDIT: - // return TRUE to set the label to the new string + // return TRUE to set the label to the new string: note that we + // also must pretend that we did process the message or it is going + // to be passed to DefWindowProc() which will happily return FALSE + // cancelling the label change *result = event.IsAllowed(); + processed = TRUE; // ensure that we don't have the text ctrl which is going to be // deleted any more @@ -2264,7 +2359,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; @@ -2288,7 +2383,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) : wxTreeItemIcon_Selected ); } - } + } break; //default: @@ -2299,18 +2394,6 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) return processed; } -// ---------------------------------------------------------------------------- -// Tree event -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent) - -wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) - : wxNotifyEvent(commandType, id) -{ - m_code = 0; - m_itemOld = 0; -} - #endif // __WIN95__ +#endif // wxUSE_TREECTRL