
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4534 8e941d3f-bd1b-0410-a28a-d453659cc2b4
255 lines
6.5 KiB
ObjectPascal
255 lines
6.5 KiB
ObjectPascal
{
|
|
richmemoutils.pas
|
|
|
|
Author: Dmitry 'skalogryz' Boyarintsev
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
unit RichMemoML;
|
|
|
|
{$mode delphi}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, RichMemo, RichMemoUtils;
|
|
|
|
type
|
|
TMarkupFormatHandler = procedure (Sender: TObject;
|
|
var tag: string; tagattr: TStrings;
|
|
var font: TFontParams; var txt: string; var tagCloses: Boolean ) of object;
|
|
|
|
TMarkupEntityReplace = procedure (Sender: TObject; var txt: string; tagsStack: TStrings) of object;
|
|
|
|
{ TFormatStack }
|
|
|
|
TFormatStack = class(Tobject)
|
|
public
|
|
tagName : string;
|
|
fmt : TFontParams;
|
|
constructor Create(const atag: string; afmt: TFontParams);
|
|
end;
|
|
|
|
{ TMarkupHandler }
|
|
|
|
TMarkupHandler = class(TObject)
|
|
private
|
|
fOnMarkup : TMarkupFormatHandler;
|
|
fOnReplace : TMarkupEntityReplace;
|
|
fStack : TList;
|
|
fStackNames : TStrings;
|
|
fRichMemo : TRichMemo;
|
|
procedure Append(const s: string; const fmt: TFontParams);
|
|
procedure EntityReplace(var s: string);
|
|
procedure GetTagFmt(var atag: string; st: TStrings; var fmt: TFontParams; var AText: string; var toBeClosed: Boolean);
|
|
procedure AddStack(const atag: string; const fmt: TFontParams);
|
|
procedure PopStack(const atag: string; var fmt: TFontParams);
|
|
procedure Clear;
|
|
public
|
|
DefParams: TFontParams;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Parse(ARichMemo: TRichMemo; const atext: string);
|
|
property OnFormatSelect: TMarkupFormatHandler read fOnMarkup write fOnMarkup;
|
|
property OnEntityReplace: TMarkupEntityReplace read fOnReplace write fOnReplace;
|
|
end;
|
|
|
|
procedure Parse(const atext: string; ADstMemo: TRichMemo; AFormat: TMarkupFormatHandler; AReplace: TMarkupEntityReplace = nil);
|
|
|
|
implementation
|
|
|
|
procedure Parse(const atext: string; ADstMemo: TRichMemo; AFormat: TMarkupFormatHandler; AReplace: TMarkupEntityReplace);
|
|
var
|
|
h : TMarkupHandler;
|
|
begin
|
|
if not Assigned(ADstMemo) or (atext='') then Exit;
|
|
h := TMarkupHandler.Create;
|
|
try
|
|
h.OnFormatSelect:=AFormat;
|
|
h.OnEntityReplace:=AReplace;
|
|
h.DefParams:=GetFontParams(ADstMemo.Font);
|
|
h.Parse(ADstMemo, atext);
|
|
finally
|
|
h.Free;
|
|
end;
|
|
end;
|
|
|
|
{ TFormatStack }
|
|
|
|
constructor TFormatStack.Create(const atag: string; afmt: TFontParams);
|
|
begin
|
|
inherited Create;
|
|
tagName:=atag;
|
|
fmt:=afmt;
|
|
end;
|
|
|
|
{ TMarkupHandler }
|
|
|
|
procedure TMarkupHandler.Append(const s: string; const fmt: TFontParams);
|
|
begin
|
|
InsertFontText(fRichMemo, s, fmt);
|
|
end;
|
|
|
|
procedure TMarkupHandler.EntityReplace(var s: string);
|
|
var
|
|
i : integer;
|
|
begin
|
|
//todo: more effecient?
|
|
fStackNames.Clear;
|
|
for i:=0 to fStack.Count-1 do
|
|
fStackNames.Add( TFormatStack(fStack[i]).tagName );
|
|
|
|
if Assigned(OnEntityReplace) then OnEntityReplace(Self, s, fStackNames);
|
|
end;
|
|
|
|
procedure TMarkupHandler.GetTagFmt(var atag: string; st: TStrings;
|
|
var fmt: TFontParams; var AText: string; var toBeClosed: Boolean);
|
|
begin
|
|
if Assigned(OnFormatSelect) then
|
|
OnFormatSelect(Self, atag, st, fmt, atext, toBeClosed);
|
|
end;
|
|
|
|
procedure TMarkupHandler.AddStack(const atag: string; const fmt: TFontParams);
|
|
begin
|
|
fStack.Add(TFormatStack.Create(atag, fmt));
|
|
end;
|
|
|
|
procedure TMarkupHandler.PopStack(const atag: string; var fmt: TFontParams);
|
|
var
|
|
i : integer;
|
|
j : integer;
|
|
fs : TFormatStack;
|
|
begin
|
|
i:=fStack.Count-1;
|
|
while i>=0 do begin
|
|
fs:=TFormatStack(fStack[i]);
|
|
if fs.tagName=atag then begin
|
|
for j:=fStack.Count-1 downto i do begin
|
|
TFormatStack(fStack[j]).Free;
|
|
fStack[j]:=nil;
|
|
end;
|
|
fStack.Pack;
|
|
|
|
dec(i);
|
|
if i>=0 then fmt:=TFormatStack(fStack[i]).fmt
|
|
else fmt:=DefParams;
|
|
Exit;
|
|
end else
|
|
dec(i);
|
|
end;
|
|
// do nothing. unknown closing tag
|
|
end;
|
|
|
|
procedure TMarkupHandler.Clear;
|
|
var
|
|
i : Integer;
|
|
begin
|
|
for i:=0 to fStack.Count-1 do
|
|
TFormatStack(fStack[i]).free;
|
|
fStack.Clear;
|
|
end;
|
|
|
|
constructor TMarkupHandler.Create;
|
|
begin
|
|
inherited;
|
|
fStack:=TList.Create;
|
|
fStackNames:=TStringList.Create;
|
|
end;
|
|
|
|
destructor TMarkupHandler.Destroy;
|
|
begin
|
|
Clear;
|
|
fStackNames.Free;
|
|
fStack.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMarkupHandler.Parse(ARichMemo: TRichMemo; const atext: string);
|
|
var
|
|
i : integer;
|
|
j : integer;
|
|
sb : string;
|
|
fmt : TFontParams;
|
|
newfmt : TFontParams;
|
|
tag : string;
|
|
openTag : Boolean;
|
|
tagAttr: TStringList;
|
|
tobeClosed : Boolean;
|
|
begin
|
|
if not Assigned(ARichMemo) then Exit;
|
|
Clear;
|
|
fmt:=DefParams;
|
|
i:=1;
|
|
j:=1;
|
|
fRichMemo:=ARichMemo;
|
|
fRichMemo.Lines.BeginUpdate;
|
|
tagAttr:=TStringList.Create;
|
|
try
|
|
while i<=length(atext) do begin
|
|
if atext[i]='<' then begin
|
|
|
|
tagattr.Clear;
|
|
if j<i then begin
|
|
sb:=Copy(atext, j, i-j);
|
|
EntityReplace(sb);
|
|
Append(sb, fmt);
|
|
end;
|
|
|
|
inc(i);
|
|
j:=i;
|
|
while (i<=length(atext)) and (atext[i]<>'>') do inc(i);
|
|
|
|
if (i>j+1) and (i<=length(atext)) and (atext[j]='/') then begin
|
|
openTag:=false;
|
|
inc(j);
|
|
end else begin
|
|
openTag:=true;
|
|
end;
|
|
tag:=Copy(atext, j, i-j);
|
|
tag:=AnsiLowerCase(tag);
|
|
|
|
if openTag then begin
|
|
tobeClosed:=true;
|
|
sb:='';
|
|
newfmt:=fmt;
|
|
GetTagFmt(tag, tagattr, newfmt, sb, tobeClosed);
|
|
|
|
if sb<>'' then Append(sb, newfmt);
|
|
|
|
if tobeClosed then fmt:=newfmt;
|
|
AddStack(tag, fmt);
|
|
end else begin
|
|
PopStack(tag, fmt);
|
|
end;
|
|
|
|
inc(i);
|
|
j:=i;
|
|
// parsing tag!
|
|
end else
|
|
inc(i);
|
|
end;
|
|
i:=length(atext)+1;
|
|
if j<i then begin
|
|
sb:=Copy(atext, j, i-j);
|
|
Append( sb, fmt );
|
|
end;
|
|
finally
|
|
fRichMemo.Lines.EndUpdate;
|
|
tagAttr.Free;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|