Files
HeidiSQL/components/synedit/Source/SynEditDocumentManager.pas

493 lines
13 KiB
ObjectPascal

unit SynEditDocumentManager;
interface
uses
Classes,
Messages,
ExtCtrls,
SynEditTypes,
SynEdit,
SynMemo,
SynEditTextBuffer,
SynEditHighlighter;
type
ISynDocument = interface
['{DC80C7CF-FC56-4FDE-9E3E-6A1C53D6EFCD}']
procedure SetCaretXY(const value: TBufferCoord);
function GetCaretXY: TBufferCoord;
procedure SetLines(const value: TStrings);
function GetLines: TStrings;
function GetUndoList: TSynEditUndoList;
function GetRedoList: TSynEditUndoList;
function GetTopLine: Integer;
procedure SetTopLine(const value: Integer);
procedure SetModified(const value: Boolean);
function GetModified: Boolean;
function GetName: string;
function GetHighLighter: TSynCustomHighlighter;
procedure SetHighlighter(const value: TSynCustomHighlighter);
function GetDataIntf: IInterface;
procedure SetDataIntf(const value: IInterface);
function GetMarks: TSynEditMarkList;
property CaretXY: TBufferCoord read GetCaretXY write SetCaretXY;
property Lines: TStrings read GetLines write SetLines;
property UndoList: TSynEditUndoList read GetUndoList;
property RedoList: TSynEditUndoList read GetRedoList;
property TopLine: Integer read GetTopLine write SetTopLine;
property Modified: Boolean read GetModified write SetModified;
property Name: string read GetName;
property Highlighter: TSynCustomHighlighter read GetHighlighter write SetHighLighter;
property DataIntf: IInterface read GetDataIntf write SetDataIntf;
property Marks: TSynEditMarkList read GetMarks;
//Line info allows us to store stuff like gutter icons, breakpoints etc.
end;
TSynEditDocumentManager = class(TComponent)
private
FDocuments: IInterfaceList;
FCurrentDocumentIndex: Integer;
FMemo: TSynMemo;
FMemoWndProc: TWndMethod;
FUpdateTimer: TTimer;
function GetCount: Integer;
function GetCurrentDocument: ISynDocument;
protected
procedure MemoWndProc(var Msg: TMessage);
procedure SetMemo(const Value: TSynMemo);
function GetDocument(index: Integer): ISynDocument;
function GetDocumentByName(index: string): ISynDocument;
procedure SetCurrentDocumentIndex(const Value: Integer);
procedure UpdateTimerEvent(Sender: TObject);
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure UpdateCurrentDocument; //saves editor to document
procedure ApplyCurrentDocument; //applies document to editor
function AddDocument(const AName: string; const ALines: TStrings; const AHighlighter: TSynCustomHighlighter): ISynDocument;
procedure RemoveDocument(const index: Integer); overload;
procedure RemoveDocument(const AName: string); overload;
procedure RemoveDocument(const ADocument: ISynDocument); overload;
procedure RemoveAll;
property Documents[index: Integer]: ISynDocument read GetDocument;
property CurrentDocument: ISynDocument read GetCurrentDocument;
property DocumentsByName[index: string]: ISynDocument read GetDocumentByName;
property CurrentDocumentIndex: Integer read FCurrentDocumentIndex write SetCurrentDocumentIndex;
property Count: Integer read GetCount;
published
property Memo: TSynMemo read FMemo write SetMemo;
end;
implementation
uses
Windows, SysUtils;
{ TSynEditDocumentManager }
type
TSynDocument = class(TInterfacedObject, ISynDocument)
private
FName: string;
FLines: TStringList;
FCaretXY: TBufferCoord;
FModified: Boolean;
FRedoList: TSynEditUndoList;
FUndoList: TSynEditUndoList;
FTopLine: Integer;
FHighLighter: TSynCustomHighlighter;
FDataIntf: IInterface;
FMarks: TSynEditMarkList;
protected
function GetCaretXY: TBufferCoord;
function GetLines: TStrings;
function GetModified: Boolean;
function GetName: string;
function GetRedoList: TSynEditUndoList;
function GetTopLine: Integer;
function GetUndoList: TSynEditUndoList;
procedure SetCaretXY(const value: TBufferCoord);
procedure SetLines(const value: TStrings);
procedure SetModified(const value: Boolean);
procedure SetTopLine(const value: Integer);
function GetHighLighter: TSynCustomHighlighter;
procedure SetHighlighter(const value: TSynCustomHighlighter);
function GetDataIntf: IInterface;
procedure SetDataIntf(const value: IInterface);
function GetMarks: TSynEditMarkList;
public
constructor Create(const AName: string; ALines: TStrings);
destructor Destroy; override;
end;
constructor TSynEditDocumentManager.Create(AOwner: TComponent);
begin
inherited;
FDocuments := TInterfaceList.Create;
FCurrentDocumentIndex := -1;
FUpdateTimer := TTimer.Create(Self);
FUpdateTimer.enabled := False;
FUpdateTimer.Interval := 200;
FUpdateTimer.OnTimer := UpdateTimerEvent;
end;
destructor TSynEditDocumentManager.Destroy;
begin
FUpdateTimer.Free;
inherited;
end;
function TSynEditDocumentManager.AddDocument(const AName: string;
const ALines: TStrings; const AHighlighter: TSynCustomHighlighter): ISynDocument;
begin
Result := GetDocumentByName(AName);
if Result <> nil then
begin
Result.Lines.Assign(ALines);
Result.Highlighter := AHighlighter;
end
else
begin
Result := TSynDocument.Create(AName,ALines);
Result.Highlighter := AHighlighter;
FDocuments.Add(Result);
{ if CurrentDocumentIndex = -1 then
CurrentDocumentIndex := 0;}
end;
end;
function TSynEditDocumentManager.GetDocument(index: Integer): ISynDocument;
begin
if (index >= 0) and (index < FDocuments.Count) then
Result := FDocuments.Items[index] as ISynDocument
else
Result := nil;
end;
function TSynEditDocumentManager.GetDocumentByName(index: string): ISynDocument;
var
i: Integer;
begin
Result := nil;
for i := 0 to FDocuments.Count -1 do
begin
Result := GetDocument(i);
if CompareText(Result.Name,index) = 0 then
Break
else
Result := nil;
end;
end;
procedure TSynEditDocumentManager.RemoveDocument(const index: Integer);
begin
FDocuments.Delete(index);
if FDocuments.Count = 0 then
FCurrentDocumentIndex := -1;
end;
procedure TSynEditDocumentManager.RemoveDocument(const AName: string);
var
doc: ISynDocument;
begin
doc := GetDocumentByName(AName);
if doc <> nil then
FDocuments.Remove(doc);
if FDocuments.Count = 0 then
FCurrentDocumentIndex := -1;
end;
procedure TSynEditDocumentManager.MemoWndProc(var Msg: TMessage);
begin
if (Msg.Msg = WM_CHAR) then
begin
FUpdateTimer.Enabled := False;
FUpdateTimer.Enabled := True;
end;
if Assigned(FMemoWndProc) then
FMemoWndProc(Msg);
end;
procedure TSynEditDocumentManager.RemoveDocument(const ADocument: ISynDocument);
begin
FDocuments.Remove(ADocument);
if FDocuments.Count = 0 then
FCurrentDocumentIndex := -1;
end;
procedure TSynEditDocumentManager.SetCurrentDocumentIndex(const Value: Integer);
begin
if FCurrentDocumentIndex <> Value then
begin
UpdateCurrentDocument;
if (Value >= 0) and (Value < FDocuments.Count) then
begin
FCurrentDocumentIndex := Value;
ApplyCurrentDocument;
end;
end;
end;
procedure TSynEditDocumentManager.SetMemo(const Value: TSynMemo);
begin
if FMemo <> Value then
begin
if FMemo <> nil then
begin
FMemo.RemoveFreeNotification(Self);
if not (csDesigning in ComponentState) then
begin
if Assigned(FMemoWndProc) then
FMemo.WindowProc := FMemoWndProc;
end;
end;
FMemo := Value;
if FMemo <> nil then
begin
FMemo.FreeNotification(Self);
if not (csDesigning in ComponentState) then
begin
FMemoWndProc := FMemo.WindowProc;
FMemo.WindowProc := Self.MemoWndProc;
end;
end;
end;
end;
procedure TSynEditDocumentManager.RemoveAll;
begin
FDocuments.Clear;
FCurrentDocumentIndex := -1;
end;
function TSynEditDocumentManager.GetCount: Integer;
begin
Result := FDocuments.Count;
end;
function TSynEditDocumentManager.GetCurrentDocument: ISynDocument;
begin
if FCurrentDocumentIndex <> -1 then
Result := GetDocument(FCurrentDocumentIndex)
else
Result := nil;
end;
function CloneMark(const AOwner: TCustomSynEdit; const source: TSynEditMark): TSynEditMark;
begin
Result := TSynEditMark.Create(AOwner);
Result.Line := source.Line;
Result.Char := source.Char;
Result.ImageIndex := source.ImageIndex;
Result.BookmarkNumber := source.BookmarkNumber;
Result.InternalImage := source.InternalImage;
Result.Visible := source.Visible;
end;
procedure TSynEditDocumentManager.ApplyCurrentDocument;
var
doc: ISynDocument;
I: Integer;
begin
if FCurrentDocumentIndex <> -1 then
begin
if FMemo <> nil then
begin
doc := GetDocument(FCurrentDocumentIndex);
if doc <> nil then
begin
FMemo.Lines.Assign(doc.Lines);
FMemo.TopLine := doc.TopLine;
FMemo.CaretXY := doc.CaretXY;
FMemo.UndoList.Assign(doc.UndoList);
FMemo.RedoList.Assign(doc.RedoList);
FMemo.Highlighter := doc.Highlighter;
//can't do this because it av's now???
// FMemo.Marks.Assign(doc.Marks);
FMemo.Marks.Clear;
for i := 0 to doc.Marks.Count - 1 do
begin
FMemo.Marks.Place(CloneMark(FMemo,doc.Marks.Items[i]));
end;
FMemo.Modified := doc.Modified;
FMemo.Refresh;
end;
end;
end;
end;
{ TSynDocument }
constructor TSynDocument.Create(const AName: string; ALines: TStrings);
begin
inherited Create;
FLines := TStringList.Create;
FRedoList := TSynEditUndoList.Create;
FUndoList := TSynEditUndoList.Create;
FName := AName;
FLines.Assign(ALines);
FModified := False;
FTopLine := 0;
FMarks := TSynEditMarkList.Create(nil);
end;
destructor TSynDocument.Destroy;
begin
FLines.Free;
FRedoList.Free;
FUndoList.Free;
FMarks.Free;
inherited;
end;
function TSynDocument.GetCaretXY: TBufferCoord;
begin
Result := FCaretXY;
end;
function TSynDocument.GetDataIntf: IInterface;
begin
Result := FDataIntf;
end;
function TSynDocument.GetHighLighter: TSynCustomHighlighter;
begin
Result := FHighLighter;
end;
function TSynDocument.GetLines: TStrings;
begin
Result := FLines;
end;
function TSynDocument.GetMarks: TSynEditMarkList;
begin
Result := FMarks;
end;
function TSynDocument.GetModified: Boolean;
begin
Result := FModified;
end;
function TSynDocument.GetName: string;
begin
Result := FName;
end;
function TSynDocument.GetRedoList: TSynEditUndoList;
begin
Result := FRedoList;
end;
function TSynDocument.GetTopLine: Integer;
begin
Result := FTopLine;
end;
function TSynDocument.GetUndoList: TSynEditUndoList;
begin
Result := FUndoList;
end;
procedure TSynDocument.SetCaretXY(const value: TBufferCoord);
begin
FCaretXY := value;
end;
procedure TSynDocument.SetDataIntf(const value: IInterface);
begin
FDataIntf := Value;
end;
procedure TSynDocument.SetHighlighter(const value: TSynCustomHighlighter);
begin
FHighLighter := value;
end;
procedure TSynDocument.SetLines(const value: TStrings);
begin
FLines.Assign(value);
end;
procedure TSynDocument.SetModified(const value: Boolean);
begin
FModified := Value;
end;
procedure TSynDocument.SetTopLine(const value: Integer);
begin
FTopLine := Value;
end;
procedure TSynEditDocumentManager.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if (AComponent = FMemo) and (Operation = opRemove) then
begin
SetMemo(nil);
end;
end;
procedure TSynEditDocumentManager.UpdateTimerEvent(Sender: TObject);
var
doc: ISynDocument;
begin
FUpdateTimer.Enabled := False;
if FCurrentDocumentIndex <> -1 then
begin
if FMemo <> nil then
begin
doc := GetDocument(FCurrentDocumentIndex);
if doc <> nil then
begin
doc.Modified := FMemo.Modified;
doc.Lines.Assign(FMemo.Lines);
doc.TopLine := FMemo.TopLine;
doc.CaretXY := FMemo.CaretXY;
doc.UndoList.Assign(FMemo.UndoList);
doc.RedoList.Assign(FMemo.RedoList);
end;
end;
end;
end;
procedure TSynEditDocumentManager.UpdateCurrentDocument;
var
doc: ISynDocument;
i: Integer;
begin
if FCurrentDocumentIndex <> -1 then
begin
//save the state of the current document
if FMemo <> nil then
begin
doc := GetDocument(FCurrentDocumentIndex);
if doc <> nil then
begin
doc.Modified := FMemo.Modified;
doc.Lines.Assign(FMemo.Lines);
doc.TopLine := FMemo.TopLine;
doc.CaretXY := FMemo.CaretXY;
doc.UndoList.Assign(FMemo.UndoList);
doc.RedoList.Assign(FMemo.RedoList);
doc.Marks.Clear;
for i := 0 to FMemo.Marks.Count - 1 do
doc.Marks.Place(CloneMark(nil,FMemo.Marks.Items[i]));
FMemo.Highlighter := doc.Highlighter;
end;
end;
end;
end;
end.