comctl32: Use single notification message for setting all item state with LVM_SETITEMSTATE (LVS_OWNERDATA case only)
Nikolay Sivov
nsivov at codeweavers.com
Mon Mar 26 07:09:40 CDT 2012
Use single notification message for setting all item state with
LVM_SETITEMSTATE (LVS_OWNERDATA case only)
-------------- next part --------------
>From 39946a9e1f5cf9e7a3c03cca1d12522b75c472ca Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue, 20 Mar 2012 10:17:47 +0300
Subject: [PATCH 3/3] Use single notification message for setting all item state with LVM_SETITEMSTATE (LVS_OWNERDATA case only)
---
dlls/comctl32/listview.c | 50 +++++++++++++---
dlls/comctl32/tests/listview.c | 121 +++++++++++++++++++++++++++++++---------
2 files changed, 134 insertions(+), 37 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 3cd316a..ccabe6b 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -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:
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index b3df59e..c38bb61 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -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);
--
1.5.6.5
More information about the wine-patches
mailing list