X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5ece068d9fff3fa17a3ac1deb662c9b8f91836d3..f538710f0b798b21365fd614ba531055b225b115:/src/msw/treectrl.cpp diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 4481d86387..c5c49719b4 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -97,7 +97,6 @@ // looks quite ugly. #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 - // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -401,11 +400,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 @@ -422,10 +422,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 @@ -444,6 +447,7 @@ private: // all the images associated with the item int m_images[wxTreeItemIcon_Max]; + // the real client data wxTreeItemData *m_data; }; @@ -454,15 +458,36 @@ private: 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 } }; +*/ // ============================================================================ // implementation @@ -513,13 +538,12 @@ void wxTreeCtrl::Init() 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; + // 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, @@ -551,14 +575,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 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \ @@ -578,10 +601,10 @@ bool wxTreeCtrl::Create(wxWindow *parent, 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 - 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 @@ -590,7 +613,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); - wxWindow::SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + wxWindow::SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); #endif @@ -966,14 +989,13 @@ wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const return NULL; } - if ( HasIndirectData(item) ) + wxTreeItemData *data = (wxTreeItemData *)tvItem.lParam; + if ( IsDataIndirect(data) ) { - return ((wxTreeItemIndirectData *)tvItem.lParam)->GetData(); - } - else - { - return (wxTreeItemData *)tvItem.lParam; + data = ((wxTreeItemIndirectData *)data)->GetData(); } + + return data; } void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) @@ -1013,14 +1035,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) @@ -1487,17 +1516,15 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag) { wxTreeEvent event(wxEVT_NULL, m_windowId); event.m_item = item; - - bool isExpanded = IsExpanded(item); - 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 } @@ -1738,14 +1765,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, @@ -1767,7 +1817,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 */); } @@ -2095,23 +2145,26 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam; - bool expand = FALSE; + int what; switch ( tv->action ) { + default: + wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv->action); + // fall through + case TVE_EXPAND: - expand = TRUE; + what = IDX_EXPAND; break; case TVE_COLLAPSE: - expand = FALSE; + what = IDX_COLLAPSE; 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; } @@ -2335,13 +2388,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 { @@ -2377,6 +2423,25 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) *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 @@ -2404,7 +2469,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) : wxTreeItemIcon_Selected ); } - } + } break; //default: