Update nSelectionMark and nFocusedItem when inserting/deleting/sorting items. SortItems: If sorting less than 2 items, do nothing.
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 436a342..b5fb2ce 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c
@@ -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 +7428,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 +7450,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);