Keeping track of nSelectionMark and nFocusedItem

François Gouget fgouget at codeweavers.com
Mon Mar 5 14:52:46 CST 2001


   These two indices must be updated when inserting/deleting/sorting
items. Strangely enough this seemingly obvious rule does not apply to
nHotItem. You can test it with the ListView ControlSpy: SetHotItem(3),
DeleteAllItems, GetHotItem gives back 3!
   Also, SortItems had an optimisation to not do the sort if there is
less than two items. But then there is no need to update the
selection/indices either, or to AlignTop or to redraw the whole thing.
So I changed it to just return TRUE in such cases.


Changelog:

   François Gouget <fgouget at codeweavers.com>

 * dlls/comctl32/listview.c

   Update nSelectionMark and nFocusedItem when
inserting/deleting/sorting items
   SortItems: If sorting less than 2 items, do nothing


-- 
François Gouget
fgouget at codeweavers.com
-------------- next part --------------
Index: dlls/comctl32/listview.c
===================================================================
RCS file: /home/cvs/wine/wine/dlls/comctl32/listview.c,v
retrieving revision 1.100
diff -u -r1.100 listview.c
--- dlls/comctl32/listview.c	2001/03/04 01:04:35	1.100
+++ dlls/comctl32/listview.c	2001/03/05 20:26:46
@@ -1479,18 +1479,17 @@
 
 /**
 * DESCRIPTION:
-* shifts all selection indexs starting with the indesx specified
-* in the direction specified.
+* Updates the various indices after an item has been inserted or deleted.
 * 
 * PARAMETER(S):
 * [I] HWND : window handle
 * [I] INT : item index 
-* [I] INT : amount and direction of shift
+* [I] INT : Direction of shift, +1 or -1.
 *
 * RETURN:
 * None
 */
-static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
+static VOID LISTVIEW_ShiftIndices(HWND hwnd, INT nItem, INT direction)
 {
   LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
   LISTVIEW_SELECTION selection,*checkselection;
@@ -1516,6 +1515,33 @@
         checkselection->upper += direction;
     index ++;
   }
+
+  /* Note that the following will fail if direction != +1 and -1 */
+  if (infoPtr->nSelectionMark > nItem)
+      infoPtr->nSelectionMark += direction;
+  else if (infoPtr->nSelectionMark == nItem)
+  {
+    if (direction > 0)
+      infoPtr->nSelectionMark += direction;
+    else if (infoPtr->nSelectionMark >= GETITEMCOUNT(infoPtr))
+      infoPtr->nSelectionMark = GETITEMCOUNT(infoPtr) - 1;
+  }
+
+  if (infoPtr->nFocusedItem > nItem)
+    infoPtr->nFocusedItem += direction;
+  else if (infoPtr->nFocusedItem == nItem)
+  {
+    if (direction > 0)
+      infoPtr->nFocusedItem += direction;
+    else
+    {
+      if (infoPtr->nFocusedItem >= GETITEMCOUNT(infoPtr))
+        infoPtr->nFocusedItem = GETITEMCOUNT(infoPtr) - 1;
+      if (infoPtr->nFocusedItem >= 0)
+        LISTVIEW_SetItemFocus(hwnd, infoPtr->nFocusedItem);
+    }
+  }
+  /* But we are not supposed to modify nHotItem! */
 }
 
 
@@ -3776,7 +3802,11 @@
   HDPA hdpaSubItems;
 
   TRACE("(hwnd=%x,)\n", hwnd);
+
   LISTVIEW_RemoveAllSelections(hwnd);
+  infoPtr->nSelectionMark=-1;
+  infoPtr->nFocusedItem=-1;
+  /* But we are supposed to leave nHotItem as is! */
 
   if (lStyle & LVS_OWNERDATA)
   {
@@ -3959,8 +3989,6 @@
   item.stateMask = LVIS_SELECTED;
   LISTVIEW_SetItemState(hwnd,nItem,&item);
 
-  LISTVIEW_ShiftSelections(hwnd,nItem,-1);
-
   if (lStyle & LVS_OWNERDATA)
   {
     infoPtr->hdpaItems->nItemCount --;
@@ -4010,6 +4038,8 @@
       bResult = DPA_Destroy(hdpaSubItems);
     }
 
+    LISTVIEW_ShiftIndices(hwnd,nItem,-1);
+
     /* align items (set position of each item) */
     if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
     {
@@ -4023,16 +4053,6 @@
       }
     }
 
-    /* If this item had focus change focus to next or previous item */
-    if (GETITEMCOUNT(infoPtr) > 0)
-    {
-       int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
-       if (infoPtr->nFocusedItem == nItem)
-	   LISTVIEW_SetItemFocus(hwnd, sItem);
-    }
-    else
-	  infoPtr->nFocusedItem = -1;
-
     LISTVIEW_UpdateScroll(hwnd);
 
     /* refresh client area */
@@ -6481,7 +6501,7 @@
 	      }
               if (nItem != -1)
               {
-                LISTVIEW_ShiftSelections(hwnd,nItem,1);
+                LISTVIEW_ShiftIndices(hwnd,nItem,1);
 
                 /* manage item focus */
                 if (lpLVItem->mask & LVIF_STATE)
@@ -7396,9 +7416,9 @@
     LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
     int nCount, i;
     UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
-    HDPA *hdpaSubItems=NULL;
+    HDPA hdpaSubItems=NULL;
     LISTVIEW_ITEM *pLVItem=NULL;
-
+    LPVOID selectionMarkItem;
 
     if (lStyle & LVS_OWNERDATA)
       return FALSE;
@@ -7408,17 +7429,19 @@
    
     nCount = GETITEMCOUNT(infoPtr);
     /* if there are 0 or 1 items, there is no need to sort */
-    if (nCount > 1)
-    {
-	infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
-	infoPtr->lParamSort = (LPARAM)wParam;
-	
-        DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
-    }
+    if (nCount < 2)
+        return TRUE;
 
-    /* Adjust selections so that they are the way they should be after
-       the sort (otherwise, the list items move around, but whatever
-       is at the item's previous original position will be selected instead) */
+    infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
+    infoPtr->lParamSort = (LPARAM)wParam;
+    DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, hwnd);
+
+    /* Adjust selections and indices so that they are the way they should 
+     * be after the sort (otherwise, the list items move around, but 
+     * whatever is at the item's previous original position will be 
+     * selected instead)
+     */
+    selectionMarkItem=(infoPtr->nSelectionMark>=0)?DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark):NULL;
     for (i=0; i < nCount; i++)
     {
        hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
@@ -7428,7 +7451,12 @@
           LISTVIEW_AddSelectionRange(hwnd, i, i);
        else
           LISTVIEW_RemoveSelectionRange(hwnd, i, i);
+       if (pLVItem->state & LVIS_FOCUSED)
+          infoPtr->nFocusedItem=i;
     }
+    if (selectionMarkItem != NULL)
+       infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
+    /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
 
     /* align the items */
     LISTVIEW_AlignTop(hwnd);


More information about the wine-patches mailing list