Module: wine Branch: master Commit: 6227bbcff79cd03a6775ac72436c1ea2f5c81694 URL: http://source.winehq.org/git/wine.git/?a=commit;h=6227bbcff79cd03a6775ac7243...
Author: Nikolay Sivov nsivov@codeweavers.com Date: Thu Jan 10 16:34:41 2013 +0400
comctl32/listview: Fix focus index update when item is deleted.
---
dlls/comctl32/listview.c | 32 ++++++++++++++----- dlls/comctl32/tests/listview.c | 69 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 8 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 2c953ad..49c326a 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 01b90ae..161278c 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);