274 lines
5.7 KiB
ObjectPascal
274 lines
5.7 KiB
ObjectPascal
unit ATStrings_Undo;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, StrUtils,
|
|
ATStringProc;
|
|
|
|
type
|
|
TATEditAction = (
|
|
cEditActionChange,
|
|
cEditActionChangeEol,
|
|
cEditActionInsert,
|
|
cEditActionDelete,
|
|
cEditActionClearModified
|
|
);
|
|
|
|
const
|
|
StrEditActionDescriptions: array[TATEditAction] of string = (
|
|
'change',
|
|
'change-eol',
|
|
'insert',
|
|
'delete',
|
|
'clear-mod'
|
|
);
|
|
|
|
type
|
|
{ TATUndoItem }
|
|
|
|
TATUndoItem = class
|
|
ItemAction: TATEditAction;
|
|
ItemIndex: integer;
|
|
ItemText: atString;
|
|
ItemEnd: TATLineEnds;
|
|
ItemCarets: TATPointArray;
|
|
ItemSoftMark: boolean;
|
|
ItemHardMark: boolean;
|
|
constructor Create(AAction: TATEditAction; AIndex: integer;
|
|
const AText: atString; AEnd: TATLineEnds; ASoftMark, AHardMark: boolean;
|
|
const ACarets: TATPointArray); virtual;
|
|
end;
|
|
|
|
type
|
|
{ TATUndoList }
|
|
|
|
TATUndoList = class
|
|
private
|
|
FList: TList;
|
|
FMaxCount: integer;
|
|
FLocked: boolean;
|
|
FSoftMark: boolean;
|
|
FHardMark: boolean;
|
|
function GetItem(N: integer): TATUndoItem;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
function IsIndexValid(N: integer): boolean;
|
|
function IsItemsEqual(N1, N2: integer): boolean;
|
|
function Count: integer;
|
|
function Last: TATUndoItem;
|
|
property Items[N: integer]: TATUndoItem read GetItem; default;
|
|
property MaxCount: integer read FMaxCount write FMaxCount;
|
|
property SoftMark: boolean read FSoftMark write FSoftMark;
|
|
property HardMark: boolean read FHardMark write FHardMark;
|
|
property Locked: boolean read FLocked write FLocked;
|
|
procedure Clear;
|
|
procedure Delete(N: integer);
|
|
procedure DeleteLast;
|
|
procedure DeleteUnmodifiedMarks;
|
|
procedure Add(AAction: TATEditAction; AIndex: integer; const AText: atString;
|
|
AEnd: TATLineEnds; const ACarets: TATPointArray);
|
|
procedure AddUnmodifiedMark;
|
|
procedure DebugShow;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math, Dialogs;
|
|
|
|
{ TATUndoItem }
|
|
|
|
constructor TATUndoItem.Create(AAction: TATEditAction; AIndex: integer;
|
|
const AText: atString; AEnd: TATLineEnds; ASoftMark, AHardMark: boolean;
|
|
const ACarets: TATPointArray);
|
|
var
|
|
i: integer;
|
|
begin
|
|
ItemAction:= AAction;
|
|
ItemIndex:= AIndex;
|
|
ItemText:= AText;
|
|
ItemEnd:= AEnd;
|
|
ItemSoftMark:= ASoftMark;
|
|
ItemHardMark:= AHardMark;
|
|
|
|
SetLength(ItemCarets, Length(ACarets));
|
|
for i:= 0 to High(ACarets) do
|
|
begin
|
|
ItemCarets[i]:= ACarets[i];
|
|
end;
|
|
end;
|
|
|
|
{ TATUndoList }
|
|
|
|
function TATUndoList.GetItem(N: integer): TATUndoItem;
|
|
begin
|
|
if IsIndexValid(N) then
|
|
Result:= TATUndoItem(FList[N])
|
|
else
|
|
Result:= nil;
|
|
end;
|
|
|
|
constructor TATUndoList.Create;
|
|
begin
|
|
FList:= TList.Create;
|
|
FMaxCount:= 5000;
|
|
FSoftMark:= false;
|
|
FHardMark:= false;
|
|
FLocked:= false;
|
|
end;
|
|
|
|
destructor TATUndoList.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(FList);
|
|
inherited;
|
|
end;
|
|
|
|
function TATUndoList.Count: integer;
|
|
begin
|
|
Result:= FList.Count;
|
|
end;
|
|
|
|
function TATUndoList.IsIndexValid(N: integer): boolean;
|
|
begin
|
|
Result:= (N>=0) and (N<Count);
|
|
end;
|
|
|
|
function TATUndoList.IsItemsEqual(N1, N2: integer): boolean;
|
|
var
|
|
i1, i2: TATUndoItem;
|
|
begin
|
|
Result:= false;
|
|
i1:= Items[N1];
|
|
i2:= Items[N2];
|
|
if not Assigned(i1) or not Assigned(i2) then Exit;
|
|
Result:=
|
|
(i1.ItemAction=cEditActionChange) and
|
|
(i1.ItemAction=i2.ItemAction) and
|
|
(i1.ItemIndex=i2.ItemIndex) and
|
|
(i1.ItemText=i2.ItemText);
|
|
end;
|
|
|
|
procedure TATUndoList.Delete(N: integer);
|
|
begin
|
|
if IsIndexValid(N) then
|
|
begin
|
|
TObject(FList[N]).Free;
|
|
FList.Delete(N);
|
|
end;
|
|
end;
|
|
|
|
procedure TATUndoList.DeleteLast;
|
|
begin
|
|
Delete(Count-1);
|
|
end;
|
|
|
|
procedure TATUndoList.Clear;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:= Count-1 downto 0 do
|
|
Delete(i);
|
|
end;
|
|
|
|
procedure TATUndoList.Add(AAction: TATEditAction; AIndex: integer;
|
|
const AText: atString; AEnd: TATLineEnds;
|
|
const ACarets: TATPointArray);
|
|
var
|
|
Item: TATUndoItem;
|
|
begin
|
|
if FLocked then Exit;
|
|
|
|
//not dup change?
|
|
if (Count>0) and (AAction in [cEditActionChange, cEditActionChangeEol]) then
|
|
begin
|
|
Item:= Items[Count-1];
|
|
if (Item.ItemAction=AAction) and
|
|
(Item.ItemIndex=AIndex) and
|
|
(Item.ItemText=AText) then
|
|
Exit;
|
|
end;
|
|
|
|
//not insert/delete same index?
|
|
if (Count>0) and (AAction=cEditActionDelete) then
|
|
begin
|
|
Item:= Items[Count-1];
|
|
if (Item.ItemAction=cEditActionInsert) and
|
|
(Item.ItemIndex=AIndex) then
|
|
begin
|
|
DeleteLast;
|
|
Exit
|
|
end;
|
|
end;
|
|
|
|
Item:= TATUndoItem.Create(AAction, AIndex, AText, AEnd, FSoftMark, FHardMark, ACarets);
|
|
FList.Add(Item);
|
|
FSoftMark:= false;
|
|
|
|
while Count>MaxCount do
|
|
Delete(0);
|
|
end;
|
|
|
|
|
|
procedure TATUndoList.AddUnmodifiedMark;
|
|
var
|
|
Item: TATUndoItem;
|
|
Carets: TATPointArray;
|
|
begin
|
|
//if FLocked then exit; //on load file called with Locked=true
|
|
|
|
//don't do two marks
|
|
Item:= Last;
|
|
if Assigned(Item) then
|
|
if Item.ItemAction=cEditActionClearModified then exit;
|
|
|
|
SetLength(Carets, 0);
|
|
Item:= TATUndoItem.Create(cEditActionClearModified, 0, '', cEndNone, false, false, Carets);
|
|
FList.Add(Item);
|
|
end;
|
|
|
|
procedure TATUndoList.DeleteUnmodifiedMarks;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:= Count-1 downto 0 do
|
|
if Items[i].ItemAction=cEditActionClearModified then
|
|
Delete(i);
|
|
end;
|
|
|
|
procedure TATUndoList.DebugShow;
|
|
var
|
|
i: integer;
|
|
s: string;
|
|
Item: TATUndoItem;
|
|
begin
|
|
s:= '';
|
|
for i:= 0 to Min(40, Count)-1 do
|
|
begin
|
|
Item:= Items[i];
|
|
s:= s+Format('%s, text "%s", %s, index %d', [
|
|
StrEditActionDescriptions[Item.ItemAction],
|
|
UTF8Encode(Item.ItemText),
|
|
IfThen(Item.ItemEnd=cEndNone, 'no-eol', ''),
|
|
Item.ItemIndex
|
|
])+#13;
|
|
end;
|
|
ShowMessage('Undo list:'#13+s);
|
|
end;
|
|
|
|
function TATUndoList.Last: TATUndoItem;
|
|
begin
|
|
if Count>0 then
|
|
Result:= Items[Count-1]
|
|
else
|
|
Result:= nil;
|
|
end;
|
|
|
|
end.
|
|
|