diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 2c953addfcb46be59944660d455d71aebaca52da..49c326ad8df7f22fb18521f18dd31c6485e5bf40 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -3447,7 +3447,6 @@ static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem) return oldFocus != infoPtr->nFocusedItem; } -/* Helper function for LISTVIEW_ShiftIndices *only* */ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction) { 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); } +/* 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: * Updates the various indices after an item has been inserted or deleted. @@ -3473,24 +3490,19 @@ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, I */ static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) { - INT nNewFocus; BOOL bOldChange; /* temporarily disable change notification while shifting items */ bOldChange = infoPtr->bDoChangeNotify; 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); assert(abs(direction) == 1); 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! */ @@ -5664,6 +5676,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) { LVITEMW item; const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON); + INT focus = infoPtr->nFocusedItem; TRACE("(nItem=%d)\n", nItem); @@ -5673,7 +5686,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) item.state = 0; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; LISTVIEW_SetItemState(infoPtr, nItem, &item); - + /* send LVN_DELETEITEM notification. */ if (!notify_deleteitem(infoPtr, nItem)) return FALSE; @@ -5714,6 +5727,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) infoPtr->nItemCount--; LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + LISTVIEW_ShiftFocus(infoPtr, focus, nItem, -1); /* now is the invalidation fun */ 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 */ LISTVIEW_ShiftIndices(infoPtr, nItem, 1); + LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, 1); /* set the item attributes */ if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) @@ -7787,6 +7802,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, undo: LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, -1); DPA_DeletePtr(infoPtr->hdpaItems, nItem); infoPtr->nItemCount--; fail: diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 01b90ae5f6517050b652ea81bdfc444d73ce6bf6..161278c698f34f5a23f2bf61c41710628af71160 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -63,6 +63,8 @@ static LVITEMA g_itema; static BOOL g_disp_A_to_W; /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */ 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); @@ -454,6 +456,16 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP "buffer size %d\n", dispinfo->item.cchTextMax); } 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: if (g_block_hover) return 1; break; @@ -5291,6 +5303,61 @@ static void test_imagelists(void) 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) { HMODULE hComctl32; @@ -5358,6 +5425,7 @@ START_TEST(listview) test_dispinfo(); test_LVM_SETITEMTEXT(); test_imagelists(); + test_deleteitem(); if (!load_v6_module(&ctx_cookie, &hCtx)) { @@ -5387,6 +5455,7 @@ START_TEST(listview) test_scrollnotify(); test_LVS_EX_TRANSPARENTBKGND(); test_LVS_EX_HEADERINALLVIEWS(); + test_deleteitem(); unload_v6_module(ctx_cookie, hCtx);