2010-05-20 10:27:49 +00:00
|
|
|
unit RichMemoRTF;
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils, LCLProc, LCLIntf,
|
2010-05-20 12:21:17 +00:00
|
|
|
RichMemo, RTFParsPre211, Graphics;
|
2010-05-20 10:27:49 +00:00
|
|
|
|
|
|
|
function MVCParserLoadStream(ARich: TCustomRichMemo; Source: TStream): Boolean;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
type
|
|
|
|
{ TRTFMemoParser }
|
|
|
|
|
|
|
|
TRTFMemoParser = class(TRTFParser)
|
2010-05-20 12:21:17 +00:00
|
|
|
private
|
|
|
|
txtbuf : String; // keep it UTF8 encoded!
|
|
|
|
|
|
|
|
fcolor : TColor; // Foreground color
|
2014-11-16 06:46:18 +00:00
|
|
|
txtlen : Integer;
|
|
|
|
pm : TParaMetric;
|
|
|
|
pa : TParaAlignment;
|
|
|
|
fnum: Integer;
|
|
|
|
fsz : double;
|
|
|
|
fst : TFontStyles;
|
2010-05-20 10:27:49 +00:00
|
|
|
protected
|
2010-05-20 12:21:17 +00:00
|
|
|
procedure classUnk;
|
2010-05-20 10:27:49 +00:00
|
|
|
procedure classText;
|
|
|
|
procedure classControl;
|
2010-05-20 12:21:17 +00:00
|
|
|
procedure classGroup;
|
|
|
|
procedure classEof;
|
2014-11-16 06:46:18 +00:00
|
|
|
procedure doChangePara(aminor, aparam: Integer);
|
2010-05-20 10:27:49 +00:00
|
|
|
|
|
|
|
procedure doSpecialChar;
|
2014-11-16 06:46:18 +00:00
|
|
|
procedure doChangeCharAttr(aminor, aparam: Integer);
|
2010-05-20 12:21:17 +00:00
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
function DefaultTextColor: TColor;
|
2010-05-20 12:21:17 +00:00
|
|
|
procedure PushText;
|
2010-05-20 10:27:49 +00:00
|
|
|
public
|
|
|
|
Memo : TCustomRichMemo;
|
|
|
|
constructor Create(AMemo: TCustomRichMemo; AStream: TStream);
|
2010-05-20 12:21:17 +00:00
|
|
|
procedure StartReading;
|
2010-05-20 10:27:49 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{ TRTFMemoParserr }
|
2010-05-20 12:21:17 +00:00
|
|
|
|
|
|
|
procedure TRTFMemoParser.classUnk;
|
|
|
|
begin
|
|
|
|
//writelN('unk: ', rtfMajor, ' ',rtfMinor,' ', rtfParam,' ', GetRtfText);
|
|
|
|
end;
|
|
|
|
|
2010-05-20 10:27:49 +00:00
|
|
|
procedure TRTFMemoParser.classText;
|
|
|
|
begin
|
2014-11-16 06:46:18 +00:00
|
|
|
//writeln('txt: ', rtfMajor, ' ',rtfMinor,' ', rtfParam,' ',Self.GetRtfText);
|
2010-05-20 10:27:49 +00:00
|
|
|
case rtfMinor of
|
2010-05-20 12:21:17 +00:00
|
|
|
rtfOptDest: {skipping option generator};
|
2010-05-20 10:27:49 +00:00
|
|
|
else
|
2010-05-20 12:21:17 +00:00
|
|
|
txtbuf:=txtbuf+Self.GetRtfText;
|
2014-11-16 06:46:18 +00:00
|
|
|
txtlen:=length(txtbuf);
|
|
|
|
|
2010-05-20 10:27:49 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TRTFMemoParser.classControl;
|
|
|
|
begin
|
2014-11-16 06:46:18 +00:00
|
|
|
if txtbuf<>'' then PushText;
|
2010-05-20 10:27:49 +00:00
|
|
|
//writeln('ctrl: ', rtfClass,' ', rtfMajor, ' ', Self.GetRtfText, ' ',rtfMinor,' ', rtfParam);
|
|
|
|
case rtfMajor of
|
|
|
|
rtfSpecialChar: doSpecialChar;
|
2014-11-16 06:46:18 +00:00
|
|
|
rtfCharAttr: doChangeCharAttr(rtfMinor, rtfParam);
|
|
|
|
rtfParAttr: doChangePara(rtfMinor, rtfParam);
|
2010-05-20 10:27:49 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2010-05-20 12:21:17 +00:00
|
|
|
procedure TRTFMemoParser.classGroup;
|
|
|
|
begin
|
|
|
|
//writeln('group: ', rtfMajor, ' ',rtfMinor,' ', rtfParam, ' ', GetRtfText);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TRTFMemoParser.classEof;
|
|
|
|
begin
|
|
|
|
PushText;
|
|
|
|
end;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
procedure TRTFMemoParser.doChangePara(aminor, aparam: Integer);
|
|
|
|
begin
|
|
|
|
case aminor of
|
|
|
|
rtfParDef:begin
|
|
|
|
FillChar(pm, sizeof(pm), 0);
|
|
|
|
pa:=paLeft;
|
|
|
|
end;
|
|
|
|
rtfQuadLeft: pa:=paLeft;
|
|
|
|
rtfQuadRight: pa:=paRight;
|
|
|
|
rtfQuadJust: pa:=paJustify;
|
|
|
|
rtfQuadCenter: pa:=paCenter;
|
|
|
|
rtfFirstIndent: begin
|
|
|
|
pm.FirstLine:=aparam / 20;
|
|
|
|
pm.FirstLine:=pm.FirstLine+pm.HeadIndent;
|
|
|
|
end;
|
|
|
|
rtfLeftIndent: begin
|
|
|
|
pm.HeadIndent:=aparam / 20;
|
|
|
|
pm.FirstLine:=pm.FirstLine+pm.HeadIndent;
|
|
|
|
end;
|
|
|
|
rtfRightIndent: pm.TailIndent := aparam / 20;
|
|
|
|
rtfSpaceBefore: pm.SpaceBefore := aparam / 20;
|
|
|
|
rtfSpaceAfter: pm.SpaceAfter := aparam / 20;
|
|
|
|
rtfSpaceBetween: pm.LineSpacing := aparam / 240;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2010-05-20 10:27:49 +00:00
|
|
|
procedure TRTFMemoParser.doSpecialChar;
|
|
|
|
const
|
2010-05-20 12:21:17 +00:00
|
|
|
{$ifdef MSWINDOWS}
|
|
|
|
CharPara = #13#10;
|
|
|
|
{$else}
|
2010-05-20 10:27:49 +00:00
|
|
|
CharPara = #10;
|
2010-05-20 12:21:17 +00:00
|
|
|
{$endif}
|
2010-05-20 10:27:49 +00:00
|
|
|
CharTab = #9;
|
|
|
|
CharLine = #13;
|
|
|
|
begin
|
|
|
|
case rtfMinor of
|
2010-05-20 12:21:17 +00:00
|
|
|
rtfLine: txtbuf:=txtbuf+CharLine;
|
|
|
|
rtfPar: txtbuf:=txtbuf+CharPara;
|
|
|
|
rtfTab: txtbuf:=txtbuf+CharTab;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
procedure TRTFMemoParser.doChangeCharAttr(aminor, aparam: Integer);
|
2010-05-20 12:21:17 +00:00
|
|
|
var
|
|
|
|
p : PRTFColor;
|
|
|
|
begin
|
|
|
|
if txtbuf<>'' then PushText;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
case aminor of
|
|
|
|
rtfPlain: fst:=[];
|
|
|
|
rtfBold: if aparam=0 then Exclude(fst,fsBold) else Include(fst, fsBold);
|
|
|
|
rtfItalic: if aparam=0 then Exclude(fst,fsItalic) else Include(fst, fsItalic);
|
|
|
|
rtfStrikeThru: if aparam=0 then Exclude(fst,fsStrikeOut) else Include(fst, fsStrikeOut);
|
|
|
|
rtfFontNum: fnum:=aparam;
|
|
|
|
rtfFontSize: fsz:=aparam/2;
|
|
|
|
rtfUnderline: if aparam=0 then Exclude(fst,fsUnderline) else Include(fst, fsUnderline);
|
|
|
|
rtfNoUnderline: Exclude(fst, fsUnderline);
|
2010-05-20 12:21:17 +00:00
|
|
|
rtfForeColor: begin
|
|
|
|
if rtfParam<>0 then p:=Colors[rtfParam]
|
|
|
|
else p:=nil;
|
|
|
|
if not Assigned(p) then
|
2014-11-16 06:46:18 +00:00
|
|
|
fcolor:=DefaultTextColor
|
2010-05-20 12:21:17 +00:00
|
|
|
else
|
|
|
|
fcolor:=RGBToColor(p^.rtfCRed, p^.rtfCGreen, p^.rtfCBlue);
|
|
|
|
end;
|
2010-05-20 10:27:49 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
function TRTFMemoParser.DefaultTextColor:TColor;
|
2010-05-20 12:21:17 +00:00
|
|
|
begin
|
|
|
|
Result:=ColorToRGB(Memo.Font.Color);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TRTFMemoParser.PushText;
|
|
|
|
var
|
|
|
|
len : Integer;
|
2014-11-16 06:46:18 +00:00
|
|
|
font : TFontParams;
|
|
|
|
pf : PRTFFONT;
|
|
|
|
selst : Integer;
|
2010-05-20 12:21:17 +00:00
|
|
|
begin
|
|
|
|
len:=UTF8Length(txtbuf);
|
|
|
|
if len=0 then Exit;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
Memo.SelStart:=MaxInt;
|
|
|
|
selst:=Memo.SelStart;
|
|
|
|
// in order to get the start selection, we need to switch to the last character
|
|
|
|
// and then get the value. SelStart doesn't match GetTextLen, since
|
|
|
|
// "StartSel" is based on number of visible characters (i.e. line break is 1 character)
|
|
|
|
// while GetTextLen is based on number of actual string characters
|
|
|
|
// selst:=Memo.GetTextLen;
|
|
|
|
|
|
|
|
Memo.SelStart:=selst;
|
2010-05-20 12:21:17 +00:00
|
|
|
Memo.SelLength:=0;
|
|
|
|
Memo.SelText:=txtbuf;
|
|
|
|
|
2014-11-16 06:46:18 +00:00
|
|
|
Memo.SetParaMetric(selst, 1, pm);
|
|
|
|
Memo.SetParaAlignment(selst, 1, pa);
|
|
|
|
|
|
|
|
Memo.GetTextAttributes(selst, font);
|
|
|
|
pf:=Fonts[fnum];
|
|
|
|
if Assigned(pf) then
|
|
|
|
font.Name:=pf^.rtfFName;
|
|
|
|
font.Size:=round(fsz);
|
|
|
|
font.Style:=fst;
|
|
|
|
font.Color:=ColorToRGB(fColor);
|
|
|
|
Memo.SetTextAttributes(selst, len, font);
|
2010-05-20 12:21:17 +00:00
|
|
|
txtbuf:='';
|
|
|
|
end;
|
|
|
|
|
2010-05-20 10:27:49 +00:00
|
|
|
constructor TRTFMemoParser.Create(AMemo:TCustomRichMemo;AStream:TStream);
|
|
|
|
begin
|
|
|
|
inherited Create(AStream);
|
|
|
|
Memo:=AMemo;
|
|
|
|
ClassCallBacks[rtfText]:=@classText;
|
|
|
|
ClassCallBacks[rtfControl]:=@classControl;
|
2010-05-20 12:21:17 +00:00
|
|
|
ClassCallBacks[rtfGroup]:=@classGroup;
|
|
|
|
ClassCallBacks[rtfUnknown]:=@classUnk;
|
|
|
|
ClassCallBacks[rtfEof]:=@classEof;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TRTFMemoParser.StartReading;
|
|
|
|
begin
|
|
|
|
Memo.Lines.BeginUpdate;
|
|
|
|
try
|
2014-11-16 06:46:18 +00:00
|
|
|
fsz:=12;//\fsN Font size in half-points (the default is 24).
|
|
|
|
fnum:=0;
|
|
|
|
|
2010-05-20 12:21:17 +00:00
|
|
|
inherited StartReading;
|
|
|
|
PushText;
|
|
|
|
Memo.SelStart:=0;
|
|
|
|
Memo.SelLength:=0;
|
|
|
|
finally
|
|
|
|
Memo.Lines.EndUpdate;
|
|
|
|
end;
|
2010-05-20 10:27:49 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function MVCParserLoadStream(ARich: TCustomRichMemo; Source: TStream): Boolean;
|
|
|
|
var
|
|
|
|
p : TRTFMemoParser;
|
|
|
|
begin
|
|
|
|
Result:=Assigned(ARich) and Assigned(Source);
|
|
|
|
if not Result then Exit;
|
|
|
|
|
|
|
|
p:=TRTFMemoParser.Create(ARich, Source);
|
|
|
|
try
|
|
|
|
p.StartReading;
|
|
|
|
finally
|
|
|
|
p.Free;
|
|
|
|
end;
|
|
|
|
Result:=True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
|
|
RTFLoadStream:=@MVCParserLoadStream;
|
|
|
|
|
|
|
|
end.
|