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

This commit is contained in:
Nikolay Sivov 2013-01-12 21:29:38 +04:00 committed by Alexandre Julliard
parent bd72767eed
commit dbd997c3c9
2 changed files with 87 additions and 8 deletions

View File

@ -4164,7 +4164,7 @@ static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle)
/*** /***
* DESCRIPTION: * DESCRIPTION:
* Helper for LISTVIEW_SetItemT *only*: sets item attributes. * Helper for LISTVIEW_SetItemT and LISTVIEW_InsertItemT: sets item attributes.
* *
* PARAMETER(S): * PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure * [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; 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; if (!uChanged) return TRUE;
*bChanged = 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); 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 (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
{ {
if (lpLVItem->state & LVIS_FOCUSED) if (lpLVItem->state & LVIS_FOCUSED)
@ -7680,7 +7696,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
LVITEMW item; LVITEMW item;
HWND hwndSelf = infoPtr->hwndSelf; 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++; if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++;
@ -7730,14 +7746,13 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
else else
nItem = min(lpLVItem->iItem, infoPtr->nItemCount); 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 ); nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
if (nItem == -1) goto fail; if (nItem == -1) goto fail;
infoPtr->nItemCount++; infoPtr->nItemCount++;
/* shift indices first so they don't get tangled */ /* shift indices first so they don't get tangled */
LISTVIEW_ShiftIndices(infoPtr, nItem, 1); LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, 1);
/* set the item attributes */ /* set the item attributes */
if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) 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 &= ~LVIS_STATEIMAGEMASK;
item.state |= INDEXTOSTATEIMAGEMASK(1); item.state |= INDEXTOSTATEIMAGEMASK(1);
} }
if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo; if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
/* make room for the position, if we are in the right mode */ /* make room for the position, if we are in the right mode */
@ -7778,7 +7794,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
} }
/* send LVN_INSERTITEM notification */ /* send LVN_INSERTITEM notification */
ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); memset(&nmlv, 0, sizeof(NMLISTVIEW));
nmlv.iItem = nItem; nmlv.iItem = nItem;
nmlv.lParam = lpItem->lParam; nmlv.lParam = lpItem->lParam;
notify_listview(infoPtr, LVN_INSERTITEM, &nmlv); notify_listview(infoPtr, LVN_INSERTITEM, &nmlv);

View File

@ -363,6 +363,15 @@ static const struct message listview_header_set_imagelist[] = {
{ 0 } { 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 LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
static LONG defwndproc_counter = 0; static LONG defwndproc_counter = 0;
@ -5434,6 +5443,58 @@ static void test_deleteitem(void)
DestroyWindow(hwnd); 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) START_TEST(listview)
{ {
HMODULE hComctl32; HMODULE hComctl32;
@ -5502,6 +5563,7 @@ START_TEST(listview)
test_LVM_SETITEMTEXT(); test_LVM_SETITEMTEXT();
test_imagelists(); test_imagelists();
test_deleteitem(); test_deleteitem();
test_insertitem();
if (!load_v6_module(&ctx_cookie, &hCtx)) if (!load_v6_module(&ctx_cookie, &hCtx))
{ {
@ -5533,6 +5595,7 @@ START_TEST(listview)
test_LVS_EX_HEADERINALLVIEWS(); test_LVS_EX_HEADERINALLVIEWS();
test_deleteitem(); test_deleteitem();
test_multiselect(); test_multiselect();
test_insertitem();
unload_v6_module(ctx_cookie, hCtx); unload_v6_module(ctx_cookie, hCtx);