2015-05-01 12:23:03 +02:00
|
|
|
unit UndoRedoCmd;
|
|
|
|
|
|
|
|
interface
|
|
|
|
uses
|
2023-01-15 16:37:33 +01:00
|
|
|
Classes, SysUtils, laz.VirtualTrees;
|
2015-05-01 12:23:03 +02:00
|
|
|
|
|
|
|
type
|
|
|
|
IUndoRedoCommand = interface (IUnknown)
|
|
|
|
['{D84BFD00-8396-11D6-B4FA-000021D960D4}']
|
|
|
|
procedure Execute;
|
|
|
|
procedure Redo;
|
|
|
|
procedure Undo;
|
|
|
|
end;
|
|
|
|
|
|
|
|
IUndoRedoCommandGroup = interface (IUndoRedoCommand)
|
|
|
|
['{9169AE00-839B-11D6-B4FA-000021D960D4}']
|
|
|
|
function GetUndoRedoCommands: TInterfaceList;
|
|
|
|
property UndoRedoCommands: TInterfaceList read GetUndoRedoCommands;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TUndoRedoCommandGroup = class (TInterfacedObject, IUndoRedoCommandGroup,
|
|
|
|
IUndoRedoCommand)
|
|
|
|
private
|
|
|
|
FList: TInterfaceList;
|
|
|
|
FCanRedo: Boolean;
|
|
|
|
public
|
|
|
|
constructor Create;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure Add(const AUndoRedoCommand: IUndoRedoCommand);
|
|
|
|
procedure Execute;
|
|
|
|
function GetUndoRedoCommands: TInterfaceList;
|
|
|
|
procedure Redo;
|
|
|
|
procedure Undo;
|
|
|
|
property UndoRedoCommands: TInterfaceList read GetUndoRedoCommands;
|
|
|
|
end;
|
|
|
|
|
|
|
|
TUndoRedoManager = class (TObject)
|
|
|
|
private
|
|
|
|
FRedoList: TInterfaceList;
|
|
|
|
FUndoList: TInterfaceList;
|
|
|
|
FTransactLevel: Integer;
|
|
|
|
FTransaction: IUndoRedoCommandGroup;
|
|
|
|
function GetCanRedo: Integer;
|
|
|
|
function GetCanUndo: Integer;
|
|
|
|
public
|
|
|
|
Enabled: Boolean;
|
|
|
|
constructor Create;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure BeginTransaction;
|
|
|
|
procedure EndTransaction;
|
|
|
|
procedure ExecCommand(const AUndoRedoCommand: IUndoRedoCommand);
|
|
|
|
procedure Redo(RedoCount: Integer = 1);
|
|
|
|
procedure Undo(UndoCount: Integer = 1);
|
|
|
|
property CanRedo: Integer read GetCanRedo;
|
|
|
|
property CanUndo: Integer read GetCanUndo;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
TUndoRedoSelectVirtualNodeCommand = class (TInterfacedObject, IUndoRedoCommand)
|
|
|
|
private
|
|
|
|
m_UndoRedoManag : TUndoRedoManager;
|
|
|
|
m_VirtualTree: TBaseVirtualTree;
|
|
|
|
m_VirtualNode: PVirtualNode;
|
|
|
|
m_ForwardDir : Boolean;
|
|
|
|
public
|
|
|
|
constructor Create(UndoRedoManag: TUndoRedoManager; VirtualTree: TBaseVirtualTree; VirtualNode: PVirtualNode);
|
|
|
|
//destructor Destroy; override;
|
|
|
|
procedure Execute;
|
|
|
|
procedure Redo;
|
|
|
|
procedure Undo;
|
|
|
|
end;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
{
|
|
|
|
**************************** TCommands Types ***********************************
|
|
|
|
}
|
|
|
|
constructor TUndoRedoSelectVirtualNodeCommand.Create(
|
|
|
|
UndoRedoManag: TUndoRedoManager; VirtualTree: TBaseVirtualTree; VirtualNode: PVirtualNode);
|
|
|
|
begin
|
|
|
|
m_UndoRedoManag := UndoRedoManag;
|
|
|
|
m_VirtualTree := VirtualTree;
|
|
|
|
m_VirtualNode := VirtualNode;
|
|
|
|
m_ForwardDir := VirtualTree.Selected[VirtualNode];
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoSelectVirtualNodeCommand.Execute;
|
|
|
|
begin
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoSelectVirtualNodeCommand.Redo;
|
|
|
|
begin
|
|
|
|
m_UndoRedoManag.Enabled := False;
|
|
|
|
m_VirtualTree.Selected[m_VirtualNode] := m_ForwardDir;
|
|
|
|
m_UndoRedoManag.Enabled := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoSelectVirtualNodeCommand.Undo;
|
|
|
|
begin
|
|
|
|
m_UndoRedoManag.Enabled := False;
|
|
|
|
//m_VirtualTree.Selected[m_VirtualNode] := not m_ForwardDir;
|
|
|
|
if m_ForwardDir
|
|
|
|
then m_VirtualTree.Selected[m_VirtualNode] := False
|
|
|
|
else m_VirtualTree.Selected[m_VirtualNode] := True;
|
|
|
|
m_UndoRedoManag.Enabled := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{
|
|
|
|
**************************** TUndoRedoCommandGroup *****************************
|
|
|
|
}
|
|
|
|
constructor TUndoRedoCommandGroup.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
FList:= TInterfaceList.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TUndoRedoCommandGroup.Destroy;
|
|
|
|
begin
|
|
|
|
FList.Free;
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoCommandGroup.Add(const AUndoRedoCommand: IUndoRedoCommand);
|
|
|
|
begin
|
|
|
|
FList.Add(AUndoRedoCommand);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoCommandGroup.Execute;
|
|
|
|
var
|
|
|
|
I: Integer;
|
|
|
|
begin
|
|
|
|
for I:= 0 to FList.Count-1 do
|
|
|
|
(FList[I] as IUndoRedoCommand).Execute;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TUndoRedoCommandGroup.GetUndoRedoCommands: TInterfaceList;
|
|
|
|
begin
|
|
|
|
Result:= FList;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoCommandGroup.Redo;
|
|
|
|
var
|
|
|
|
I: Integer;
|
|
|
|
begin
|
|
|
|
if FCanRedo then
|
|
|
|
begin
|
|
|
|
for I:= 0 to FList.Count-1 do
|
|
|
|
(FList[I] as IUndoRedoCommand).Redo;
|
|
|
|
|
|
|
|
FCanRedo:= False;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
raise Exception.Create('Must call TUndoRedoCommandGroup.Undo before calling Redo.');
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoCommandGroup.Undo;
|
|
|
|
var
|
|
|
|
I: Integer;
|
|
|
|
begin
|
|
|
|
if FCanRedo then
|
|
|
|
raise Exception.Create('TUndoRedoCommandGroup.Undo already called');
|
|
|
|
|
|
|
|
for I:= FList.Count-1 downto 0 do
|
|
|
|
(FList[I] as IUndoRedoCommand).Undo;
|
|
|
|
|
|
|
|
FCanRedo:= True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{
|
|
|
|
******************************* TUndoRedoManager *******************************
|
|
|
|
}
|
|
|
|
constructor TUndoRedoManager.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
FRedoList:= TInterfaceList.Create;
|
|
|
|
FUndoList:= TInterfaceList.Create;
|
|
|
|
Enabled := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TUndoRedoManager.Destroy;
|
|
|
|
begin
|
|
|
|
FRedoList.Free;
|
|
|
|
FUndoList.Free;
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoManager.BeginTransaction;
|
|
|
|
begin
|
|
|
|
Inc(FTransactLevel);
|
|
|
|
if FTransactLevel = 1 then
|
|
|
|
FTransaction:= TUndoRedoCommandGroup.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoManager.EndTransaction;
|
|
|
|
begin
|
|
|
|
Dec(FTransactLevel);
|
|
|
|
if (FTransactLevel = 0) then
|
|
|
|
begin
|
|
|
|
if FTransaction.UndoRedoCommands.Count > 0 then
|
|
|
|
begin
|
|
|
|
FRedoList.Clear;
|
|
|
|
FUndoList.Add(FTransaction);
|
|
|
|
end;
|
|
|
|
FTransaction:= nil;
|
|
|
|
end
|
|
|
|
else if FTransactLevel < 0 then
|
|
|
|
raise Exception.Create('Unmatched TUndoRedoManager.BeginTransaction and EndTransaction');
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoManager.ExecCommand(const AUndoRedoCommand: IUndoRedoCommand);
|
|
|
|
begin
|
|
|
|
if Enabled then begin
|
|
|
|
BeginTransaction;
|
|
|
|
try
|
|
|
|
FTransaction.UndoRedoCommands.Add(AUndoRedoCommand);
|
|
|
|
AUndoRedoCommand.Execute;
|
|
|
|
finally
|
|
|
|
EndTransaction;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TUndoRedoManager.GetCanRedo: Integer;
|
|
|
|
begin
|
|
|
|
Result:= FRedoList.Count;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TUndoRedoManager.GetCanUndo: Integer;
|
|
|
|
begin
|
|
|
|
Result:= FUndoList.Count;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoManager.Redo(RedoCount: Integer = 1);
|
|
|
|
var
|
|
|
|
I: Integer;
|
|
|
|
Item: IUndoRedoCommand;
|
|
|
|
RedoLast: Integer;
|
|
|
|
begin
|
|
|
|
if FTransactLevel <> 0 then
|
|
|
|
raise Exception.Create('Cannot Redo while in Transaction');
|
|
|
|
|
|
|
|
// Index of last redo item
|
|
|
|
RedoLast:= FRedoList.Count - RedoCount;
|
|
|
|
if RedoLast < 0 then
|
|
|
|
RedoLast:= 0;
|
|
|
|
|
|
|
|
for I:= FRedoList.Count-1 downto RedoLast do
|
|
|
|
begin
|
|
|
|
Item:= FRedoList[I] as IUndoRedoCommand;
|
|
|
|
FRedoList.Delete(I);
|
|
|
|
FUndoList.Add(Item);
|
|
|
|
Item.Redo;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TUndoRedoManager.Undo(UndoCount: Integer = 1);
|
|
|
|
var
|
|
|
|
I: Integer;
|
|
|
|
Item: IUndoRedoCommand;
|
|
|
|
UndoLast: Integer;
|
|
|
|
begin
|
|
|
|
if FTransactLevel <> 0 then
|
|
|
|
raise Exception.Create('Cannot undo while in Transaction');
|
|
|
|
|
|
|
|
// Index of last undo item
|
|
|
|
UndoLast:= FUndoList.Count - UndoCount;
|
|
|
|
if UndoLast < 0 then
|
|
|
|
UndoLast:= 0;
|
|
|
|
|
|
|
|
for I:= FUndoList.Count-1 downto UndoLast do
|
|
|
|
begin
|
|
|
|
Item:= FUndoList[I] as IUndoRedoCommand;
|
|
|
|
FUndoList.Delete(I);
|
|
|
|
FRedoList.Add(Item);
|
|
|
|
Item.Undo;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|