comctl32: Use single notification message for setting all item state with LVM_SETITEMSTATE (LVS_OWNERDATA case only).

This commit is contained in:
Nikolay Sivov 2012-03-20 10:17:47 +03:00 committed by Alexandre Julliard
parent 1478648b9f
commit b326426fec
2 changed files with 134 additions and 37 deletions

View File

@ -8809,26 +8809,31 @@ static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, const PO
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] nItem : item index
* [I] lpLVItem : item or subitem info
* [I] item : item or subitem info
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem)
static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *item)
{
BOOL bResult = TRUE;
BOOL ret = TRUE;
LVITEMW lvItem;
if (!item) return FALSE;
lvItem.iItem = nItem;
lvItem.iSubItem = 0;
lvItem.mask = LVIF_STATE;
lvItem.state = lpLVItem->state;
lvItem.stateMask = lpLVItem->stateMask;
TRACE("lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
lvItem.state = item->state;
lvItem.stateMask = item->stateMask;
TRACE("item=%s\n", debuglvitem_t(&lvItem, TRUE));
if (nItem == -1)
{
UINT oldstate = 0;
BOOL notify;
/* select all isn't allowed in LVS_SINGLESEL */
if ((lvItem.state & lvItem.stateMask & LVIS_SELECTED) && (infoPtr->dwStyle & LVS_SINGLESEL))
return FALSE;
@ -8836,14 +8841,40 @@ static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITE
/* focus all isn't allowed */
if (lvItem.state & lvItem.stateMask & LVIS_FOCUSED) return FALSE;
notify = infoPtr->bDoChangeNotify;
if (infoPtr->dwStyle & LVS_OWNERDATA)
{
infoPtr->bDoChangeNotify = FALSE;
if (!(lvItem.state & LVIS_SELECTED) && LISTVIEW_GetSelectedCount(infoPtr))
oldstate |= LVIS_SELECTED;
if (infoPtr->nFocusedItem != -1) oldstate |= LVIS_FOCUSED;
}
/* apply to all items */
for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++)
if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) bResult = FALSE;
if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) ret = FALSE;
if (infoPtr->dwStyle & LVS_OWNERDATA)
{
NMLISTVIEW nmlv;
infoPtr->bDoChangeNotify = notify;
nmlv.iItem = -1;
nmlv.iSubItem = 0;
nmlv.uNewState = lvItem.state & lvItem.stateMask;
nmlv.uOldState = oldstate & lvItem.stateMask;
nmlv.uChanged = LVIF_STATE;
nmlv.ptAction.x = nmlv.ptAction.y = 0;
nmlv.lParam = 0;
notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
}
}
else
bResult = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE);
ret = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE);
return bResult;
return ret;
}
/***
@ -11410,7 +11441,6 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, (POINT*)lParam);
case LVM_SETITEMSTATE:
if (lParam == 0) return FALSE;
return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam);
case LVM_SETITEMTEXTA:

View File

@ -3,7 +3,7 @@
*
* Copyright 2006 Mike McCormack for CodeWeavers
* Copyright 2007 George Gov
* Copyright 2009-2011 Nikolay Sivov
* Copyright 2009-2012 Nikolay Sivov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -50,11 +50,11 @@ static HWND hwndparent, hwndparentW;
static BOOL blockEdit;
/* return nonzero on NM_HOVER */
static BOOL g_block_hover;
/* dumps LVN_ITEMCHANGED message data */
static BOOL g_dump_itemchanged;
/* notification data for LVN_ITEMCHANGED */
static NMLISTVIEW g_nmlistview;
/* format reported to control:
-1 falls to defproc, anything else returned */
static INT notifyFormat;
static INT notifyFormat;
/* indicates we're running < 5.80 version */
static BOOL g_is_below_5;
/* item data passed to LVN_GETDISPINFOA */
@ -391,11 +391,9 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
}
break;
case LVN_ITEMCHANGED:
if (g_dump_itemchanged)
{
NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
g_nmlistview = *nmlv;
}
break;
case LVN_GETDISPINFOA:
@ -2768,35 +2766,68 @@ static void test_ownerdata(void)
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
"ownerdata select all notification", TRUE);
"ownerdata select all notification", FALSE);
/* select all again, note that all items are selected already */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
"ownerdata select all notification", TRUE);
"ownerdata select all notification", FALSE);
/* deselect all */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_SELECTED;
item.state = 0;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
"ownerdata deselect all notification", TRUE);
/* nothing selected, deselect all again */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_SELECTED;
item.state = 0;
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", TRUE);
/* select one, then deselect all */
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
@ -2805,10 +2836,18 @@ static void test_ownerdata(void)
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_SELECTED;
item.state = 0;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
"ownerdata select all notification", TRUE);
@ -2824,16 +2863,18 @@ static void test_ownerdata(void)
item.stateMask = LVIS_FOCUSED;
res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
expect(0, res);
/* setting all to focused returns failure value */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_FOCUSED;
item.state = LVIS_FOCUSED;
g_dump_itemchanged = TRUE;
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(FALSE, res);
g_dump_itemchanged = FALSE;
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
"ownerdata focus all notification", FALSE);
/* focus single item, remove all */
item.stateMask = LVIS_FOCUSED;
item.state = LVIS_FOCUSED;
@ -2842,32 +2883,58 @@ static void test_ownerdata(void)
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_FOCUSED;
item.state = 0;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
"ownerdata remove focus all notification", TRUE);
/* set all cut */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_CUT;
item.state = LVIS_CUT;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
"ownerdata cut all notification", TRUE);
"ownerdata cut all notification", FALSE);
/* all marked cut, try again */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
item.stateMask = LVIS_CUT;
item.state = LVIS_CUT;
g_dump_itemchanged = TRUE;
memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
expect(TRUE, res);
g_dump_itemchanged = FALSE;
ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
"ownerdata cut all notification #2", TRUE);
"ownerdata cut all notification #2", FALSE);
DestroyWindow(hwnd);