Nikolay Sivov : comctl32/listview: Fix focus index update when item is deleted.

Alexandre Julliard julliard at winehq.org
Thu Jan 10 13:36:12 CST 2013


Module: wine
Branch: master
Commit: 6227bbcff79cd03a6775ac72436c1ea2f5c81694
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6227bbcff79cd03a6775ac72436c1ea2f5c81694

Author: Nikolay Sivov <nsivov at 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);
 




More information about the wine-cvs mailing list