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