1. Added m_count and maintain its value in InsertItem, RemoveItem
etc. and return it from GetItemCount to save so many calls to ListView_GetItemCount. 2. If EVT_LIST_DELETE_ALL_ITEMS was not handled then the post-processing code to prevent LVN_DELETEITEM messages was not getting executed. Changed it so the post processing always happens. 3. It's possible with some versions of comctl32 that garbage values can be passed in nmLV->lParam so don't try to get the internal item data pointer from it. This should close bug# 659939 4. Added FreeAllInternalData from DeleteAllItems, (part of patch #672065) and also guard against processing LVN_CHANG* messages while freeing the internal data. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@19021 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -370,6 +370,9 @@ protected:
|
|||||||
long m_baseStyle; // Basic Windows style flags, for recreation purposes
|
long m_baseStyle; // Basic Windows style flags, for recreation purposes
|
||||||
int m_colCount; // Windows doesn't have GetColumnCount so must
|
int m_colCount; // Windows doesn't have GetColumnCount so must
|
||||||
// keep track of inserted/deleted columns
|
// keep track of inserted/deleted columns
|
||||||
|
long m_count; // Keep track of item count to save calls to
|
||||||
|
// ListView_GetItemCount
|
||||||
|
bool m_ignoreChangeMessages;
|
||||||
|
|
||||||
// TRUE if we have any internal data (user data & attributes)
|
// TRUE if we have any internal data (user data & attributes)
|
||||||
bool m_AnyInternalData;
|
bool m_AnyInternalData;
|
||||||
|
@@ -244,6 +244,8 @@ void wxListCtrl::Init()
|
|||||||
m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
|
m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
|
||||||
m_baseStyle = 0;
|
m_baseStyle = 0;
|
||||||
m_colCount = 0;
|
m_colCount = 0;
|
||||||
|
m_count = 0;
|
||||||
|
m_ignoreChangeMessages = FALSE;
|
||||||
m_textCtrl = NULL;
|
m_textCtrl = NULL;
|
||||||
m_AnyInternalData = FALSE;
|
m_AnyInternalData = FALSE;
|
||||||
m_hasAnyAttr = FALSE;
|
m_hasAnyAttr = FALSE;
|
||||||
@@ -378,8 +380,10 @@ void wxListCtrl::FreeAllInternalData()
|
|||||||
int n = GetItemCount();
|
int n = GetItemCount();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
m_ignoreChangeMessages = TRUE;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
wxDeleteInternalData(this, i);
|
wxDeleteInternalData(this, i);
|
||||||
|
m_ignoreChangeMessages = TRUE;
|
||||||
|
|
||||||
m_AnyInternalData = FALSE;
|
m_AnyInternalData = FALSE;
|
||||||
}
|
}
|
||||||
@@ -1014,7 +1018,7 @@ bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
|
|||||||
// Gets the number of items in the list control
|
// Gets the number of items in the list control
|
||||||
int wxListCtrl::GetItemCount() const
|
int wxListCtrl::GetItemCount() const
|
||||||
{
|
{
|
||||||
return ListView_GetItemCount(GetHwnd());
|
return m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the spacing between icons in pixels.
|
// Retrieves the spacing between icons in pixels.
|
||||||
@@ -1204,6 +1208,10 @@ bool wxListCtrl::DeleteItem(long item)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_count -= 1;
|
||||||
|
wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
|
||||||
|
wxT("m_count should match ListView_GetItemCount"));
|
||||||
|
|
||||||
// the virtual list control doesn't refresh itself correctly, help it
|
// the virtual list control doesn't refresh itself correctly, help it
|
||||||
if ( IsVirtual() )
|
if ( IsVirtual() )
|
||||||
{
|
{
|
||||||
@@ -1232,6 +1240,7 @@ bool wxListCtrl::DeleteItem(long item)
|
|||||||
// Deletes all items
|
// Deletes all items
|
||||||
bool wxListCtrl::DeleteAllItems()
|
bool wxListCtrl::DeleteAllItems()
|
||||||
{
|
{
|
||||||
|
FreeAllInternalData();
|
||||||
return ListView_DeleteAllItems(GetHwnd()) != 0;
|
return ListView_DeleteAllItems(GetHwnd()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1448,8 +1457,12 @@ long wxListCtrl::InsertItem(wxListItem& info)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
long rv = ListView_InsertItem(GetHwnd(), & item);
|
||||||
|
m_count += 1;
|
||||||
|
wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
|
||||||
|
wxT("m_count should match ListView_GetItemCount"));
|
||||||
|
|
||||||
return (long) ListView_InsertItem(GetHwnd(), & item);
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
long wxListCtrl::InsertItem(long index, const wxString& label)
|
long wxListCtrl::InsertItem(long index, const wxString& label)
|
||||||
@@ -1641,6 +1654,7 @@ bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id)
|
|||||||
|
|
||||||
bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
||||||
{
|
{
|
||||||
|
|
||||||
// prepare the event
|
// prepare the event
|
||||||
// -----------------
|
// -----------------
|
||||||
|
|
||||||
@@ -1770,53 +1784,29 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
|||||||
|
|
||||||
const int iItem = nmLV->iItem;
|
const int iItem = nmLV->iItem;
|
||||||
|
|
||||||
// set the data event field for all messages for which the system gives
|
|
||||||
// us a valid NM_LISTVIEW::lParam
|
// FreeAllInternalData will cause LVN_ITEMCHANG* messages, which can be
|
||||||
switch ( nmLV->hdr.code )
|
// ignored for efficiency. It is done here because the internal data is in the
|
||||||
|
// process of being deleted so we don't want to try and access it below.
|
||||||
|
if ( m_ignoreChangeMessages &&
|
||||||
|
( (nmLV->hdr.code == LVN_ITEMCHANGED) || (nmLV->hdr.code == LVN_ITEMCHANGING)))
|
||||||
{
|
{
|
||||||
case LVN_BEGINDRAG:
|
return TRUE;
|
||||||
case LVN_BEGINRDRAG:
|
|
||||||
case LVN_COLUMNCLICK:
|
|
||||||
case LVN_ITEMCHANGED:
|
|
||||||
case LVN_ITEMCHANGING:
|
|
||||||
if ( iItem != -1 )
|
|
||||||
{
|
|
||||||
if ( iItem >= GetItemCount() )
|
|
||||||
{
|
|
||||||
// there is apparently a bug in comctl32.dll version
|
|
||||||
// 5.50.4704.1100 (note that the MS DLL database
|
|
||||||
// doesn't say what this version is, it's not the one
|
|
||||||
// shipped with W2K although the bug was reported under
|
|
||||||
// that system) and it sends us LVN_ITEMCHANGING
|
|
||||||
// notifications with the item out of range -- and as
|
|
||||||
// we access the items client data, we crash below
|
|
||||||
//
|
|
||||||
// see
|
|
||||||
//
|
|
||||||
// http://lists.wxwindows.org/cgi-bin/ezmlm-cgi?8:mss:29852:knlihdmadhaljafjajei
|
|
||||||
//
|
|
||||||
// and the thread continuation for more details
|
|
||||||
// (although note that the bug may be present in other
|
|
||||||
// versions of comctl32.dll as well as it has been
|
|
||||||
// reported quite a few times)
|
|
||||||
//
|
|
||||||
// to fix this, simply ignore these "bad" events (as
|
|
||||||
// above with HDN_GETDISPINFOW)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxListItemInternalData *internaldata =
|
|
||||||
(wxListItemInternalData *) nmLV->lParam;
|
|
||||||
|
|
||||||
if ( internaldata )
|
|
||||||
event.m_item.m_data = internaldata->lParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
// fall through
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If we have a valid item then check if there is a data value
|
||||||
|
// associated with it and put it in the event.
|
||||||
|
if ( iItem >= 0 && iItem < GetItemCount() )
|
||||||
|
{
|
||||||
|
wxListItemInternalData *internaldata =
|
||||||
|
wxGetInternalData(GetHwnd(), iItem);
|
||||||
|
|
||||||
|
if ( internaldata )
|
||||||
|
event.m_item.m_data = internaldata->lParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch ( nmhdr->code )
|
switch ( nmhdr->code )
|
||||||
{
|
{
|
||||||
case LVN_BEGINRDRAG:
|
case LVN_BEGINRDRAG:
|
||||||
@@ -1885,11 +1875,17 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LVN_DELETEALLITEMS:
|
case LVN_DELETEALLITEMS:
|
||||||
|
m_count = 0;
|
||||||
eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
|
eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
|
||||||
event.m_itemIndex = -1;
|
event.m_itemIndex = -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LVN_DELETEITEM:
|
case LVN_DELETEITEM:
|
||||||
|
if (m_count == 0)
|
||||||
|
// this should be prevented by the post-processing code below,
|
||||||
|
// but "just in case"
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
|
eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
|
||||||
event.m_itemIndex = iItem;
|
event.m_itemIndex = iItem;
|
||||||
// delete the assoicated internal data
|
// delete the assoicated internal data
|
||||||
@@ -2133,12 +2129,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
|||||||
|
|
||||||
event.SetEventType(eventType);
|
event.SetEventType(eventType);
|
||||||
|
|
||||||
if ( !GetEventHandler()->ProcessEvent(event) )
|
bool processed = GetEventHandler()->ProcessEvent(event);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// post processing
|
// post processing
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
switch ( nmhdr->code )
|
switch ( nmhdr->code )
|
||||||
{
|
{
|
||||||
case LVN_DELETEALLITEMS:
|
case LVN_DELETEALLITEMS:
|
||||||
@@ -2146,7 +2140,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
|||||||
// notifications - this makes deleting all items from a list ctrl
|
// notifications - this makes deleting all items from a list ctrl
|
||||||
// much faster
|
// much faster
|
||||||
*result = TRUE;
|
*result = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
case LVN_ENDLABELEDITA:
|
case LVN_ENDLABELEDITA:
|
||||||
@@ -2168,9 +2161,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*result = !event.IsAllowed();
|
if ( processed )
|
||||||
|
*result = !event.IsAllowed();
|
||||||
|
|
||||||
return TRUE;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32_IE) && _WIN32_IE >= 0x300
|
#if defined(_WIN32_IE) && _WIN32_IE >= 0x300
|
||||||
@@ -2370,6 +2364,9 @@ void wxListCtrl::SetItemCount(long count)
|
|||||||
{
|
{
|
||||||
wxLogLastError(_T("ListView_SetItemCount"));
|
wxLogLastError(_T("ListView_SetItemCount"));
|
||||||
}
|
}
|
||||||
|
m_count = count;
|
||||||
|
wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
|
||||||
|
wxT("m_count should match ListView_GetItemCount"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxListCtrl::RefreshItem(long item)
|
void wxListCtrl::RefreshItem(long item)
|
||||||
|
Reference in New Issue
Block a user