Commit 76f397e3 authored by Dimitrie O. Paun's avatar Dimitrie O. Paun Committed by Alexandre Julliard

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.
parent f645727a
...@@ -1810,16 +1810,14 @@ static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *infoPtr) ...@@ -1810,16 +1810,14 @@ 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 i;
INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
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
...@@ -2092,6 +2090,42 @@ static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr) ...@@ -2092,6 +2090,42 @@ static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr)
/*** /***
* DESCRIPTION: * 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. * Manages the item focus.
* *
* PARAMETER(S): * PARAMETER(S):
...@@ -2231,13 +2265,20 @@ static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) ...@@ -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) ...@@ -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) ...@@ -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; for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
}
item.stateMask = LVIS_SELECTED;
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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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;
} }
} }
...@@ -5519,31 +5556,6 @@ static BOOL LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin) ...@@ -5519,31 +5556,6 @@ static BOOL LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
/*** /***
* DESCRIPTION: * 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. * Retrieves the width of a string.
* *
* PARAMETER(S): * PARAMETER(S):
...@@ -7688,11 +7700,12 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment