📄 rvundo.pas
字号:
Item.Caption := s;
Item.CaretItemNo := CaretItemNo;
Item.CaretOffs := CaretOffs;
Add(Item);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.EndItem;
begin
if (Count>0) and (TRVUndoInfos(Items[Count-1]).Count=0) then
Delete(Count-1);
end;
{------------------------------------------------------------------------------}
function TRVUndoList.CurrentUndoType: TRVUndoType;
begin
if Count=0 then
Result := rvutNone
else
Result := TRVUndoInfos(Items[Count-1]).UndoType;
end;
{------------------------------------------------------------------------------}
function TRVUndoList.CurrentUndoCaption: String;
begin
if Count=0 then
Result := ''
else
Result := TRVUndoInfos(Items[Count-1]).Caption;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.AddTyping(CaretItemNo, CaretOffs: Integer; Unicode: Boolean);
var info: TRVUndoTypingInfo;
infos: TRVUndoInfos;
cancombine: Boolean;
begin
if Limit=0 then exit;
if (Count>0) and (TRVUndoInfos(Items[Count-1]).Count=0) then
Delete(Count-1);
cancombine := False;
if (Count>0) then begin
infos := TRVUndoInfos(Items[Count-1]);
if (infos.Count>0) and (TRVUndoInfo(infos.Items[0]) is TRVUndoTypingInfo) then begin
info := TRVUndoTypingInfo(infos.Items[0]);
if (info.ItemNo = CaretItemNo) and (info.Index+info.Length = CaretOffs) then begin
inc(info.Length);
inc(infos.CaretOffs);
cancombine := True;
end;
end;
end;
if not cancombine then begin
BeginItem(rvutTyping,'',CaretItemNo,CaretOffs);
info := TRVUndoTypingInfo.Create;
info.Action := rvuTyping;
info.ItemNo := CaretItemNo;
info.Index := CaretOffs;
info.Length := 1;
info.Unicode := Unicode;
AddInfo(info);
end;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.AddUntyping(const c: String; CaretItemNo, CaretOffs: Integer);
var info: TRVRedoTypingInfo;
infos: TRVUndoInfos;
unicode, cancombine: Boolean;
Len: Integer;
begin
Unicode := Length(c)>1;
if (Count>0) and (TRVUndoInfos(Items[Count-1]).Count=0) then
Delete(Count-1);
cancombine := False;
if (Count>0) then begin
infos := TRVUndoInfos(Items[Count-1]);
if (infos.Count>0) and (TRVUndoInfo(infos.Items[0]) is TRVRedoTypingInfo) then begin
info := TRVRedoTypingInfo(infos.Items[0]);
Len := Length(info.s);
{$IFNDEF RVDONOTUSEUNICODE}
if Unicode then begin
RVCheckUni(Len);
Len := Len div 2;
end;
{$ENDIF}
if (info.ItemNo = CaretItemNo) and (info.Index-Len = CaretOffs) then begin
info.s := info.s+c;
dec(infos.CaretOffs);
cancombine := True;
end;
end;
end;
if not cancombine then begin
BeginItem(rvutTyping,'',CaretItemNo,CaretOffs);
info := TRVRedoTypingInfo.Create;
info.Action := rvuTyping;
info.ItemNo := CaretItemNo;
info.Index := CaretOffs;
info.s := c;
info.Unicode := Unicode;
AddInfo(info);
end;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.AddInfo(Info: TRVUndoInfo);
var infos: TRVUndoInfos;
begin
if Count=0 then
raise ERichViewError.Create(errRVUndoEmpty);
infos := TRVUndoInfos(Items[Count-1]);
if (infos.Count=1) and (TRVUndoInfo(infos.Items[0]).Action = rvuTyping) then
raise ERichViewError.Create(errRVUndoAdd);
Info.FUndoList := Self;
infos.Add(Info);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.AddInfos(Infos: TRVUndoInfos);
begin
Add(Infos);
Infos.ChangeUndoList(Self);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.PopIfEmpty;
var infos: TRVUndoInfos;
begin
if (Count=0) or (GroupModeCount>0) then exit;
infos := TRVUndoInfos(Items[Count-1]);
if infos.Count=0 then
Delete(Count-1);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.Pop;
var infos: TRVUndoInfos;
begin
infos := TRVUndoInfos(Items[Count-1]);
if infos.CanDelete then
Delete(Count-1)
else
if TRVUndoInfo(infos.Items[0]) is TRVUndoTypingInfo then
dec(infos.CaretOffs)
else //TRVRedoTypingInfo
inc(infos.CaretOffs)
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.Undo(RVData: TRichViewRVData);
begin
if Count=0 then
raise ERichViewError.Create(errRVUndoEmptyBuffer);
TRVUndoInfos(Items[Count-1]).Undo(RVData, FReformatLock<=0);
Pop;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.Redo(RVData: TRichViewRVData);
begin
if Count=0 then
raise ERichViewError.Create(errRVUndoEmptyBuffer);
TRVUndoInfos(Items[Count-1]).Redo(RVData, FReformatLock<=0);
Pop;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.LockRFR;
begin
inc(FReformatLock);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoList.UnlockRFR;
begin
dec(FReformatLock);
end;
{------------------------------------------------------------------------------}
{
procedure TRVUndoList.ChangeRVData(ARVData: TRichViewRVData;
Restoring: Boolean);
var i: Integer;
begin
for i := 0 to Count-1 do
TRVUndoInfos(Items[i]).ChangeRVData(ARVData, Restoring);
end;
//!!
}
{=============================== TRVUndoInfos =================================}
function TRVUndoInfos.CanDelete: Boolean;
begin
Result := True;
if Count=0 then exit;
if TRVUndoInfo(Items[0]) is TRVUndoTypingInfo then
Result := TRVUndoTypingInfo(Items[0]).Length=0
else if TRVUndoInfo(Items[0]) is TRVRedoTypingInfo then
Result := Length(TRVRedoTypingInfo(Items[0]).s)=0
else if TRVUndoInfo(Items[0]) is TRVCompositeUndo then
Result := TRVCompositeUndo(Items[0]).UndoList.Count=0;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfos.ChangeUndoList(UndoList: TRVUndoList);
var i: Integer;
begin
for i := 0 to Count-1 do
TRVUndoInfo(Items[i]).FUndoList := UndoList;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfos.PerformUndo(RVData: TRichViewRVData; Reformat: Boolean);
var i, ItemsAdded,ItemsAdded1, StartItem, EndItem,
StartItem1, EndItem1, TerminatorCount,TerminatorW: Integer;
RF, RFR, SRF: Boolean;
ui: TRVUndoInfo;
begin
if Count=0 then exit;
RVData.Deselect(nil, True);
StartItem := RVData.Items.Count-1;
EndItem := 0;
ItemsAdded := 0;
RFR := False;
RF := False;
SRF := False;
for i := Count-1 downto 0 do begin
ui := TRVUndoInfo(Items[i]);
RF := RF or ui.RequiresFormat;
SRF := SRF or ui.RequiresSuperFormat;
ui.SetItemsRange(StartItem1, EndItem1, RVData);
{
if ItemsAdded<0 then
inc(StartItem1,ItemsAdded);
}
if ItemsAdded>0 then
inc(EndItem1,ItemsAdded);
ItemsAdded1 := ui.ItemsAdded;
if ItemsAdded1>0 then
inc(EndItem1, ItemsAdded1);
inc(ItemsAdded,ItemsAdded1);
if StartItem1<StartItem then
StartItem := StartItem1;
if EndItem1>EndItem then
EndItem := EndItem1;
end;
if EndItem<StartItem then begin
StartItem1 := StartItem;
StartItem := EndItem;
EndItem := StartItem1;
end;
if StartItem<0 then
StartItem := 0;
if EndItem<StartItem then
EndItem := StartItem;
if EndItem+ItemsAdded<StartItem then
EndItem := StartItem-ItemsAdded;
if EndItem>=RVData.Items.Count then
EndItem := RVData.Items.Count-1;
RVData.Item2DrawItem(StartItem, 1, StartItem, StartItem1);
RVData.Item2DrawItem(EndItem, 1, EndItem, EndItem1);
if StartItem=-1 then
StartItem := 0;
if EndItem=-1 then
EndItem := RVData.DrawItems.Count-1;
RVData.GetParaBounds(StartItem,EndItem, StartItem, EndItem);
TerminatorCount := 0;
TerminatorW := 0;
for i := Count-1 downto 0 do begin
ui := TRVUndoInfo(Items[i]);
if TerminatorCount=0 then
RFR := RF and (RFR or ui.RequiresFullReformat1(RVData));
if ui is TRVUndoModifyItemTerminator then begin
if not TRVUndoModifyItemTerminator(ui).Opening then begin
if TerminatorCount=0 then
TerminatorW := TRVUndoModifyItemTerminator(ui).OldW;
inc(TerminatorCount);
end
else begin
dec(TerminatorCount);
if TerminatorCount=0 then
TRVUndoModifyItemTerminator(ui).OldW := TerminatorW;
end;
end;
ui.Undo(RVData);
if TerminatorCount=0 then
RFR := RF and (RFR or ui.RequiresFullReformat2(RVData));
end;
if Reformat and RF then
if RFR and (RVData.DocumentWidth<>RVData.CalculateMinDocWidthPlus(nil,nil)) then
RVData.Format(False)
else
RVData.FormatParas(StartItem, EndItem, ItemsAdded);
if TCustomRichView(RVData.RichView).InplaceEditor=nil then
RVData.SetSelectionBounds(CaretItemNo,CaretOffs,CaretItemNo,CaretOffs);
RVData.Invalidate;
if SRF then
(RVData.GetAbsoluteRootData as TRichViewRVData).Format_(True, True, True, 0, nil, False, True);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfos.Redo(RVData: TRichViewRVData; Reformat: Boolean);
begin
TRVEditRVData(RVData).BeginNamedUndoSequence(UndoType, Caption, True);
PerformUndo(RVData, Reformat);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfos.Undo(RVData: TRichViewRVData; Reformat: Boolean);
begin
TRVEditRVData(RVData).BeginRedoSequence(UndoType, Caption);
PerformUndo(RVData, Reformat);
end;
{=============================== TRVUndoInfo ==================================}
constructor TRVUndoInfo.Create;
begin
inherited Create;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfo.Undo(RVData: TRichViewRVData);
begin
end;
{------------------------------------------------------------------------------}
procedure TRVUndoInfo.SetItemsRange(var StartItem, EndItem: Integer; RVData: TRichViewRVData);
begin
// empty
end;
{------------------------------------------------------------------------------}
{
procedure TRVUndoInfo.ChangeRVData(ARVData: TRichViewRVData; Restoring: Boolean);
begin
// empty
end;
//!!
}
{------------------------------------------------------------------------------}
function TRVUndoInfo.RequiresFullReformat1(RVData: TRichViewRVData): Boolean;
begin
Result := False;
end;
{------------------------------------------------------------------------------}
function TRVUndoInfo.RequiresFormat: Boolean;
begin
Result := True;
end;
{------------------------------------------------------------------------------}
function TRVUndoInfo.RequiresSuperFormat: Boolean;
begin
Result := False;
end;
{------------------------------------------------------------------------------}
function TRVUndoInfo.RequiresFullReformat2(RVData: TRichViewRVData): Boolean;
begin
Result := False;
end;
{------------------------------------------------------------------------------}
function TRVUndoInfo.ItemsAdded: Integer;
begin
Result := 0;
end;
{------------------------------------------------------------------------------}
function TRVUndoInfo.GetUndoListOwnerRVData: TCustomRVFormattedData;
begin
Result := FUndoList.FRVData;
end;
{================================ TRVUndoItemNoInfo ===========================}
constructor TRVUndoItemNoInfo.Create;
begin
inherited Create;
LastAffectedItemNo := -1;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoItemNoInfo.SetItemsRange(var StartItem, EndItem: Integer; RVData: TRichViewRVData);
begin
if ItemNo>=0 then begin
StartItem := ItemNo;
if LastAffectedItemNo>=0 then
EndItem := LastAffectedItemNo
else
EndItem := ItemNo;
end;
end;
{========================= TRVUndoStringItemListInfo ==========================}
constructor TRVUndoStringItemListInfo.Create;
begin
inherited Create;
List := TStringList.Create;
end;
{------------------------------------------------------------------------------}
destructor TRVUndoStringItemListInfo.Destroy;
var i: Integer;
begin
for i := 0 to List.Count-1 do
FreeItem(TCustomRVItemInfo(List.Objects[i]), GetUndoListOwnerRVData);
List.Free;
inherited Destroy;
end;
{========================== TRVUndoItemRangeInfo ==============================}
constructor TRVUndoItemRangeInfo.Create;
begin
inherited Create;
LastAffectedItemNo := -1;
end;
{------------------------------------------------------------------------------}
procedure TRVUndoItemRangeInfo.SetItemsRange(var StartItem,
EndItem: Integer; RVData: TRichViewRVData);
begin
StartItem := StartItemNo;
if LastAffectedItemNo=-1 then
EndItem := StartItemNo+List.Count
else
EndItem := LastAffectedItemNo;
end;
{============================== TRVUndoItemInfo ===============================}
destructor TRVUndoItemInfo.Destroy;
begin
FreeItem(Item, GetUndoListOwnerRVData);
inherited Destroy;
end;
{================================== TRVUndoDeleteItem =========================}
function TRVUndoDeleteItemInfo.ItemsAdded: Integer;
begin
Result := +1;
end;
{------------------------------------------------------------------------------}
function TRVUndoDeleteItemInfo.RequiresFullReformat2(
RVData: TRichViewRVData): Boolean;
begin
Result := FR or
(RVData.CalculateMinItemWidthPlusEx(ItemNo)>
RVData.DocumentWidth);
end;
{------------------------------------------------------------------------------}
procedure TRVUndoDeleteItemInfo.Undo(RVData: TRichViewRVData);
begin
TRVEditRVData(RVData).Do_InsertItem(ItemNo,s,Item, True, FR);
Item := nil;
end;
{================================= TRVUndoDeleteItems =========================}
function TRVUndoDeleteItemsInfo.ItemsAdded: Integer;
begin
Result := +List.Count;
end;
{------------------------------------------------------------------------------}
function TRVUndoDeleteItemsInfo.RequiresFullReformat2(
RVData: TRichViewRVData): Boolean;
begin
Result := FR or
(RVData.CalculateMinItemsWidthPlusEx(StartItemNo, EndItemNo)>RVData.DocumentWidth);
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -