X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/31cc5049d386913adeba034e499e3c181ad54a50..9741fd45f734ea30e094f5b15f092b8394621204:/src/msw/listctrl.cpp diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index d3ec4279ed..484443466f 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -142,7 +142,7 @@ public: // init without conversion void Init(LV_ITEM_NATIVE& item) { - wxASSERT_MSG( !m_pItem, _T("Init() called twice?") ); + wxASSERT_MSG( !m_pItem, wxT("Init() called twice?") ); m_pItem = &item; } @@ -224,11 +224,6 @@ public: wxDECLARE_NO_COPY_CLASS(wxMSWListItemData); }; -// Get the internal data structure -static wxMSWListItemData *wxGetInternalData(HWND hwnd, long itemId); -static wxMSWListItemData *wxGetInternalData(const wxListCtrl *ctl, long itemId); - - #if wxUSE_EXTENDED_RTTI WX_DEFINE_FLAGS( wxListCtrlStyle ) @@ -404,7 +399,7 @@ WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const MAP_MODE_STYLE(wxLC_REPORT, LVS_REPORT) wxASSERT_MSG( nModes == 1, - _T("wxListCtrl style should have exactly one mode bit set") ); + wxT("wxListCtrl style should have exactly one mode bit set") ); #undef MAP_MODE_STYLE @@ -434,7 +429,7 @@ WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const wstyle |= LVS_SORTASCENDING; wxASSERT_MSG( !(style & wxLC_SORT_DESCENDING), - _T("can't sort in ascending and descending orders at once") ); + wxT("can't sort in ascending and descending orders at once") ); } else if ( style & wxLC_SORT_DESCENDING ) wstyle |= LVS_SORTDESCENDING; @@ -502,8 +497,7 @@ void wxListCtrl::DeleteEditControl() { m_textCtrl->UnsubclassWin(); m_textCtrl->SetHWND(0); - delete m_textCtrl; - m_textCtrl = NULL; + wxDELETE(m_textCtrl); } } @@ -708,7 +702,7 @@ int wxListCtrl::GetColumnIndexFromOrder(int order) const { const int numCols = GetColumnCount(); wxCHECK_MSG( order >= 0 && order < numCols, -1, - _T("Column position out of bounds") ); + wxT("Column position out of bounds") ); wxArrayInt indexArray(numCols); if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) ) @@ -720,7 +714,7 @@ int wxListCtrl::GetColumnIndexFromOrder(int order) const int wxListCtrl::GetColumnOrder(int col) const { const int numCols = GetColumnCount(); - wxASSERT_MSG( col >= 0 && col < numCols, _T("Column index out of bounds") ); + wxASSERT_MSG( col >= 0 && col < numCols, wxT("Column index out of bounds") ); wxArrayInt indexArray(numCols); if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) ) @@ -732,7 +726,7 @@ int wxListCtrl::GetColumnOrder(int col) const return pos; } - wxFAIL_MSG( _T("no column with with given order?") ); + wxFAIL_MSG( wxT("no column with with given order?") ); return -1; } @@ -755,7 +749,7 @@ bool wxListCtrl::SetColumnsOrder(const wxArrayInt& orders) const int numCols = GetColumnCount(); wxCHECK_MSG( orders.size() == (size_t)numCols, false, - _T("wrong number of elements in column orders array") ); + wxT("wrong number of elements in column orders array") ); return ListView_SetColumnOrderArray(GetHwnd(), numCols, &orders[0]) != 0; } @@ -850,7 +844,7 @@ bool wxListCtrl::SetItem(wxListItem& info) { const long id = info.GetId(); wxCHECK_MSG( id >= 0 && id < GetItemCount(), false, - _T("invalid item index in SetItem") ); + wxT("invalid item index in SetItem") ); LV_ITEM item; wxConvertToMSWListItem(this, info, item); @@ -899,7 +893,7 @@ bool wxListCtrl::SetItem(wxListItem& info) { if ( !ListView_SetItem(GetHwnd(), &item) ) { - wxLogDebug(_T("ListView_SetItem() failed")); + wxLogDebug(wxT("ListView_SetItem() failed")); return false; } @@ -987,7 +981,7 @@ bool wxListCtrl::SetItemState(long item, long state, long stateMask) if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE, (WPARAM)item, (LPARAM)&lvItem) ) { - wxLogLastError(_T("ListView_SetItemState")); + wxLogLastError(wxT("ListView_SetItemState")); return false; } @@ -1036,12 +1030,13 @@ bool wxListCtrl::SetItemColumnImage(long item, long column, int image) } // Gets the item text -wxString wxListCtrl::GetItemText(long item) const +wxString wxListCtrl::GetItemText(long item, int col) const { wxListItem info; info.m_mask = wxLIST_MASK_TEXT; info.m_itemId = item; + info.m_col = col; if (!GetItem(info)) return wxEmptyString; @@ -1110,7 +1105,7 @@ wxRect wxListCtrl::GetViewRect() const RECT rc; if ( !ListView_GetViewRect(GetHwnd(), &rc) ) { - wxLogDebug(_T("ListView_GetViewRect() failed.")); + wxLogDebug(wxT("ListView_GetViewRect() failed.")); wxZeroMemory(rc); } @@ -1132,7 +1127,7 @@ wxRect wxListCtrl::GetViewRect() const } else { - wxFAIL_MSG( _T("not implemented in this mode") ); + wxFAIL_MSG( wxT("not implemented in this mode") ); } return rect; @@ -1151,11 +1146,11 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) // completely bogus in this case), so we check item validity ourselves wxCHECK_MSG( subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM || (subItem >= 0 && subItem < GetColumnCount()), - false, _T("invalid sub item index") ); + false, wxT("invalid sub item index") ); // use wxCHECK_MSG against "item" too, for coherency with the generic implementation: wxCHECK_MSG( item >= 0 && item < GetItemCount(), false, - _T("invalid item in GetSubItemRect") ); + wxT("invalid item in GetSubItemRect") ); int codeWin; if ( code == wxLIST_RECT_BOUNDS ) @@ -1166,7 +1161,7 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) codeWin = LVIR_LABEL; else { - wxFAIL_MSG( _T("incorrect code in GetItemRect() / GetSubItemRect()") ); + wxFAIL_MSG( wxT("incorrect code in GetItemRect() / GetSubItemRect()") ); codeWin = LVIR_BOUNDS; } @@ -1188,7 +1183,7 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) // there is no way to retrieve the first sub item bounding rectangle using // wxGetListCtrlSubItemRect() as 0 means the whole item, so we need to // truncate it at first column ourselves - if ( subItem == 0 ) + if ( subItem == 0 && code == wxLIST_RECT_BOUNDS ) rect.width = GetColumnWidth(0); return true; @@ -1433,7 +1428,7 @@ bool wxListCtrl::DeleteItem(long item) { if ( !ListView_DeleteItem(GetHwnd(), (int) item) ) { - wxLogLastError(_T("ListView_DeleteItem")); + wxLogLastError(wxT("ListView_DeleteItem")); return false; } @@ -1543,8 +1538,7 @@ wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass) if ( !hWnd ) { // failed to start editing - delete m_textCtrl; - m_textCtrl = NULL; + wxDELETE(m_textCtrl); return NULL; } @@ -1565,14 +1559,21 @@ bool wxListCtrl::EndEditLabel(bool cancel) if ( !hwnd ) return false; - if ( cancel ) - ::SetWindowText(hwnd, wxEmptyString); // dubious but better than nothing - - // we shouldn't destroy the control ourselves according to MSDN, which - // proposes WM_CANCELMODE to do this, but it doesn't seem to work - // - // posting WM_CLOSE to it does seem to work without any side effects - ::PostMessage(hwnd, WM_CLOSE, 0, 0); + // Newer versions of Windows have a special message for cancelling editing, + // use it if available. +#ifdef ListView_CancelEditLabel + if ( cancel && (wxApp::GetComCtl32Version() >= 600) ) + { + ListView_CancelEditLabel(GetHwnd()); + } + else +#endif // ListView_CancelEditLabel + { + // We shouldn't destroy the control ourselves according to MSDN, which + // proposes WM_CANCELMODE to do this, but it doesn't seem to work so + // emulate the corresponding user action instead. + ::SendMessage(hwnd, WM_KEYDOWN, cancel ? VK_ESCAPE : VK_RETURN, 0); + } return true; } @@ -1727,7 +1728,7 @@ wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const // -1 otherwise. long wxListCtrl::InsertItem(const wxListItem& info) { - wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") ); + wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") ); LV_ITEM item; wxConvertToMSWListItem(this, info, item); @@ -1758,7 +1759,10 @@ long wxListCtrl::InsertItem(const wxListItem& info) } } - long rv = ListView_InsertItem(GetHwnd(), & item); + const long rv = ListView_InsertItem(GetHwnd(), & item); + + // failing to insert the item is really unexpected + wxCHECK_MSG( rv != -1, rv, "failed to insert an item in wxListCtrl" ); m_count++; wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()), @@ -1849,7 +1853,7 @@ bool wxListCtrl::ScrollList(int dx, int dy) { if ( !ListView_Scroll(GetHwnd(), dx, dy) ) { - wxLogDebug(_T("ListView_Scroll(%d, %d) failed"), dx, dy); + wxLogDebug(wxT("ListView_Scroll(%d, %d) failed"), dx, dy); return false; } @@ -1904,7 +1908,7 @@ bool wxListCtrl::SortItems(wxListCtrlCompare fn, wxIntPtr data) wxInternalDataCompareFunc, (WPARAM) &internalData) ) { - wxLogDebug(_T("ListView_SortItems() failed")); + wxLogDebug(wxT("ListView_SortItems() failed")); return false; } @@ -1970,7 +1974,7 @@ int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick) #endif //__WXWINCE__ if ( !::GetCursorPos(ptClick) ) { - wxLogLastError(_T("GetCursorPos")); + wxLogLastError(wxT("GetCursorPos")); } // we need to use listctrl coordinates for the event point so this is what @@ -1979,12 +1983,12 @@ int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick) POINT ptClickHeader = *ptClick; if ( !::ScreenToClient(nmhdr->hwndFrom, &ptClickHeader) ) { - wxLogLastError(_T("ScreenToClient(listctrl header)")); + wxLogLastError(wxT("ScreenToClient(listctrl header)")); } if ( !::ScreenToClient(::GetParent(nmhdr->hwndFrom), ptClick) ) { - wxLogLastError(_T("ScreenToClient(listctrl)")); + wxLogLastError(wxT("ScreenToClient(listctrl)")); } const int colCount = Header_GetItemCount(nmhdr->hwndFrom); @@ -2031,29 +2035,50 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) event.m_itemIndex = -1; + bool ignore = false; switch ( nmhdr->code ) { // yet another comctl32.dll bug: under NT/W2K it sends Unicode // TRACK messages even to ANSI programs: on my system I get - // HDN_BEGINTRACKW and HDN_ENDTRACKA and no HDN_TRACK at all! + // HDN_BEGINTRACKW and HDN_ENDTRACKA! // // work around is to simply catch both versions and hope that it // works (why should this message exist in ANSI and Unicode is // beyond me as it doesn't deal with strings at all...) // - // note that fr HDN_TRACK another possibility could be to use - // HDN_ITEMCHANGING but it is sent even after HDN_ENDTRACK and when - // something other than the item width changes so we'd have to - // filter out the unwanted events then + // another problem is that HDN_TRACK is not sent at all by header + // with HDS_FULLDRAG style which is used by default by wxListCtrl + // under recent Windows versions (starting from at least XP) so we + // need to use HDN_ITEMCHANGING instead of it case HDN_BEGINTRACKA: case HDN_BEGINTRACKW: eventType = wxEVT_COMMAND_LIST_COL_BEGIN_DRAG; // fall through - case HDN_TRACKA: - case HDN_TRACKW: + case HDN_ITEMCHANGING: if ( eventType == wxEVT_NULL ) + { + if ( !nmHDR->pitem || !(nmHDR->pitem->mask & HDI_WIDTH) ) + { + // something other than the width is being changed, + // ignore it + ignore = true; + break; + } + + // also ignore the events sent when the width didn't really + // change: this is not just an optimization but also gets + // rid of a useless and unexpected DRAGGING event which + // would otherwise be sent after the END_DRAG one as we get + // an HDN_ITEMCHANGING after HDN_ENDTRACK for some reason + if ( nmHDR->pitem->cxy == GetColumnWidth(nmHDR->iItem) ) + { + ignore = true; + break; + } + eventType = wxEVT_COMMAND_LIST_COL_DRAGGING; + } // fall through case HDN_ENDTRACKA: @@ -2091,8 +2116,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) return true; default: - return wxControl::MSWOnNotify(idCtrl, lParam, result); + ignore = true; } + + if ( ignore ) + return wxControl::MSWOnNotify(idCtrl, lParam, result); } else #endif // defined(HDN_BEGINTRACKA) @@ -2216,8 +2244,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( m_internalData[n] == data ) { m_internalData.erase(m_internalData.begin() + n); - delete data; - data = NULL; + wxDELETE(data); break; } } @@ -2367,13 +2394,18 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxZeroMemory(lvhti); #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400 - if(nmhdr->code == GN_CONTEXTMENU) { - lvhti.pt = ((NMRGINFO*)nmhdr)->ptAction; - } else + if ( nmhdr->code == GN_CONTEXTMENU ) + { + lvhti.pt = ((NMRGINFO*)nmhdr)->ptAction; + } + else #endif //__WXWINCE__ - ::GetCursorPos(&(lvhti.pt)); - ::ScreenToClient(GetHwnd(),&(lvhti.pt)); - if ( ListView_HitTest(GetHwnd(),&lvhti) != -1 ) + { + ::GetCursorPos(&(lvhti.pt)); + } + + ::ScreenToClient(GetHwnd(), &lvhti.pt); + if ( ListView_HitTest(GetHwnd(), &lvhti) != -1 ) { if ( lvhti.flags & LVHT_ONITEM ) { @@ -2443,7 +2475,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) const int startPos = pFindInfo->iStart; const int maxPos = GetItemCount(); wxCHECK_MSG( startPos <= maxPos, false, - _T("bad starting position in LVN_ODFINDITEM") ); + wxT("bad starting position in LVN_ODFINDITEM") ); int currentPos = startPos; do @@ -2451,7 +2483,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // wrap to the beginning if necessary if ( currentPos == maxPos ) { - // somewhat surprizingly, LVFI_WRAP isn't set in + // somewhat surprisingly, LVFI_WRAP isn't set in // flags but we still should wrap currentPos = 0; } @@ -2537,6 +2569,17 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) event.SetEventType(eventType); + // fill in the item before passing it to the event handler if we do have a + // valid item index and haven't filled it yet (e.g. for LVN_ITEMCHANGED) + if ( event.m_itemIndex != -1 && !event.m_item.GetMask() ) + { + wxListItem& item = event.m_item; + + item.SetId(event.m_itemIndex); + item.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE | wxLIST_MASK_DATA); + GetItem(item); + } + bool processed = HandleWindowEvent(event); // post processing @@ -2937,7 +2980,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) numCols, &indexArray[0]) ) { - wxFAIL_MSG( _T("invalid column index array in OnPaint()") ); + wxFAIL_MSG( wxT("invalid column index array in OnPaint()") ); return; } @@ -2987,7 +3030,7 @@ wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) cons { // this is a pure virtual function, in fact - which is not really pure // because the controls which are not virtual don't need to implement it - wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") ); + wxFAIL_MSG( wxT("wxListCtrl::OnGetItemText not supposed to be called") ); return wxEmptyString; } @@ -3011,7 +3054,7 @@ int wxListCtrl::OnGetItemColumnImage(long item, long column) const wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const { wxASSERT_MSG( item >= 0 && item < GetItemCount(), - _T("invalid item index in OnGetItemAttr()") ); + wxT("invalid item index in OnGetItemAttr()") ); // no attributes by default return NULL; @@ -3028,12 +3071,12 @@ wxListItemAttr *wxListCtrl::DoGetItemColumnAttr(long item, long column) const void wxListCtrl::SetItemCount(long count) { - wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); + wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") ); if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT, (WPARAM)count, LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL) ) { - wxLogLastError(_T("ListView_SetItemCount")); + wxLogLastError(wxT("ListView_SetItemCount")); } m_count = count; wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),