CodeSnip Old Code (SVN)
A repository for source code snippets, designed with Pascal in mind.
Brought to you by:
delphidabbler
--- a +++ b/trunk/Src/UActiveTextRTF.pas @@ -0,0 +1,256 @@ +{ + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/ + * + * Copyright (C) 2012, Peter Johnson (www.delphidabbler.com). + * + * $Rev$ + * $Date$ + * + * Implements a class and helpers that create RTF representations of active text + * with customised styling. +} + + +unit UActiveTextRTF; + + +interface + + +uses + // Delphi + Generics.Collections, + // Project + UActiveText, UBaseObjects, URTFBuilder, URTFStyles; + + +type + // TODO: need a better name for this class + TRTFStyleMap = class(TObject) + strict private + var + fMap: TDictionary<TActiveTextActionElemKind,TRTFStyle>; + function GetStyle(ElemKind: TActiveTextActionElemKind): TRTFStyle; + public + constructor Create; + destructor Destroy; override; + procedure Add(const ElemKind: TActiveTextActionElemKind; + const Style: TRTFStyle); + procedure Assign(const Src: TRTFStyleMap); + // enumerator enumerates styles, not pair or action element kind + function GetEnumerator: TEnumerator<TRTFStyle>; + property Styles[ElemKInd: TActiveTextActionElemKind]: TRTFStyle + read GetStyle; default; + end; + +type + TActiveTextRTF = class(TObject) + strict private + var + fElemStyleMap: TRTFStyleMap; + fDisplayURLs: Boolean; + fURLStyle: TRTFStyle; + fInBlock: Boolean; + procedure SetElemStyleMap(const ElemStyleMap: TRTFStyleMap); + procedure Initialise(const Builder: TRTFBuilder); + procedure RenderTextElem(Elem: IActiveTextTextElem; + const Builder: TRTFBuilder); + procedure RenderBlockActionElem(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); + procedure RenderInlineActionElem(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); + procedure RenderURL(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); + public + constructor Create; + destructor Destroy; override; + property ElemStyleMap: TRTFStyleMap + read fElemStyleMap write SetElemStyleMap; + property DisplayURLs: Boolean read fDisplayURLs write fDisplayURLs; + property URLStyle: TRTFStyle read fURLStyle write fURLStyle; + procedure Render(ActiveText: IActiveText; + const RTFBuilder: TRTFBuilder); + end; + + +implementation + + +uses + // Project + SysUtils, Generics.Defaults; + + +{ TRTFStyleMap } + +procedure TRTFStyleMap.Add(const ElemKind: TActiveTextActionElemKind; + const Style: TRTFStyle); +begin + Assert(not fMap.ContainsKey(ElemKind), + ClassName + '.Add: ElemKind already in map'); + fMap.Add(ElemKind, Style); +end; + +procedure TRTFStyleMap.Assign(const Src: TRTFStyleMap); +var + Entry: TPair<TActiveTextActionElemKind, TRTFStyle>; +begin + fMap.Clear; + for Entry in Src.fMap do + fMap.Add(Entry.Key, Entry.Value); +end; + +constructor TRTFStyleMap.Create; +begin + inherited Create; + fMap := TDictionary<TActiveTextActionElemKind,TRTFStyle>.Create( + TDelegatedEqualityComparer<TActiveTextActionElemKind>.Create( + function (const Left, Right: TActiveTextActionElemKind): Boolean + begin + Result := Left = Right; + end, + function (const ElemKind: TActiveTextActionElemKind): Integer + begin + Result := Ord(ElemKind); + end + ) + ) +end; + +destructor TRTFStyleMap.Destroy; +begin + fMap.Free; + inherited; +end; + +function TRTFStyleMap.GetEnumerator: TEnumerator<TRTFStyle>; +begin + Result := fMap.Values.GetEnumerator; +end; + +function TRTFStyleMap.GetStyle(ElemKind: TActiveTextActionElemKind): TRTFStyle; +begin + if fMap.ContainsKey(ElemKind) then + Result := fMap[ElemKind] + else + Result := TRTFStyle.CreateNull; +end; + +{ TActiveTextRTF } + +constructor TActiveTextRTF.Create; +begin + inherited Create; + fElemStyleMap := TRTFStyleMap.Create; +end; + +destructor TActiveTextRTF.Destroy; +begin + fElemStyleMap.Free; + inherited; +end; + +procedure TActiveTextRTF.Initialise(const Builder: TRTFBuilder); +var + Style: TRTFStyle; +begin + for Style in fElemStyleMap do + begin + Builder.FontTable.AddFromStyle(Style); + Builder.ColourTable.AddFromStyle(Style); + end; + Builder.FontTable.AddFromStyle(fURLStyle); + Builder.ColourTable.AddFromStyle(fURLStyle); +end; + +procedure TActiveTextRTF.Render(ActiveText: IActiveText; + const RTFBuilder: TRTFBuilder); +var + Elem: IActiveTextElem; + TextElem: IActiveTextTextElem; + ActionElem: IActiveTextActionElem; +begin + Initialise(RTFBuilder); + for Elem in ActiveText do + begin + if Supports(Elem, IActiveTextTextElem, TextElem) then + RenderTextElem(TextElem, RTFBuilder) + else if Supports(Elem, IActiveTextActionElem, ActionElem) then + begin + if ActionElem.DisplayStyle = dsBlock then + RenderBlockActionElem(ActionElem, RTFBuilder) + else + RenderInlineActionElem(ActionElem, RTFBuilder); + end; + end; +end; + +procedure TActiveTextRTF.RenderBlockActionElem(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); +begin + case Elem.State of + fsOpen: + begin + fInBlock := True; + Builder.BeginGroup; + Builder.ApplyStyle(fElemStyleMap[Elem.Kind]); + end; + fsClose: + begin + Builder.EndPara; + Builder.EndGroup; + fInBlock := False; + end; + end; +end; + +procedure TActiveTextRTF.RenderInlineActionElem(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); +begin + if not fInBlock then + Exit; + case Elem.State of + fsOpen: + begin + Builder.BeginGroup; + Builder.ApplyStyle(fElemStyleMap[Elem.Kind]); + end; + fsClose: + begin + if (Elem.Kind = ekLink) and fDisplayURLs then + RenderURL(Elem, Builder); + Builder.EndGroup; + end; + end; +end; + +procedure TActiveTextRTF.RenderTextElem(Elem: IActiveTextTextElem; + const Builder: TRTFBuilder); +begin + if not fInBlock then + Exit; + Builder.AddText(Elem.Text); +end; + +procedure TActiveTextRTF.RenderURL(Elem: IActiveTextActionElem; + const Builder: TRTFBuilder); +resourcestring + sURL = ' (%s)'; // formatting for URLs from hyperlinks +begin + Assert(Elem.Kind = ekLink, ClassName + '.RenderURL: Not a link element'); + Builder.BeginGroup; + Builder.ApplyStyle(URLStyle); + Builder.AddText( + Format(sURL, [Elem.Attrs[TActiveTextAttrNames.Link_URL]]) + ); + Builder.EndGroup; +end; + +procedure TActiveTextRTF.SetElemStyleMap(const ElemStyleMap: TRTFStyleMap); +begin + fElemStyleMap.Assign(ElemStyleMap); +end; + +end.