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 -
This commit is contained in:
zeljko 2011-06-25 08:31:57 +00:00
parent c74cdc3959
commit cd32bf59f0
6 changed files with 87 additions and 54 deletions

View File

@ -1011,7 +1011,8 @@ type
TListHotTrackStyles = set of TListHotTrackStyle;
TListViewFlag = (
lffSelectedValid
lffSelectedValid,
lffItemsMoving
);
TListViewFlags = set of TListViewFlag;

View File

@ -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;
{------------------------------------------------------------------------------}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;