Listview K10

Dimitrie O. Paun dpaun at rogers.com
Sat Oct 5 02:14:33 CDT 2002


This one fixes selection problem in OWNERDATA, OWNERDRAW
listviews. Which means (among other things) Xnews now
works better.

Unfortunately, focus handling for OWNERDRAW is still broken.
Next thing to look at.

Alos, two critical performance problems were fixed: Xnews
took >5 secs to do trivial things, like move focus, or select.

ChangeLog
  Fix bug in OWNERDATA selection handling
  Fix critical performance bug in GetSelectedCount
  Fix critical performance bug in SetGroupSelection
  Fix problems for OWNERDRAW report
  Fix hidden/latent bugs in state handling
  Better debug messages.


--- dlls/comctl32/listview.c.K9	Fri Oct  4 18:56:54 2002
+++ dlls/comctl32/listview.c	Sat Oct  5 03:05:31 2002
@@ -1810,16 +1810,14 @@
 #if 0
 static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr)
 {
-  RANGE *selection;
-  INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
-  INT i;
+    INT i;
 
-  TRACE("Selections are:\n");
-  for (i = 0; i < topSelection; i++)
-  {
-    selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
-    TRACE("     %lu - %lu\n",selection->lower,selection->upper);
-  }
+    ERR("Selections are:\n");
+    for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++)
+    {
+    	RANGE *selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges, i);
+    	ERR("   [%d - %d]\n", selection->lower, selection->upper);
+    }
 }
 #endif
 
@@ -2092,6 +2090,42 @@
 
 /***
  * DESCRIPTION:
+ * Retrieves the number of items that are marked as selected.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ *
+ * RETURN:
+ * Number of items selected.
+ */
+static INT LISTVIEW_GetSelectedCount(LISTVIEW_INFO *infoPtr)
+{
+    INT i, nSelectedCount = 0;
+
+    if (infoPtr->uCallbackMask & LVIS_SELECTED)
+    {
+        INT i;
+	for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+  	{
+	    if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
+		nSelectedCount++;
+	}
+    }
+    else
+    {
+	for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++)
+	{
+	    RANGE *sel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, i);
+	    nSelectedCount += sel->upper - sel->lower + 1;
+	}
+    }
+
+    TRACE("nSelectedCount=%d\n", nSelectedCount);
+    return nSelectedCount;
+}
+
+/***
+ * DESCRIPTION:
  * Manages the item focus.
  *
  * PARAMETER(S):
@@ -2231,13 +2265,20 @@
 static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
 {
     UINT uView = LISTVIEW_GetType(infoPtr);
-    INT i, nFirst, nLast;
+    INT i;
     LVITEMW item;
     POINT ptItem;
     RECT rcSel;
 
+    LISTVIEW_RemoveAllSelections(infoPtr);
+    
+    item.state = LVIS_SELECTED; 
+    item.stateMask = LVIS_SELECTED;
+
     if ((uView == LVS_LIST) || (uView == LVS_REPORT))
     {
+	INT nFirst, nLast;
+
 	if (infoPtr->nSelectionMark == -1)
 	    infoPtr->nSelectionMark = nFirst = nLast = nItem;
 	else
@@ -2245,6 +2286,8 @@
 	    nFirst = min(infoPtr->nSelectionMark, nItem);
 	    nLast = max(infoPtr->nSelectionMark, nItem);
 	}
+	for (i = nFirst; i < nLast; i++)
+	    LISTVIEW_SetItemState(infoPtr, i, &item);
     }
     else
     {
@@ -2255,22 +2298,14 @@
 	rcSelMark.left = LVIR_BOUNDS;
 	if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return;
 	UnionRect(&rcSel, &rcItem, &rcSelMark);
-	nFirst = nLast = -1;
-    }
-
-    item.stateMask = LVIS_SELECTED;
-
-    for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
-    {
-	if (nFirst > -1) 
-	    item.state = (i < nFirst) || (i > nLast) ? 0 : LVIS_SELECTED;
-	else
+	for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
 	{
 	    LISTVIEW_GetItemPosition(infoPtr, i, &ptItem);
-	    item.state = PtInRect(&rcSel, ptItem) ? LVIS_SELECTED : 0;
+	    if (PtInRect(&rcSel, ptItem)) 
+		LISTVIEW_SetItemState(infoPtr, i, &item);
 	}
-	LISTVIEW_SetItemState(infoPtr, i, &item);
     }
+
     LISTVIEW_SetItemFocus(infoPtr, nItem);
 }
 
@@ -3314,20 +3349,23 @@
 	    if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
 	   
 	    ZeroMemory(&dis, sizeof(dis)); 
-            dis.hwndItem = infoPtr->hwndSelf;
-            dis.hDC = hdc;
             dis.CtlType = ODT_LISTVIEW;
             dis.CtlID = uID;
             dis.itemID = nItem;
             dis.itemAction = ODA_DRAWENTIRE;
-            dis.itemData = item.lParam;
+            if (item.state & LVIS_SELECTED) dis.itemAction |= ODA_SELECT;
+            if (item.state & LVIS_FOCUSED) dis.itemAction |= ODA_FOCUS;
+	    /*dis.itemState = ODS_DEFAULT; */
             if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
             if (item.state & LVIS_FOCUSED) dis.itemState |= ODS_FOCUS;
+            dis.hwndItem = infoPtr->hwndSelf;
+            dis.hDC = hdc;
             dis.rcItem.left = lpCols[0].rc.left;
             dis.rcItem.right = lpCols[nColumnCount - 1].rc.right;
             dis.rcItem.top = nDrawPosY;
             dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
             OffsetRect(&dis.rcItem, ptOrig.x, 0);
+            dis.itemData = item.lParam;
 
 	    TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem));
             SendMessageW(GetParent(infoPtr->hwndSelf), WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
@@ -4746,6 +4784,7 @@
 	    if (lpLVItem->mask & LVIF_STATE)
 	        dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
 	    notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
+	    dispInfo.item.stateMask = lpLVItem->stateMask;
 	    *lpLVItem = dispInfo.item;
 	    TRACE("   getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
 	}
@@ -4754,7 +4793,7 @@
 	if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
 
 	/* if focus is handled by us, report it */
-	if ( !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) 
+	if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) 
 	{
 	    lpLVItem->state &= ~LVIS_FOCUSED;
 	    if (infoPtr->nFocusedItem == lpLVItem->iItem)
@@ -4762,11 +4801,10 @@
         }
 
 	/* and do the same for selection, if we handle it */
-	if ( !(infoPtr->uCallbackMask & LVIS_SELECTED) ) 
+	if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) 
 	{
 	    lpLVItem->state &= ~LVIS_SELECTED;
-	    if ((lpLVItem->stateMask & LVIS_SELECTED) &&
-		is_item_selected(infoPtr, lpLVItem->iItem))
+	    if (is_item_selected(infoPtr, lpLVItem->iItem))
 		lpLVItem->state |= LVIS_SELECTED;
 	}
 	
@@ -4866,17 +4904,16 @@
 	    lpLVItem->state &= ~dispInfo.item.stateMask;
 	    lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
 	}
-	if ( !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) 
+	if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) 
 	{
 	    lpLVItem->state &= ~LVIS_FOCUSED;
 	    if (infoPtr->nFocusedItem == lpLVItem->iItem)
 	        lpLVItem->state |= LVIS_FOCUSED;
         }
-	if ( !(infoPtr->uCallbackMask & LVIS_SELECTED) ) 
+	if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) 
 	{
 	    lpLVItem->state &= ~LVIS_SELECTED;
-	    if ((lpLVItem->stateMask & LVIS_SELECTED) &&
-	        is_item_selected(infoPtr, lpLVItem->iItem))
+	    if (is_item_selected(infoPtr, lpLVItem->iItem))
 		lpLVItem->state |= LVIS_SELECTED;
 	}	    
     }
@@ -5519,31 +5556,6 @@
 
 /***
  * DESCRIPTION:
- * Retrieves the number of items that are marked as selected.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- *
- * RETURN:
- * Number of items selected.
- */
-static LRESULT LISTVIEW_GetSelectedCount(LISTVIEW_INFO *infoPtr)
-{
-/* REDO THIS */
-  INT nSelectedCount = 0;
-  INT i;
-
-  for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
-  {
-    if (ListView_GetItemState(infoPtr->hwndSelf, i, LVIS_SELECTED) & LVIS_SELECTED)
-      nSelectedCount++;
-  }
-
-  return nSelectedCount;
-}
-
-/***
- * DESCRIPTION:
  * Retrieves the width of a string.
  *
  * PARAMETER(S):
@@ -7688,11 +7700,12 @@
   infoPtr->bLButtonDown = TRUE;
 
   nItem = LISTVIEW_GetItemAtPt(infoPtr, pt);
+  TRACE("nItem=%d\n", nItem);
   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
   {
     if (lStyle & LVS_SINGLESEL)
     {
-      if ((LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) & LVIS_SELECTED)
+      if ((LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
           && infoPtr->nEditLabelItem == -1)
           infoPtr->nEditLabelItem = nItem;
       else
@@ -7708,12 +7721,10 @@
 	{
           LVITEMW item;
 
-	  item.state = LVIS_SELECTED;
-	  item.stateMask = LVIS_SELECTED;
+	  item.state = LVIS_SELECTED | LVIS_FOCUSED;
+	  item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
 
 	  LISTVIEW_SetItemState(infoPtr,nItem,&item);
-
-	  LISTVIEW_SetItemFocus(infoPtr, nItem);
 	  infoPtr->nSelectionMark = nItem;
 	}
       }
@@ -7723,11 +7734,9 @@
 
 	bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
 	
-	item.state = bGroupSelect ? LVIS_SELECTED : 0;
-        item.stateMask = LVIS_SELECTED;
+	item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED;
+        item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
 	LISTVIEW_SetItemState(infoPtr, nItem, &item);
-
-        LISTVIEW_SetItemFocus(infoPtr, nItem);
         infoPtr->nSelectionMark = nItem;
       }
       else  if (wKey & MK_SHIFT)
@@ -7736,8 +7745,7 @@
       }
       else
       {
-	BOOL was_selected =
-	    (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) & LVIS_SELECTED);
+	BOOL was_selected = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
 
 	/* set selection (clears other pre-existing selections) */
         LISTVIEW_SetSelection(infoPtr, nItem);




More information about the wine-patches mailing list