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.
This commit is contained in:
Dimitrie O. Paun 2002-10-05 18:04:30 +00:00 committed by Alexandre Julliard
parent f645727afe
commit 76f397e3a1
1 changed files with 77 additions and 69 deletions

View File

@ -1810,15 +1810,13 @@ static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *infoPtr)
#if 0 #if 0
static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr) static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr)
{ {
RANGE *selection;
INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
INT i; INT i;
TRACE("Selections are:\n"); ERR("Selections are:\n");
for (i = 0; i < topSelection; i++) for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++)
{ {
selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i); RANGE *selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges, i);
TRACE(" %lu - %lu\n",selection->lower,selection->upper); ERR(" [%d - %d]\n", selection->lower, selection->upper);
} }
} }
#endif #endif
@ -2090,6 +2088,42 @@ static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr)
return TRUE; return TRUE;
} }
/***
* 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: * DESCRIPTION:
* Manages the item focus. * Manages the item focus.
@ -2231,13 +2265,20 @@ static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
{ {
UINT uView = LISTVIEW_GetType(infoPtr); UINT uView = LISTVIEW_GetType(infoPtr);
INT i, nFirst, nLast; INT i;
LVITEMW item; LVITEMW item;
POINT ptItem; POINT ptItem;
RECT rcSel; RECT rcSel;
LISTVIEW_RemoveAllSelections(infoPtr);
item.state = LVIS_SELECTED;
item.stateMask = LVIS_SELECTED;
if ((uView == LVS_LIST) || (uView == LVS_REPORT)) if ((uView == LVS_LIST) || (uView == LVS_REPORT))
{ {
INT nFirst, nLast;
if (infoPtr->nSelectionMark == -1) if (infoPtr->nSelectionMark == -1)
infoPtr->nSelectionMark = nFirst = nLast = nItem; infoPtr->nSelectionMark = nFirst = nLast = nItem;
else else
@ -2245,6 +2286,8 @@ static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
nFirst = min(infoPtr->nSelectionMark, nItem); nFirst = min(infoPtr->nSelectionMark, nItem);
nLast = max(infoPtr->nSelectionMark, nItem); nLast = max(infoPtr->nSelectionMark, nItem);
} }
for (i = nFirst; i < nLast; i++)
LISTVIEW_SetItemState(infoPtr, i, &item);
} }
else else
{ {
@ -2255,22 +2298,14 @@ static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
rcSelMark.left = LVIR_BOUNDS; rcSelMark.left = LVIR_BOUNDS;
if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return; if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return;
UnionRect(&rcSel, &rcItem, &rcSelMark); UnionRect(&rcSel, &rcItem, &rcSelMark);
nFirst = nLast = -1;
}
item.stateMask = LVIS_SELECTED;
for (i = 0; i <= GETITEMCOUNT(infoPtr); i++) for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
{
if (nFirst > -1)
item.state = (i < nFirst) || (i > nLast) ? 0 : LVIS_SELECTED;
else
{ {
LISTVIEW_GetItemPosition(infoPtr, i, &ptItem); 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); LISTVIEW_SetItemFocus(infoPtr, nItem);
} }
@ -3314,20 +3349,23 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
if (!LISTVIEW_GetItemW(infoPtr, &item)) continue; if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
ZeroMemory(&dis, sizeof(dis)); ZeroMemory(&dis, sizeof(dis));
dis.hwndItem = infoPtr->hwndSelf;
dis.hDC = hdc;
dis.CtlType = ODT_LISTVIEW; dis.CtlType = ODT_LISTVIEW;
dis.CtlID = uID; dis.CtlID = uID;
dis.itemID = nItem; dis.itemID = nItem;
dis.itemAction = ODA_DRAWENTIRE; 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_SELECTED) dis.itemState |= ODS_SELECTED;
if (item.state & LVIS_FOCUSED) dis.itemState |= ODS_FOCUS; 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.left = lpCols[0].rc.left;
dis.rcItem.right = lpCols[nColumnCount - 1].rc.right; dis.rcItem.right = lpCols[nColumnCount - 1].rc.right;
dis.rcItem.top = nDrawPosY; dis.rcItem.top = nDrawPosY;
dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight; dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
OffsetRect(&dis.rcItem, ptOrig.x, 0); OffsetRect(&dis.rcItem, ptOrig.x, 0);
dis.itemData = item.lParam;
TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem)); TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem));
SendMessageW(GetParent(infoPtr->hwndSelf), WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); SendMessageW(GetParent(infoPtr->hwndSelf), WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
@ -4746,6 +4784,7 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
if (lpLVItem->mask & LVIF_STATE) if (lpLVItem->mask & LVIF_STATE)
dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask; dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask;
notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
dispInfo.item.stateMask = lpLVItem->stateMask;
*lpLVItem = dispInfo.item; *lpLVItem = dispInfo.item;
TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW)); TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
} }
@ -4754,7 +4793,7 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE; if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
/* if focus is handled by us, report it */ /* if focus is handled by us, report it */
if ( !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
{ {
lpLVItem->state &= ~LVIS_FOCUSED; lpLVItem->state &= ~LVIS_FOCUSED;
if (infoPtr->nFocusedItem == lpLVItem->iItem) if (infoPtr->nFocusedItem == lpLVItem->iItem)
@ -4762,11 +4801,10 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
} }
/* and do the same for selection, if we handle it */ /* 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; lpLVItem->state &= ~LVIS_SELECTED;
if ((lpLVItem->stateMask & LVIS_SELECTED) && if (is_item_selected(infoPtr, lpLVItem->iItem))
is_item_selected(infoPtr, lpLVItem->iItem))
lpLVItem->state |= LVIS_SELECTED; lpLVItem->state |= LVIS_SELECTED;
} }
@ -4866,17 +4904,16 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
lpLVItem->state &= ~dispInfo.item.stateMask; lpLVItem->state &= ~dispInfo.item.stateMask;
lpLVItem->state |= (dispInfo.item.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; lpLVItem->state &= ~LVIS_FOCUSED;
if (infoPtr->nFocusedItem == lpLVItem->iItem) if (infoPtr->nFocusedItem == lpLVItem->iItem)
lpLVItem->state |= LVIS_FOCUSED; lpLVItem->state |= LVIS_FOCUSED;
} }
if ( !(infoPtr->uCallbackMask & LVIS_SELECTED) ) if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
{ {
lpLVItem->state &= ~LVIS_SELECTED; lpLVItem->state &= ~LVIS_SELECTED;
if ((lpLVItem->stateMask & LVIS_SELECTED) && if (is_item_selected(infoPtr, lpLVItem->iItem))
is_item_selected(infoPtr, lpLVItem->iItem))
lpLVItem->state |= LVIS_SELECTED; lpLVItem->state |= LVIS_SELECTED;
} }
} }
@ -5517,31 +5554,6 @@ static BOOL LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
return TRUE; return TRUE;
} }
/***
* 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: * DESCRIPTION:
* Retrieves the width of a string. * Retrieves the width of a string.
@ -7688,11 +7700,12 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
infoPtr->bLButtonDown = TRUE; infoPtr->bLButtonDown = TRUE;
nItem = LISTVIEW_GetItemAtPt(infoPtr, pt); nItem = LISTVIEW_GetItemAtPt(infoPtr, pt);
TRACE("nItem=%d\n", nItem);
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
{ {
if (lStyle & LVS_SINGLESEL) 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 == -1)
infoPtr->nEditLabelItem = nItem; infoPtr->nEditLabelItem = nItem;
else else
@ -7708,12 +7721,10 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
{ {
LVITEMW item; LVITEMW item;
item.state = LVIS_SELECTED; item.state = LVIS_SELECTED | LVIS_FOCUSED;
item.stateMask = LVIS_SELECTED; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
LISTVIEW_SetItemState(infoPtr,nItem,&item); LISTVIEW_SetItemState(infoPtr,nItem,&item);
LISTVIEW_SetItemFocus(infoPtr, nItem);
infoPtr->nSelectionMark = nItem; infoPtr->nSelectionMark = nItem;
} }
} }
@ -7723,11 +7734,9 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0); bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
item.state = bGroupSelect ? LVIS_SELECTED : 0; item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED;
item.stateMask = LVIS_SELECTED; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
LISTVIEW_SetItemState(infoPtr, nItem, &item); LISTVIEW_SetItemState(infoPtr, nItem, &item);
LISTVIEW_SetItemFocus(infoPtr, nItem);
infoPtr->nSelectionMark = nItem; infoPtr->nSelectionMark = nItem;
} }
else if (wKey & MK_SHIFT) else if (wKey & MK_SHIFT)
@ -7736,8 +7745,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
} }
else else
{ {
BOOL was_selected = BOOL was_selected = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
(LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) & LVIS_SELECTED);
/* set selection (clears other pre-existing selections) */ /* set selection (clears other pre-existing selections) */
LISTVIEW_SetSelection(infoPtr, nItem); LISTVIEW_SetSelection(infoPtr, nItem);