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