comctl32/listview: Update focus index when new item data is already there.
This commit is contained in:
parent
bd72767eed
commit
dbd997c3c9
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue