From 261424827b8b35650bf0e9f85498791f45a101ba Mon Sep 17 00:00:00 2001 From: martin Date: Thu, 15 Apr 2010 18:42:04 +0000 Subject: [PATCH] SynEdit, Refactor: Moved Modified/ChangStamp completely to TextBuffer (shred editors share this state) git-svn-id: trunk@24633 - --- components/synedit/synedit.pp | 78 ++++------- components/synedit/syneditlines.pas | 10 +- components/synedit/synedittextbase.pas | 28 ++-- components/synedit/synedittextbuffer.pp | 167 ++++++++++++------------ 4 files changed, 126 insertions(+), 157 deletions(-) diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index 3c517c195d..1b7bb60ac9 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -413,7 +413,6 @@ type FMouseActions, FMouseSelActions: TSynEditMouseActions; FMouseActionSearchHandlerList: TSynEditMouseActionSearchList; FMouseActionExecHandlerList: TSynEditMouseActionExecList; - fModified: Boolean; fMarkList: TSynEditMarkList; fExtraLineSpacing: integer; FUseUTF8: boolean; @@ -447,16 +446,15 @@ type fOnReplaceText: TReplaceTextEvent; fOnSpecialLineColors: TSpecialLineColorsEvent;// needed, because bug fpc 11926 fOnStatusChange: TStatusChangeEvent; - {$IFDEF SYN_LAZARUS} FOnSpecialLineMarkup: TSpecialLineMarkupEvent;// needed, because bug fpc 11926 FOnClickLink: TMouseEvent; FOnMouseLink: TSynMouseLinkEvent; - fChangeStamp: int64; - {$ENDIF} procedure AquirePrimarySelection; + function GetChangeStamp: int64; function GetDefSelectionMode: TSynSelectionMode; function GetFoldState: String; + function GetModified: Boolean; function GetPaintLockOwner: TSynEditBase; function GetPlugin(Index: Integer): TSynEditPlugin; function GetTextBetweenPoints(aStartPoint, aEndPoint: TPoint): String; @@ -571,8 +569,8 @@ type procedure SetParagraphBlock(Value: TPoint); procedure SizeOrFontChanged(bFont: boolean); procedure StatusChanged(AChanges: TSynStatusChanges); - procedure UpdateModified; procedure UndoRedoAdded(Sender: TObject); + procedure ModifiedChanged(Sender: TObject); procedure UnlockUndo; procedure UpdateCaret(IgnorePaintLock: Boolean = False); procedure UpdateScrollBars; @@ -600,7 +598,6 @@ type procedure Resize; override; function RealGetText: TCaption; override; procedure RealSetText(const Value: TCaption); override; - procedure IncreaseChangeStamp; function GetLines: TStrings; override; function GetViewedTextBuffer: TSynEditStrings; override; function GetTextBuffer: TSynEditStrings; override; @@ -870,7 +867,7 @@ type property Marks: TSynEditMarkList read fMarkList; property MaxLeftChar: integer read fMaxLeftChar write SetMaxLeftChar default 1024; - property Modified: Boolean read fModified write SetModified; + property Modified: Boolean read GetModified write SetModified; property PaintLock: Integer read fPaintLock; property ReadOnly: Boolean read GetReadOnly write SetReadOnly default FALSE; property SelAvail: Boolean read GetSelAvail; @@ -885,7 +882,7 @@ type property UseUTF8: boolean read FUseUTF8; procedure Update; override; procedure Invalidate; override; - property ChangeStamp: int64 read fChangeStamp; + property ChangeStamp: int64 read GetChangeStamp; {$ENDIF} procedure ShareTextBufferFrom(AShareEditor: TCustomSynEdit); procedure UnShareTextBuffer; @@ -1318,6 +1315,11 @@ begin end; end; +function TCustomSynEdit.GetChangeStamp: int64; +begin + Result := TSynEditStringList(FLines).TextChangeStamp; +end; + function TCustomSynEdit.GetDefSelectionMode: TSynSelectionMode; begin Result := FBlockSelection.SelectionMode; @@ -1328,6 +1330,11 @@ begin Result := FFoldedLinesView.GetFoldDescription(0, 0, -1, -1, True); end; +function TCustomSynEdit.GetModified: Boolean; +begin + Result := TSynEditStringList(FLines).Modified; +end; + function TCustomSynEdit.GetPaintLockOwner: TSynEditBase; begin Result := TSynEditStringList(FLines).PaintLockOwner; @@ -1536,7 +1543,7 @@ begin FTheLinesView := FTabbedLinesView; FTopLinesView := FTrimmedLinesView; // External Accessor - FStrings := TSynEditLines.Create(FLines, {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved); + FStrings := TSynEditLines.Create(TSynEditStringList(FLines), {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved); FCaret.Lines := FTheLinesView; FInternalCaret.Lines := FTheLinesView; @@ -1549,7 +1556,8 @@ begin AddNotifyHandler(senrBeginUpdate, {$IFDEF FPC}@{$ENDIF}LinesChanging); AddNotifyHandler(senrEndUpdate, {$IFDEF FPC}@{$ENDIF}LinesChanged); AddNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}ListCleared); - AddNotifyHandler(senrUndoRedoAdded, {$IFDEF FPC}@{$ENDIF}UndoRedoAdded); + AddNotifyHandler(senrUndoRedoAdded, {$IFDEF FPC}@{$ENDIF}Self.UndoRedoAdded); + AddNotifyHandler(senrModifiedChanged, {$IFDEF FPC}@{$ENDIF}ModifiedChanged); end; FUndoList := TSynEditStringList(fLines).UndoList; @@ -4108,14 +4116,6 @@ begin FLines.Text := Value; // Do not trim end; -procedure TCustomSynEdit.IncreaseChangeStamp; -begin - if fChangeStamp=High(fChangeStamp) then - fChangeStamp:=Low(fChangeStamp) - else - inc(fChangeStamp); -end; - function TCustomSynEdit.CurrentMaxTopLine: Integer; begin if (eoScrollPastEof in Options) then @@ -4593,7 +4593,6 @@ procedure TCustomSynEdit.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer); begin {$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- LineCountChanged Aindex', AIndex, ' ACount=', ACount]);{$ENDIF} - IncreaseChangeStamp; if (AIndex < FBeautifyStartLineIdx) or (FBeautifyStartLineIdx < 0) then FBeautifyStartLineIdx := AIndex; if ACount > 0 then begin @@ -4628,7 +4627,6 @@ procedure TCustomSynEdit.LineTextChanged(Sender: TSynEditStrings; AIndex, ACount: Integer); begin {$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- LineTextChanged Aindex', AIndex, ' ACount=', ACount]);{$ENDIF} - IncreaseChangeStamp; if (AIndex < FBeautifyStartLineIdx) or (FBeautifyStartLineIdx < 0) then FBeautifyStartLineIdx := AIndex; if (AIndex + ACount - 1 > FBeautifyEndLineIdx) then @@ -5062,7 +5060,7 @@ begin // Recreate te public access to FLines FreeAndNil(FStrings); - FStrings := TSynEditLines.Create(FLines, {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved); + FStrings := TSynEditLines.Create(TSynEditStringList(FLines), {$IFDEF FPC}@{$ENDIF}MarkTextAsSaved); // Attach Highlighter if FHighlighter <> nil then @@ -7630,21 +7628,7 @@ end; procedure TCustomSynEdit.SetModified(Value: boolean); begin - if Value then - IncreaseChangeStamp; - if Value <> fModified then - begin - fModified := Value; - {$IFDEF SYN_LAZARUS} - if not fModified then - begin - // the current state should be the unmodified state. - fUndoList.MarkTopAsUnmodified; - fRedoList.MarkTopAsUnmodified; - end; - {$ENDIF} - StatusChanged([scModified]); - end; + TSynEditStringList(FLines).Modified := Value; end; {$IFNDEF SYN_LAZARUS} @@ -8398,28 +8382,18 @@ begin end; end; -procedure TCustomSynEdit.UpdateModified; -begin - if fUndoList.UnModifiedMarkerExists then - Modified:=not fUndoList.IsTopMarkedAsUnmodified - else if fRedoList.UnModifiedMarkerExists then - Modified:=not fRedoList.IsTopMarkedAsUnmodified - else - Modified := fUndoList.CanUndo or fUndoList.FullUndoImpossible; //mh 2000-10-03 -end; - procedure TCustomSynEdit.UndoRedoAdded(Sender: TObject); begin - IncreaseChangeStamp; - UpdateModified; - // we have to clear the redo information, since adding undo info removes - // the necessary context to undo earlier edit actions - if (Sender = fUndoList) and not (fUndoList.IsInsideRedo) then //mh 2000-10-30 - fRedoList.Clear; + // Todo: Check Paintlock, otherwise move to LinesChanged, LineCountChanged if Assigned(fOnChange) then fOnChange(Self); end; +procedure TCustomSynEdit.ModifiedChanged(Sender: TObject); +begin + StatusChanged([scModified]); +end; + function TCustomSynEdit.LogicalToPhysicalPos(const p: TPoint): TPoint; begin Result := FTheLinesView.LogicalToPhysicalPos(p); diff --git a/components/synedit/syneditlines.pas b/components/synedit/syneditlines.pas index f225acdbea..feb7a106f1 100644 --- a/components/synedit/syneditlines.pas +++ b/components/synedit/syneditlines.pas @@ -34,7 +34,7 @@ unit SynEditLines; interface uses - Classes, SysUtils, FileUtil, FPCAdds, SynEditTextBase; + Classes, SysUtils, FileUtil, FPCAdds, SynEditTextBuffer; type @@ -45,7 +45,7 @@ type TSynEditLines = class(TStrings) private fDosFileFormat: boolean; - FTextBuffer: TSynEditStrings; + FTextBuffer: TSynEditStringList; FOnSaved: TSavedNotification; function GetTextChangeStamp: int64; protected @@ -60,7 +60,7 @@ type {$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF} procedure SetUpdateState(Updating: Boolean); override; public - constructor Create(ATextBuffer: TSynEditStrings; OnSaved: TSavedNotification); + constructor Create(ATextBuffer: TSynEditStringList; OnSaved: TSavedNotification); function Add(const S: string): integer; override; procedure AddStrings(AStrings: TStrings); override; procedure Clear; override; @@ -70,7 +70,7 @@ type procedure LoadFromFile(const FileName: string); override; procedure SaveToFile(const FileName: string); override; property DosFileFormat: boolean read fDosFileFormat write fDosFileFormat; - property TextChangeStamp: int64 read GetTextChangeStamp; + property TextChangeStamp: int64 read GetTextChangeStamp; deprecated '#############'; end; implementation @@ -273,7 +273,7 @@ end; { TSynEditLines } -constructor TSynEditLines.Create(ATextBuffer: TSynEditStrings; OnSaved: TSavedNotification); +constructor TSynEditLines.Create(ATextBuffer: TSynEditStringList; OnSaved: TSavedNotification); begin inherited Create; FTextBuffer := ATextBuffer; diff --git a/components/synedit/synedittextbase.pas b/components/synedit/synedittextbase.pas index 6ddd9f929c..759a3e97b0 100644 --- a/components/synedit/synedittextbase.pas +++ b/components/synedit/synedittextbase.pas @@ -38,13 +38,16 @@ type Text: String) of object; TSynEditNotifyReason = ( // TStringListLineCountEvent - senrLineCount, senrLineChange, senrEditAction, - senrHighlightChanged, // used by Highlighter + senrLineCount, // Lines Inserted or Deleted (if not empty, they will trigger senrLineChange too) + senrLineChange, // Lines modified (also triggered by senrEditAction) + senrHighlightChanged, // used by Highlighter (invalidate and fold checks needed) // TStringListLineEditEvent - senrTextEdit, + senrEditAction, // EditInsert, EditDelete, EditLineBreak, ... // TNotifyEvent - senrBeginUpdate, senrEndUpdate, senrCleared, - senrUndoRedoAdded + senrBeginUpdate, senrEndUpdate, + senrCleared, + senrUndoRedoAdded, + senrModifiedChanged // The modified flag was changed ); TPhysicalCharWidths = Array of Shortint; @@ -84,7 +87,6 @@ type TSynEditStrings = class(TStrings) protected - FTextChangeStamp: int64; FIsUtf8: Boolean; function GetIsUtf8 : Boolean; virtual; procedure SetIsUtf8(const AValue : Boolean); virtual; @@ -161,14 +163,12 @@ type property CurUndoList: TSynEditUndoList read GetCurUndoList; // Re or Undo (Redo while undoing) property IsUndoing: Boolean read GetIsUndoing write SetIsUndoing; property IsRedoing: Boolean read GetIsRedoing write SetIsRedoing; - procedure IncreaseTextChangeStamp; procedure SendHighlightChanged(aIndex, aCount: Integer); public property ExpandedStrings[Index: integer]: string read GetExpandedString; property LengthOfLongestLine: integer read GetLengthOfLongestLine; property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8; property Ranges[Index: TClass]: TSynEditStorageMem read GetRange write PutRange; - property TextChangeStamp: int64 read FTextChangeStamp; end; { TSynEditStringsLinked } @@ -401,12 +401,12 @@ end; procedure TSynEditStrings.AddEditHandler(AHandler: TStringListLineEditEvent); begin - AddGenericHandler(senrTextEdit, TMethod(AHandler)); + AddGenericHandler(senrEditAction, TMethod(AHandler)); end; procedure TSynEditStrings.RemoveEditHandler(AHandler: TStringListLineEditEvent); begin - RemoveGenericHandler(senrTextEdit, TMethod(AHandler)); + RemoveGenericHandler(senrEditAction, TMethod(AHandler)); end; function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths; @@ -527,14 +527,6 @@ begin Result := BytePos + 1 + PhysicalPos - ScreenPos; end; -procedure TSynEditStrings.IncreaseTextChangeStamp; -begin - if fTextChangeStamp=High(fTextChangeStamp) then - fTextChangeStamp:=Low(fTextChangeStamp) - else - inc(fTextChangeStamp); -end; - procedure TSynEditStrings.SendHighlightChanged(aIndex, aCount: Integer); begin SendNotification(senrHighlightChanged, Self, aIndex, aCount); diff --git a/components/synedit/synedittextbuffer.pp b/components/synedit/synedittextbuffer.pp index f69085ea8d..7d24a751eb 100644 --- a/components/synedit/synedittextbuffer.pp +++ b/components/synedit/synedittextbuffer.pp @@ -42,9 +42,8 @@ unit SynEditTextBuffer; interface uses - Classes, SysUtils, SynEditTextBase, - FileUtil, LCLProc, LCLIntf, LCLType, - SynEditTypes, SynEditMiscProcs, SynEditMiscClasses; + Classes, SysUtils, LCLProc, LCLIntf, LCLType, + SynEditTextBase, SynEditTypes, SynEditMiscProcs, SynEditMiscClasses; const NullRange = TSynEditRange(nil); @@ -139,14 +138,7 @@ type FAttributeList: Array of TSynEditStringAttribute; FAttachedSynEditList: TFPList; - FLineRangeNotificationList: TLineRangeNotificationList; // LineCount - FLineChangeNotificationList: TLineRangeNotificationList; // ContentChange (not called on add...) - FLineInvalidateNotificationList: TLineRangeNotificationList; // senrHighlightChanged - FLineEditNotificationList: TLineEditNotificationList; - FUndoRedoAddedNotificationList: TSynMethodList; - FOnChangeList: TSynMethodList; - FOnChangingList: TSynMethodList; - FOnClearedList: TSynMethodList; + FNotifyLists: Array [TSynEditNotifyReason] of TSynMethodList; FIgnoreSendNotification: array [TSynEditNotifyReason] of Integer; fDosFileFormat: boolean; @@ -155,6 +147,9 @@ type FUndoList: TSynEditUndoList; FIsUndoing, FIsRedoing: Boolean; + FModified: Boolean; + FTextChangeStamp: int64; + function GetAttachedSynEdits(Index: Integer): TSynEditBase; function GetFlags(Index: Integer): TSynEditStringFlags; procedure Grow; @@ -162,6 +157,7 @@ type function ClassIndexForAttribute(AttrIndex: TClass): Integer; Procedure SetAttributeSize(NewSize: Integer); procedure SetFlags(Index: Integer; const AValue: TSynEditStringFlags); + procedure SetModified(const AValue: Boolean); protected function GetExpandedString(Index: integer): string; override; function GetLengthOfLongestLine: integer; override; @@ -197,6 +193,7 @@ type procedure SetUpdateState(Updating: Boolean); override; procedure UndoEditLinesDelete(LogY, ACount: Integer); + procedure IncreaseTextChangeStamp; public constructor Create; destructor Destroy; override; @@ -228,6 +225,8 @@ type property LengthOfLongestLine: integer read GetLengthOfLongestLine; property Flags[Index: Integer]: TSynEditStringFlags read GetFlags write SetFlags; + property Modified: Boolean read FModified write SetModified; + property TextChangeStamp: int64 read FTextChangeStamp; public property UndoList: TSynEditUndoList read GetUndoList write fUndoList; property RedoList: TSynEditUndoList read GetRedoList write fRedoList; @@ -434,15 +433,17 @@ begin fRedoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded; FIsUndoing := False; FIsRedoing := False; + FModified := False; - FLineRangeNotificationList := TLineRangeNotificationList.Create; - FLineChangeNotificationList := TLineRangeNotificationList.Create; - FLineInvalidateNotificationList := TLineRangeNotificationList.Create; - FLineEditNotificationList := TLineEditNotificationList.Create; - FUndoRedoAddedNotificationList := TLineEditNotificationList.Create; - FOnChangeList := TSynMethodList.Create; - FOnChangingList := TSynMethodList.Create; - FOnClearedList := TSynMethodList.Create; + FNotifyLists[senrLineCount] := TLineRangeNotificationList.Create; + FNotifyLists[senrLineChange] := TLineRangeNotificationList.Create; + FNotifyLists[senrHighlightChanged] := TLineRangeNotificationList.Create; + FNotifyLists[senrEditAction] := TLineEditNotificationList.Create; + FNotifyLists[senrBeginUpdate] := TSynMethodList.Create; + FNotifyLists[senrEndUpdate] := TSynMethodList.Create; + FNotifyLists[senrCleared] := TSynMethodList.Create; + FNotifyLists[senrUndoRedoAdded] := TSynMethodList.Create; + FNotifyLists[senrModifiedChanged] := TSynMethodList.Create; for r := low(TSynEditNotifyReason) to high(TSynEditNotifyReason) do FIgnoreSendNotification[r] := 0; @@ -456,19 +457,15 @@ begin end; destructor TSynEditStringList.Destroy; +var + i: TSynEditNotifyReason; begin fAttributeList := nil; inherited Destroy; SetCount(0); SetCapacity(0); - FreeAndNil(FLineRangeNotificationList); - FreeAndNil(FLineChangeNotificationList); - FreeAndNil(FLineInvalidateNotificationList); - FreeAndNil(FLineEditNotificationList); - FreeAndNil(FUndoRedoAddedNotificationList); - FreeAndNil(FOnChangeList); - FreeAndNil(FOnChangingList); - FreeAndNil(FOnClearedList); + for i := low(TSynEditNotifyReason) to high(TSynEditNotifyReason) do + FreeAndNil(FNotifyLists[i]); FreeAndNil(FUndoList); FreeAndNil(FRedoList); FreeAndNil(FAttachedSynEditList); @@ -481,7 +478,7 @@ begin BeginUpdate; Result := Count; InsertItem(Result, S); - FLineRangeNotificationList.CallRangeNotifyEvents(self, Result, Count - Result); + SendNotification(senrLineCount, self, Result, Count - Result); EndUpdate; end; @@ -506,7 +503,7 @@ begin end; Flags[Count-1] := []; end; - FLineRangeNotificationList.CallRangeNotifyEvents(self, FirstAdded, Count - FirstAdded); + SendNotification(senrLineCount, self, FirstAdded, Count - FirstAdded); finally EndUpdate; end; @@ -523,8 +520,8 @@ begin BeginUpdate; SetCount(0); SetCapacity(0); - FOnClearedList.CallNotifyEvents(Self); - FLineRangeNotificationList.CallRangeNotifyEvents(self, 0, -c); + FNotifyLists[senrCleared].CallNotifyEvents(Self); + SendNotification(senrLineCount, self, 0, -c); EndUpdate; end; fIndexOfLongestLine := -1; @@ -538,7 +535,7 @@ begin BeginUpdate; FList.DeleteRows(Index, 1); fIndexOfLongestLine := -1; - FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, -1); + SendNotification(senrLineCount, self, Index, -1); EndUpdate; end; @@ -550,7 +547,7 @@ begin ListIndexOutOfBounds(Index); BeginUpdate; FList.DeleteRows(Index, NumLines); - FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, -NumLines); + SendNotification(senrLineCount, self, Index, -NumLines); EndUpdate; end; end; @@ -663,7 +660,18 @@ end; procedure TSynEditStringList.UndoRedoAdded(Sender: TObject); begin - FUndoRedoAddedNotificationList.CallNotifyEvents(Sender); + // we have to clear the redo information, since adding undo info removes + // the necessary context to undo earlier edit actions + if (Sender = fUndoList) and not (fUndoList.IsInsideRedo) then + fRedoList.Clear; + if fUndoList.UnModifiedMarkerExists then + Modified := not fUndoList.IsTopMarkedAsUnmodified + else if fRedoList.UnModifiedMarkerExists then + Modified := not fRedoList.IsTopMarkedAsUnmodified + else + Modified := fUndoList.CanUndo or fUndoList.FullUndoImpossible; + + FNotifyLists[senrUndoRedoAdded].CallNotifyEvents(Sender); end; // Maps the Physical Width (ScreenCells) to each character @@ -737,7 +745,7 @@ begin BeginUpdate; OldCnt:=Count; InsertItem(Index, S); - FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, Count - OldCnt); + SendNotification(senrLineCount, self, Index, Count - OldCnt); EndUpdate; end; @@ -769,7 +777,7 @@ begin if Capacity 0 then exit; case AReason of - senrLineChange: - FLineChangeNotificationList.CallRangeNotifyEvents(ASender, aIndex, aCount); - senrLineCount: - FLineRangeNotificationList.CallRangeNotifyEvents(ASender, aIndex, aCount); + senrLineChange, senrLineCount, senrHighlightChanged: + TLineRangeNotificationList(FNotifyLists[AReason]) + .CallRangeNotifyEvents(ASender, aIndex, aCount); senrEditAction: - FLineEditNotificationList.CallRangeNotifyEvents(ASender, aIndex, // aindex is mis-named (linepos) for edit action - aBytePos, aLen, aCount, aTxt); - senrHighlightChanged: - FLineInvalidateNotificationList.CallRangeNotifyEvents(ASender, aIndex, aCount); + // aindex is mis-named (linepos) for edit action + TLineEditNotificationList(FNotifyLists[senrEditAction]) + .CallRangeNotifyEvents(ASender, aIndex, aBytePos, aLen, aCount, aTxt); end; end;