Nikolay Sivov : comctl32/listview: Update focus index when new item data is already there.

Alexandre Julliard julliard at winehq.org
Mon Jan 14 15:55:49 CST 2013


Module: wine
Branch: master
Commit: dbd997c3c9284749a06d8b645680c78814bb28c1
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=dbd997c3c9284749a06d8b645680c78814bb28c1

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Sat Jan 12 21:29:38 2013 +0400

comctl32/listview: Update focus index when new item data is already there.

---

 dlls/comctl32/listview.c       |   32 +++++++++++++++-----
 dlls/comctl32/tests/listview.c |   63 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index bb6d1b2..75aa51b 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -4164,7 +4164,7 @@ static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
 
 /***
  * DESCRIPTION:
- * Helper for LISTVIEW_SetItemT *only*: sets item attributes.
+ * Helper for LISTVIEW_SetItemT and LISTVIEW_InsertItemT: sets item attributes.
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
@@ -4256,6 +4256,15 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL
 	return FALSE;
     }
 
+    /* When item is inserted we need to shift existing focus index if new item has lower index. */
+    if (isNew && (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) &&
+        /* this means we won't hit a focus change path later */
+        ((uChanged & LVIF_STATE) == 0 || (!(lpLVItem->state & LVIS_FOCUSED) && (infoPtr->nFocusedItem != lpLVItem->iItem))))
+    {
+        if (infoPtr->nFocusedItem != -1 && (lpLVItem->iItem <= infoPtr->nFocusedItem))
+            infoPtr->nFocusedItem++;
+    }
+
     if (!uChanged) return TRUE;
     *bChanged = TRUE;
 
@@ -4288,7 +4297,14 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL
 	{
 	    ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem);
 	}
-	/* if we are asked to change focus, and we manage it, do it */
+	/* If we are asked to change focus, and we manage it, do it.
+           It's important to have all new item data stored at this point,
+           cause changing existing focus could result in redrawing operation,
+           which in turn could ask for disp data, application should see all data
+           for inserted item when processing LVN_GETDISPINFO.
+
+           The way this works application will see nested item change notifications -
+           changed item notifications interrupted by ones from item loosing focus. */
 	if (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
 	{
 	    if (lpLVItem->state & LVIS_FOCUSED)
@@ -4320,7 +4336,7 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL
 
     /* if we're inserting the item, we're done */
     if (isNew) return TRUE;
-    
+
     /* send LVN_ITEMCHANGED notification */
     if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam;
     if (infoPtr->bDoChangeNotify) notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv);
@@ -7680,7 +7696,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
     LVITEMW item;
     HWND hwndSelf = infoPtr->hwndSelf;
 
-    TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
+    TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
 
     if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++;
 
@@ -7730,14 +7746,13 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
     else
         nItem = min(lpLVItem->iItem, infoPtr->nItemCount);
 
-    TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
+    TRACE("inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
     nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
     if (nItem == -1) goto fail;
     infoPtr->nItemCount++;
 
     /* shift indices first so they don't get tangled */
     LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
-    LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, 1);
 
     /* set the item attributes */
     if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS))
@@ -7763,6 +7778,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
         item.state &= ~LVIS_STATEIMAGEMASK;
         item.state |= INDEXTOSTATEIMAGEMASK(1);
     }
+
     if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
 
     /* make room for the position, if we are in the right mode */
@@ -7776,9 +7792,9 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
 	    goto undo;
 	}
     }
-    
+
     /* send LVN_INSERTITEM notification */
-    ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
+    memset(&nmlv, 0, sizeof(NMLISTVIEW));
     nmlv.iItem = nItem;
     nmlv.lParam = lpItem->lParam;
     notify_listview(infoPtr, LVN_INSERTITEM, &nmlv);
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index cff6e92..2fb7cb5 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -363,6 +363,15 @@ static const struct message listview_header_set_imagelist[] = {
     { 0 }
 };
 
+static const struct message parent_insert_focused_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
+    { 0 }
+};
+
 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
@@ -5434,6 +5443,58 @@ static void test_deleteitem(void)
     DestroyWindow(hwnd);
 }
 
+static void test_insertitem(void)
+{
+    LVITEMA item;
+    UINT state;
+    HWND hwnd;
+    INT ret;
+
+    hwnd = create_listview_control(LVS_REPORT);
+
+    /* insert item 0 focused */
+    item.mask = LVIF_STATE;
+    item.state = LVIS_FOCUSED;
+    item.stateMask = LVIS_FOCUSED;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    ok(ret == 0, "got %d\n", ret);
+
+    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
+    ok(state == LVIS_FOCUSED, "got %x\n", state);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* insert item 1, focus shift */
+    item.mask = LVIF_STATE;
+    item.state = LVIS_FOCUSED;
+    item.stateMask = LVIS_FOCUSED;
+    item.iItem = 1;
+    item.iSubItem = 0;
+    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    ok(ret == 1, "got %d\n", ret);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
+
+    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
+    ok(state == LVIS_FOCUSED, "got %x\n", state);
+
+    /* insert item 2, no focus shift */
+    item.mask = LVIF_STATE;
+    item.state = 0;
+    item.stateMask = LVIS_FOCUSED;
+    item.iItem = 2;
+    item.iSubItem = 0;
+    ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    ok(ret == 2, "got %d\n", ret);
+
+    state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
+    ok(state == LVIS_FOCUSED, "got %x\n", state);
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(listview)
 {
     HMODULE hComctl32;
@@ -5502,6 +5563,7 @@ START_TEST(listview)
     test_LVM_SETITEMTEXT();
     test_imagelists();
     test_deleteitem();
+    test_insertitem();
 
     if (!load_v6_module(&ctx_cookie, &hCtx))
     {
@@ -5533,6 +5595,7 @@ START_TEST(listview)
     test_LVS_EX_HEADERINALLVIEWS();
     test_deleteitem();
     test_multiselect();
+    test_insertitem();
 
     unload_v6_module(ctx_cookie, hCtx);
 




More information about the wine-cvs mailing list