⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rvundo.pas

📁 richview1.7 full.source
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  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 + -