comctl32/listview: Fix focus index update when item is deleted.
This commit is contained in:
parent
0c67e653c0
commit
6227bbcff7
|
@ -3447,7 +3447,6 @@ static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
|
||||||
return oldFocus != infoPtr->nFocusedItem;
|
return oldFocus != infoPtr->nFocusedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for LISTVIEW_ShiftIndices *only* */
|
|
||||||
static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
|
static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction)
|
||||||
{
|
{
|
||||||
if (nShiftItem < nItem) return nShiftItem;
|
if (nShiftItem < nItem) return nShiftItem;
|
||||||
|
@ -3459,6 +3458,24 @@ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, I
|
||||||
return min(nShiftItem, infoPtr->nItemCount - 1);
|
return min(nShiftItem, infoPtr->nItemCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function updates focus index.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
focus : current focus index
|
||||||
|
item : index of item to be added/removed
|
||||||
|
direction : add/remove flag
|
||||||
|
*/
|
||||||
|
static void LISTVIEW_ShiftFocus(LISTVIEW_INFO *infoPtr, INT focus, INT item, INT direction)
|
||||||
|
{
|
||||||
|
BOOL old_change = infoPtr->bDoChangeNotify;
|
||||||
|
|
||||||
|
infoPtr->bDoChangeNotify = FALSE;
|
||||||
|
focus = shift_item(infoPtr, focus, item, direction);
|
||||||
|
if (focus != infoPtr->nFocusedItem)
|
||||||
|
LISTVIEW_SetItemFocus(infoPtr, focus);
|
||||||
|
infoPtr->bDoChangeNotify = old_change;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DESCRIPTION:
|
* DESCRIPTION:
|
||||||
* Updates the various indices after an item has been inserted or deleted.
|
* Updates the various indices after an item has been inserted or deleted.
|
||||||
|
@ -3473,14 +3490,13 @@ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, I
|
||||||
*/
|
*/
|
||||||
static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
|
static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
|
||||||
{
|
{
|
||||||
INT nNewFocus;
|
|
||||||
BOOL bOldChange;
|
BOOL bOldChange;
|
||||||
|
|
||||||
/* temporarily disable change notification while shifting items */
|
/* temporarily disable change notification while shifting items */
|
||||||
bOldChange = infoPtr->bDoChangeNotify;
|
bOldChange = infoPtr->bDoChangeNotify;
|
||||||
infoPtr->bDoChangeNotify = FALSE;
|
infoPtr->bDoChangeNotify = FALSE;
|
||||||
|
|
||||||
TRACE("Shifting %iu, %i steps\n", nItem, direction);
|
TRACE("Shifting %i, %i steps\n", nItem, direction);
|
||||||
|
|
||||||
ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount);
|
ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount);
|
||||||
|
|
||||||
|
@ -3488,10 +3504,6 @@ static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT directi
|
||||||
|
|
||||||
infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction);
|
infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction);
|
||||||
|
|
||||||
nNewFocus = shift_item(infoPtr, infoPtr->nFocusedItem, nItem, direction);
|
|
||||||
if (nNewFocus != infoPtr->nFocusedItem)
|
|
||||||
LISTVIEW_SetItemFocus(infoPtr, nNewFocus);
|
|
||||||
|
|
||||||
/* But we are not supposed to modify nHotItem! */
|
/* But we are not supposed to modify nHotItem! */
|
||||||
|
|
||||||
infoPtr->bDoChangeNotify = bOldChange;
|
infoPtr->bDoChangeNotify = bOldChange;
|
||||||
|
@ -5664,6 +5676,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
|
||||||
{
|
{
|
||||||
LVITEMW item;
|
LVITEMW item;
|
||||||
const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON);
|
const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON);
|
||||||
|
INT focus = infoPtr->nFocusedItem;
|
||||||
|
|
||||||
TRACE("(nItem=%d)\n", nItem);
|
TRACE("(nItem=%d)\n", nItem);
|
||||||
|
|
||||||
|
@ -5714,6 +5727,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
|
||||||
|
|
||||||
infoPtr->nItemCount--;
|
infoPtr->nItemCount--;
|
||||||
LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
|
LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
|
||||||
|
LISTVIEW_ShiftFocus(infoPtr, focus, nItem, -1);
|
||||||
|
|
||||||
/* now is the invalidation fun */
|
/* now is the invalidation fun */
|
||||||
if (!is_icon)
|
if (!is_icon)
|
||||||
|
@ -7721,6 +7735,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
|
||||||
|
|
||||||
/* 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))
|
||||||
|
@ -7787,6 +7802,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
|
||||||
|
|
||||||
undo:
|
undo:
|
||||||
LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
|
LISTVIEW_ShiftIndices(infoPtr, nItem, -1);
|
||||||
|
LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, -1);
|
||||||
DPA_DeletePtr(infoPtr->hdpaItems, nItem);
|
DPA_DeletePtr(infoPtr->hdpaItems, nItem);
|
||||||
infoPtr->nItemCount--;
|
infoPtr->nItemCount--;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -63,6 +63,8 @@ static LVITEMA g_itema;
|
||||||
static BOOL g_disp_A_to_W;
|
static BOOL g_disp_A_to_W;
|
||||||
/* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
|
/* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
|
||||||
static NMLVDISPINFO g_editbox_disp_info;
|
static NMLVDISPINFO g_editbox_disp_info;
|
||||||
|
/* when this is set focus will be tested on LVN_DELETEITEM */
|
||||||
|
static BOOL g_focus_test_LVN_DELETEITEM;
|
||||||
|
|
||||||
static HWND subclass_editbox(HWND hwndListview);
|
static HWND subclass_editbox(HWND hwndListview);
|
||||||
|
|
||||||
|
@ -454,6 +456,16 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
|
||||||
"buffer size %d\n", dispinfo->item.cchTextMax);
|
"buffer size %d\n", dispinfo->item.cchTextMax);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LVN_DELETEITEM:
|
||||||
|
if (g_focus_test_LVN_DELETEITEM)
|
||||||
|
{
|
||||||
|
NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
|
||||||
|
UINT state;
|
||||||
|
|
||||||
|
state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
|
||||||
|
ok(state == 0, "got state %x\n", state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NM_HOVER:
|
case NM_HOVER:
|
||||||
if (g_block_hover) return 1;
|
if (g_block_hover) return 1;
|
||||||
break;
|
break;
|
||||||
|
@ -5291,6 +5303,61 @@ static void test_imagelists(void)
|
||||||
DestroyWindow(hwnd);
|
DestroyWindow(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_deleteitem(void)
|
||||||
|
{
|
||||||
|
LVITEMA item;
|
||||||
|
UINT state;
|
||||||
|
HWND hwnd;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
hwnd = create_listview_control(LVS_REPORT);
|
||||||
|
|
||||||
|
insert_item(hwnd, 0);
|
||||||
|
insert_item(hwnd, 0);
|
||||||
|
insert_item(hwnd, 0);
|
||||||
|
insert_item(hwnd, 0);
|
||||||
|
insert_item(hwnd, 0);
|
||||||
|
|
||||||
|
g_focus_test_LVN_DELETEITEM = TRUE;
|
||||||
|
|
||||||
|
/* delete focused item (not the last index) */
|
||||||
|
item.stateMask = LVIS_FOCUSED;
|
||||||
|
item.state = LVIS_FOCUSED;
|
||||||
|
ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
/* next item gets focus */
|
||||||
|
state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
|
||||||
|
ok(state == LVIS_FOCUSED, "got %x\n", state);
|
||||||
|
|
||||||
|
/* focus last item and delete it */
|
||||||
|
item.stateMask = LVIS_FOCUSED;
|
||||||
|
item.state = LVIS_FOCUSED;
|
||||||
|
ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
/* new last item gets focus */
|
||||||
|
state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
|
||||||
|
ok(state == LVIS_FOCUSED, "got %x\n", state);
|
||||||
|
|
||||||
|
/* focus first item and delete it */
|
||||||
|
item.stateMask = LVIS_FOCUSED;
|
||||||
|
item.state = LVIS_FOCUSED;
|
||||||
|
ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
|
||||||
|
ok(ret == TRUE, "got %d\n", ret);
|
||||||
|
/* new first item gets focus */
|
||||||
|
state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
|
||||||
|
ok(state == LVIS_FOCUSED, "got %x\n", state);
|
||||||
|
|
||||||
|
g_focus_test_LVN_DELETEITEM = FALSE;
|
||||||
|
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(listview)
|
START_TEST(listview)
|
||||||
{
|
{
|
||||||
HMODULE hComctl32;
|
HMODULE hComctl32;
|
||||||
|
@ -5358,6 +5425,7 @@ START_TEST(listview)
|
||||||
test_dispinfo();
|
test_dispinfo();
|
||||||
test_LVM_SETITEMTEXT();
|
test_LVM_SETITEMTEXT();
|
||||||
test_imagelists();
|
test_imagelists();
|
||||||
|
test_deleteitem();
|
||||||
|
|
||||||
if (!load_v6_module(&ctx_cookie, &hCtx))
|
if (!load_v6_module(&ctx_cookie, &hCtx))
|
||||||
{
|
{
|
||||||
|
@ -5387,6 +5455,7 @@ START_TEST(listview)
|
||||||
test_scrollnotify();
|
test_scrollnotify();
|
||||||
test_LVS_EX_TRANSPARENTBKGND();
|
test_LVS_EX_TRANSPARENTBKGND();
|
||||||
test_LVS_EX_HEADERINALLVIEWS();
|
test_LVS_EX_HEADERINALLVIEWS();
|
||||||
|
test_deleteitem();
|
||||||
|
|
||||||
unload_v6_module(ctx_cookie, hCtx);
|
unload_v6_module(ctx_cookie, hCtx);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue