From cd32bf59f003135d43331b96f826af05e6097668 Mon Sep 17 00:00:00 2001 From: zeljko Date: Sat, 25 Jun 2011 08:31:57 +0000 Subject: [PATCH] LCL: preserve selection when moving items. Return cached checked item when moving items. Win32: simplified LVItem assigning in case of exchange and move, fixed bugs git-svn-id: trunk@31373 - --- lcl/comctrls.pp | 3 +- lcl/include/customlistview.inc | 3 +- lcl/include/listitem.inc | 3 +- lcl/include/listitems.inc | 55 ++++++++++---- lcl/interfaces/win32/win32wscomctrls.pp | 1 + .../win32/win32wscustomlistview.inc | 76 ++++++++++--------- 6 files changed, 87 insertions(+), 54 deletions(-) diff --git a/lcl/comctrls.pp b/lcl/comctrls.pp index f828b43bb5..2a2a6d605e 100644 --- a/lcl/comctrls.pp +++ b/lcl/comctrls.pp @@ -1011,7 +1011,8 @@ type TListHotTrackStyles = set of TListHotTrackStyle; TListViewFlag = ( - lffSelectedValid + lffSelectedValid, + lffItemsMoving ); TListViewFlags = set of TListViewFlag; diff --git a/lcl/include/customlistview.inc b/lcl/include/customlistview.inc index 2220f1cfe6..d409bda48b 100644 --- a/lcl/include/customlistview.inc +++ b/lcl/include/customlistview.inc @@ -427,7 +427,8 @@ end; procedure TCustomListView.DoSelectItem(AItem: TListItem; ASelected: Boolean); begin AItem.Selected:=ASelected; - if Assigned(FOnSelectItem) then FOnSelectItem(Self, AItem, ASelected); + if Assigned(FOnSelectItem) and not (lffItemsMoving in FFlags) then + FOnSelectItem(Self, AItem, ASelected); end; {------------------------------------------------------------------------------} diff --git a/lcl/include/listitem.inc b/lcl/include/listitem.inc index 11817a74b9..3a9866e7d9 100644 --- a/lcl/include/listitem.inc +++ b/lcl/include/listitem.inc @@ -523,7 +523,8 @@ var LV: TCustomListView; begin LV := FOwner.FOwner; - Result := LV.Checkboxes and WSUpdateAllowed; + // we are using cached data when moving or exchanging items + Result := LV.Checkboxes and WSUpdateAllowed and not (lffItemsMoving in LV.FFlags); if Result then Result := TWSCustomListViewClass(LV.WidgetSetClass).ItemGetChecked(LV, GetIndex, Self) else diff --git a/lcl/include/listitems.inc b/lcl/include/listitems.inc index 14a02d793a..11c620178c 100644 --- a/lcl/include/listitems.inc +++ b/lcl/include/listitems.inc @@ -147,6 +147,8 @@ end; procedure TListItems.Exchange(const AIndex1, AIndex2: Integer); var AItem: TListItem; + SelItem: TListItem; + FocusItem: TListItem; begin if AIndex1 = AIndex2 then exit; @@ -155,19 +157,33 @@ begin if (AIndex2 < 0) or (AIndex2 >= FItems.Count) then raise Exception.CreateFmt(rsListIndexExceedsBounds, [AIndex2]); AItem := Item[AIndex1]; - FItems.Exchange(AIndex1, AIndex2); - FCacheIndex := AIndex1; - FCacheItem := AItem; - if not Owner.OwnerData and WSUpdateAllowed then - begin - TWSCustomListViewClass(FOwner.WidgetSetClass).ItemExchange(FOwner, AItem, - AIndex1, AIndex2); + SelItem := Owner.Selected; + FocusItem := Owner.ItemFocused; + + Include(Owner.FFlags, lffItemsMoving); + try + FItems.Exchange(AIndex1, AIndex2); + FCacheIndex := AIndex1; + FCacheItem := AItem; + if not Owner.OwnerData and WSUpdateAllowed then + begin + TWSCustomListViewClass(FOwner.WidgetSetClass).ItemExchange(FOwner, AItem, + AIndex1, AIndex2); + Owner.InvalidateSelected; + Owner.ItemFocused := nil; + Owner.Selected := SelItem; + Owner.ItemFocused := FocusItem; + end; + finally + Exclude(Owner.FFlags, lffItemsMoving); end; end; procedure TListItems.Move(const AFromIndex, AToIndex: Integer); var AItem: TListItem; + SelItem: TListItem; + FocusItem: TListItem; begin if AFromIndex = AToIndex then exit; @@ -176,13 +192,24 @@ begin if (AToIndex < 0) or (AToIndex >= FItems.Count) then raise Exception.CreateFmt(rsListIndexExceedsBounds, [AToIndex]); AItem := Item[AFromIndex]; - FItems.Move(AFromIndex, AToIndex); - FCacheIndex := AToIndex; - FCacheItem := AItem; - if not Owner.OwnerData and WSUpdateAllowed then - begin - TWSCustomListViewClass(FOwner.WidgetSetClass).ItemMove(FOwner, AItem, - AFromIndex, AToIndex); + SelItem := Owner.Selected; + FocusItem := Owner.ItemFocused; + Include(Owner.FFlags, lffItemsMoving); + try + FItems.Move(AFromIndex, AToIndex); + FCacheIndex := AToIndex; + FCacheItem := AItem; + if not Owner.OwnerData and WSUpdateAllowed then + begin + TWSCustomListViewClass(FOwner.WidgetSetClass).ItemMove(FOwner, AItem, + AFromIndex, AToIndex); + Owner.InvalidateSelected; + Owner.ItemFocused := nil; + Owner.Selected := SelItem; + Owner.ItemFocused := FocusItem; + end; + finally + Exclude(Owner.FFlags, lffItemsMoving); end; end; diff --git a/lcl/interfaces/win32/win32wscomctrls.pp b/lcl/interfaces/win32/win32wscomctrls.pp index 47782e1fdd..51f57be403 100644 --- a/lcl/interfaces/win32/win32wscomctrls.pp +++ b/lcl/interfaces/win32/win32wscomctrls.pp @@ -83,6 +83,7 @@ type class procedure PositionHeader(const AHandle: THandle); class procedure UpdateStyle(const AHandle: THandle; const AMask, AStyle: Integer); class procedure UpdateExStyle(const AHandle: THandle; const AMask, AStyle: Integer); + class procedure LVItemAssign(const ALV: TCustomListView; AItem: TListItem; const AIndex: Integer); published // columns class procedure ColumnDelete(const ALV: TCustomListView; const AIndex: Integer); override; diff --git a/lcl/interfaces/win32/win32wscustomlistview.inc b/lcl/interfaces/win32/win32wscustomlistview.inc index 67fbac44fc..7b490e1b86 100644 --- a/lcl/interfaces/win32/win32wscustomlistview.inc +++ b/lcl/interfaces/win32/win32wscustomlistview.inc @@ -529,6 +529,31 @@ begin SendMessage(ALV.Handle, mes, AIndex, lparam(@Result)); end; +class procedure TWin32WSCustomListView.LVItemAssign(const ALV: TCustomListView; + AItem: TListItem; const AIndex: Integer); +var + i: Integer; + B: Boolean; +begin + if ALV.CheckBoxes then + B := AItem.Checked; + ItemSetText(ALV, AIndex, AItem, 0, AItem.Caption); + for i := 0 to AItem.SubItems.Count - 1 do + ItemSetText(ALV, AIndex, AItem, i + 1, AItem.SubItems[i]); + + // set state images + if Assigned(TListView(ALV).StateImages) then + ItemSetStateImage(ALV, AIndex,AItem,0, AItem.StateIndex); + + // set images + if AItem.ImageIndex >= 0 then + ItemSetImage(ALV, AIndex, AItem, 0, AItem.ImageIndex); + + // apply checkbox states + if ALV.Checkboxes then + ItemSetChecked(ALV, AIndex, AItem, B); +end; + class procedure TWin32WSCustomListView.ItemExchange(const ALV: TCustomListView; AItem: TListItem; const AIndex1, AIndex2: Integer); var @@ -544,51 +569,27 @@ begin AItem1 := ALV.Items[AIndex2]; AItem2 := ALV.Items[AIndex1]; - if ALV.Checkboxes then - begin - B2 := AItem1.Checked; - B1 := AItem2.Checked; - end; - ItemSetText(ALV, AIndex2, AItem1, 0, AItem1.Caption); - for i := 0 to AItem1.SubItems.Count - 1 do - ItemSetText(ALV, AIndex2, AItem1, i + 1, AItem1.SubItems[i]); - - - ItemSetText(ALV, AIndex1, AItem2, 0, AItem2.Caption); - for i := 0 to AItem2.SubItems.Count - 1 do - ItemSetText(ALV, AIndex1, AItem2, i + 1, AItem2.SubItems[i]); - - - // set state images - if Assigned(TListView(ALV).StateImages) then - begin - ItemSetStateImage(ALV, AIndex2,AItem1,0, AItem1.StateIndex); - ItemSetStateImage(ALV, AIndex1,AItem2,0, AItem2.StateIndex); - end; - - // set images - if AItem1.ImageIndex >= 0 then - ItemSetImage(ALV, AIndex2, AItem1, 0, AItem1.ImageIndex); - if AItem2.ImageIndex >= 0 then - ItemSetImage(ALV, AIndex1, AItem2, 0, AItem2.ImageIndex); - - // apply checkbox states - if ALV.Checkboxes then - begin - ItemSetChecked(ALV, AIndex2, AItem1, B1); - ItemSetChecked(ALV, AIndex1, AItem2, B2); - end; - //TODO: selection and focused item. - // that works but triggers selection change in LCL ... + LVItemAssign(ALV, AItem1, AIndex2); + LVItemAssign(ALV, AItem2, AIndex1); end; class procedure TWin32WSCustomListView.ItemMove(const ALV: TCustomListView; AItem: TListItem; const AFromIndex, AToIndex: Integer); +var + i: Integer; begin if not WSCheckHandleAllocated(ALV, 'ItemMove') then exit; - ItemExchange(ALV, AItem, AFromIndex, AToIndex); + if AFromIndex = AToIndex then + exit; + if AFromIndex > AToIndex then + begin + for i := AToIndex to AFromIndex do + LVItemAssign(ALV, ALV.Items[i], i); + end else + for i := AFromIndex to AToIndex do + LVItemAssign(ALV, ALV.Items[i], i); end; class function TWin32WSCustomListView.ItemGetChecked(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem): Boolean; @@ -1316,3 +1317,4 @@ begin Windows.InvalidateRect(AHandle, nil, true); end; +