comctl32/listview: Fix LVM_INSERTITEM handling on LVS_SORTxxx styles.
This commit is contained in:
parent
ac8c6a526f
commit
2829c5fd1e
|
@ -63,8 +63,9 @@
|
|||
* -- LISTVIEW_GetNextItem needs to be rewritten. It is currently
|
||||
* linear in the number of items in the list, and this is
|
||||
* unacceptable for large lists.
|
||||
* -- in sorted mode, LISTVIEW_InsertItemT sorts the array,
|
||||
* instead of inserting in the right spot
|
||||
* -- if list is sorted by item text LISTVIEW_InsertItemT could use
|
||||
* binary search to calculate item index (e.g. DPA_Search()).
|
||||
* This requires sorted state to be reliably tracked in item modifiers.
|
||||
* -- we should keep an ordered array of coordinates in iconic mode
|
||||
* this would allow to frame items (iterator_frameditems),
|
||||
* and find nearest item (LVFI_NEARESTXY) a lot more efficiently
|
||||
|
@ -6592,33 +6593,6 @@ static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht,
|
|||
return lpht->iItem = iItem;
|
||||
}
|
||||
|
||||
|
||||
/* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
|
||||
in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
|
||||
This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
|
||||
and not during the processing of a LVM_SORTITEMS message. Applications should provide
|
||||
their own sort proc. when sending LVM_SORTITEMS.
|
||||
*/
|
||||
/* Platform SDK:
|
||||
(remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
|
||||
if:
|
||||
LVS_SORTXXX must be specified,
|
||||
LVS_OWNERDRAW is not set,
|
||||
<item>.pszText is not LPSTR_TEXTCALLBACK.
|
||||
|
||||
(LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
|
||||
are sorted based on item text..."
|
||||
*/
|
||||
static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
|
||||
{
|
||||
ITEM_INFO* lv_first = DPA_GetPtr( first, 0 );
|
||||
ITEM_INFO* lv_second = DPA_GetPtr( second, 0 );
|
||||
INT cmpv = textcmpWT(lv_first->hdr.pszText, lv_second->hdr.pszText, TRUE);
|
||||
|
||||
/* if we're sorting descending, negate the return value */
|
||||
return (((const LISTVIEW_INFO *)lParam)->dwStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
|
||||
}
|
||||
|
||||
/***
|
||||
* DESCRIPTION:
|
||||
* Inserts a new item in the listview control.
|
||||
|
@ -6663,7 +6637,29 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
|
|||
|
||||
if (lpLVItem->iItem < 0 && !is_sorted) return -1;
|
||||
|
||||
nItem = is_sorted ? infoPtr->nItemCount : min(lpLVItem->iItem, infoPtr->nItemCount);
|
||||
/* calculate new item index */
|
||||
if (is_sorted)
|
||||
{
|
||||
HDPA hItem;
|
||||
ITEM_INFO *item_s;
|
||||
INT i = 0, cmpv;
|
||||
|
||||
while (i < infoPtr->nItemCount)
|
||||
{
|
||||
hItem = DPA_GetPtr( infoPtr->hdpaItems, i);
|
||||
item_s = (ITEM_INFO*)DPA_GetPtr(hItem, 0);
|
||||
|
||||
cmpv = textcmpWT(item_s->hdr.pszText, lpLVItem->pszText, TRUE);
|
||||
if (infoPtr->dwStyle & LVS_SORTDESCENDING) cmpv *= -1;
|
||||
|
||||
if (cmpv >= 0) break;
|
||||
i++;
|
||||
}
|
||||
nItem = i;
|
||||
}
|
||||
else
|
||||
nItem = min(lpLVItem->iItem, infoPtr->nItemCount);
|
||||
|
||||
TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem);
|
||||
nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems );
|
||||
if (nItem == -1) goto fail;
|
||||
|
@ -6698,14 +6694,6 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
|
|||
}
|
||||
if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo;
|
||||
|
||||
/* if we're sorted, sort the list, and update the index */
|
||||
if (is_sorted)
|
||||
{
|
||||
DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr );
|
||||
nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
|
||||
assert(nItem != -1);
|
||||
}
|
||||
|
||||
/* make room for the position, if we are in the right mode */
|
||||
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
|
||||
{
|
||||
|
|
|
@ -1629,7 +1629,7 @@ static void test_sorting(void)
|
|||
LVITEMA item = {0};
|
||||
DWORD r;
|
||||
LONG_PTR style;
|
||||
static CHAR names[][4] = {"A", "B", "C", "D"};
|
||||
static CHAR names[][5] = {"A", "B", "C", "D", "0"};
|
||||
CHAR buff[10];
|
||||
|
||||
hwnd = create_listview_control(0);
|
||||
|
@ -1744,23 +1744,60 @@ static void test_sorting(void)
|
|||
item.cchTextMax = sizeof(buff);
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
todo_wine ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
|
||||
ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
|
||||
|
||||
item.iItem = 1;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
todo_wine ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
|
||||
ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
|
||||
|
||||
item.iItem = 2;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
todo_wine ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
|
||||
ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
|
||||
|
||||
item.iItem = 3;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
|
||||
|
||||
/* corner case - item should be placed at first position */
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = 4;
|
||||
item.iSubItem = 0;
|
||||
item.pszText = names[4];
|
||||
r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
|
||||
expect(0, r);
|
||||
|
||||
item.iItem = 0;
|
||||
item.pszText = buff;
|
||||
item.cchTextMax = sizeof(buff);
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
|
||||
|
||||
item.iItem = 1;
|
||||
item.pszText = buff;
|
||||
item.cchTextMax = sizeof(buff);
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
|
||||
|
||||
item.iItem = 2;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
|
||||
|
||||
item.iItem = 3;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
|
||||
|
||||
item.iItem = 4;
|
||||
r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
|
||||
expect(TRUE, r);
|
||||
ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
|
||||
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue