Componentes.Terceros.FastRe.../internal/4.2/1/Source/frxRich.pas
2007-11-18 19:40:07 +00:00

625 lines
16 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport v4.0 }
{ RichEdit Add-In Object }
{ }
{ Copyright (c) 1998-2007 }
{ by Alexander Tzyganenko, }
{ Fast Reports Inc. }
{ }
{******************************************}
unit frxRich;
interface
{$I frx.inc}
uses
Windows, Messages, SysUtils, Classes, Graphics, Forms, Menus, frxClass,
RichEdit, frxRichEdit, frxPrinter
{$IFDEF Delphi6}
, Variants
{$ENDIF}
{$IFDEF FR_COM}
, ActiveX, AxCtrls
, ClrStream
, FastReport_TLB
{$ENDIF};
type
TfrxRichObject = class(TComponent) // fake component
end;
{$IFDEF FR_COM}
TfrxRichView = class(TfrxStretcheable, IfrxRichView)
{$ELSE}
TfrxRichView = class(TfrxStretcheable)
{$ENDIF}
private
FAllowExpressions: Boolean;
FExpressionDelimiters: String;
FFlowTo: TfrxRichView;
FGapX: Extended;
FGapY: Extended;
FParaBreak: Boolean;
FRichEdit: TrxRichEdit;
FTempStream: TMemoryStream;
FTempStream1: TMemoryStream;
FWysiwyg: Boolean;
function CreateMetafile: TMetafile;
function IsExprDelimitersStored: Boolean;
function UsePrinterCanvas: Boolean;
procedure ReadData(Stream: TStream);
procedure WriteData(Stream: TStream);
{$IFDEF FR_COM}
function LoadViewFromStream(const Stream: IUnknown): HResult; stdcall;
function SaveViewToStream(const Stream: IUnknown): HResult; stdcall;
function Get_RichAlign(out Value: frxHAlign): HResult; stdcall;
function Set_RichAlign(Value: frxHAlign): HResult; stdcall;
function Get_WYSIWIG(out Value: WordBool): HResult; stdcall;
function Set_WYSIWIG(Value: WordBool): HResult; stdcall;
function Get_AllowExpressions(out Value: WordBool): HResult; stdcall;
function Set_AllowExpressions(Value: WordBool): HResult; stdcall;
{$ENDIF}
protected
procedure DefineProperties(Filer: TFiler); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX, OffsetY: Extended); override;
procedure AfterPrint; override;
procedure BeforePrint; override;
procedure GetData; override;
procedure InitPart; override;
function CalcHeight: Extended; override;
function DrawPart: Extended; override;
class function GetDescription: String; override;
function GetComponentText: String; override;
property RichEdit: TrxRichEdit read FRichEdit;
published
property AllowExpressions: Boolean read FAllowExpressions
write FAllowExpressions default True;
property BrushStyle;
property Color;
property Cursor;
property DataField;
property DataSet;
property DataSetName;
property ExpressionDelimiters: String read FExpressionDelimiters
write FExpressionDelimiters stored IsExprDelimitersStored;
property FlowTo: TfrxRichView read FFlowTo write FFlowTo;
property Frame;
property GapX: Extended read FGapX write FGapX;
property GapY: Extended read FGapY write FGapY;
property TagStr;
property URL;
property Wysiwyg: Boolean read FWysiwyg write FWysiwyg default True;
end;
procedure frxAssignRich(RichFrom, RichTo: TrxRichEdit);
implementation
uses
frxRichRTTI,
{$IFNDEF NO_EDITORS}
frxRichEditor,
{$ENDIF}
frxUtils, frxDsgnIntf, frxRes;
procedure frxAssignRich(RichFrom, RichTo: TrxRichEdit);
var
st: TMemoryStream;
begin
st := TMemoryStream.Create;
try
RichFrom.Lines.SaveToStream(st);
st.Position := 0;
RichTo.Lines.LoadFromStream(st);
finally
st.Free;
end;
end;
{ TfrxRichView }
constructor TfrxRichView.Create(AOwner: TComponent);
begin
inherited;
FRichEdit := TrxRichEdit.Create(nil);
FRichEdit.Parent := frxParentForm;
SendMessage(frxParentForm.Handle, WM_CREATEHANDLE, Integer(FRichEdit), 0);
FRichEdit.AutoURLDetect := False;
{ make rich transparent }
SetWindowLong(FRichEdit.Handle, GWL_EXSTYLE,
GetWindowLong(FRichEdit.Handle, GWL_EXSTYLE) or WS_EX_TRANSPARENT);
FTempStream := TMemoryStream.Create;
FTempStream1 := TMemoryStream.Create;
FAllowExpressions := True;
FExpressionDelimiters := '[,]';
FGapX := 2;
FGapY := 1;
FWysiwyg := True;
end;
destructor TfrxRichView.Destroy;
begin
SendMessage(frxParentForm.Handle, WM_DESTROYHANDLE, Integer(FRichEdit), 0);
FRichEdit.Free;
FTempStream.Free;
FTempStream1.Free;
inherited;
end;
class function TfrxRichView.GetDescription: String;
begin
Result := frxResources.Get('obRich');
end;
function TfrxRichView.IsExprDelimitersStored: Boolean;
begin
Result := FExpressionDelimiters <> '[,]';
end;
procedure TfrxRichView.DefineProperties(Filer: TFiler);
begin
inherited;
Filer.DefineBinaryProperty('RichEdit', ReadData, WriteData, True);
end;
procedure TfrxRichView.ReadData(Stream: TStream);
begin
FRichEdit.Lines.LoadFromStream(Stream);
end;
procedure TfrxRichView.WriteData(Stream: TStream);
begin
FRichEdit.Lines.SaveToStream(Stream);
end;
procedure TfrxRichView.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FFlowTo) then
FFlowTo := nil;
end;
function TfrxRichView.UsePrinterCanvas: Boolean;
begin
Result := frxPrinters.HasPhysicalPrinters and FWysiwyg;
end;
function TfrxRichView.CreateMetafile: TMetafile;
var
Range: TFormatRange;
EMFCanvas: TMetafileCanvas;
PrinterHandle: THandle;
begin
if UsePrinterCanvas then
PrinterHandle := frxPrinters.Printer.Canvas.Handle
else
PrinterHandle := GetDC(0);
FillChar(Range, SizeOf(TFormatRange), 0);
with Range do
begin
rc := Rect(Round(GapX * 1440 / 96), Round(GapY * 1440 / 96),
Round((Width - GapX) * 1440 / 96),
Round((Height - GapY) * 1440 / 96));
rcPage := rc;
Result := TMetafile.Create;
Result.Width := Round(Width * GetDeviceCaps(PrinterHandle, LOGPIXELSX) / 96);
Result.Height := Round(Height * GetDeviceCaps(PrinterHandle, LOGPIXELSY) / 96);
EMFCanvas := TMetafileCanvas.Create(Result, PrinterHandle);
hdc := EMFCanvas.Handle;
hdcTarget := hdc;
chrg.cpMin := 0;
chrg.cpMax := -1;
FRichEdit.Perform(EM_FORMATRANGE, 1, Integer(@Range));
end;
if not UsePrinterCanvas then
ReleaseDC(0, PrinterHandle);
FRichEdit.Perform(EM_FORMATRANGE, 0, 0);
EMFCanvas.Free;
end;
procedure TfrxRichView.Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX,
OffsetY: Extended);
var
EMF: TMetafile;
begin
BeginDraw(Canvas, ScaleX, ScaleY, OffsetX, OffsetY);
DrawBackground;
EMF := CreateMetafile;
try
Canvas.StretchDraw(Rect(FX, FY, FX1, FY1), EMF);
finally
EMF.Free;
end;
DrawFrame;
end;
procedure TfrxRichView.BeforePrint;
begin
inherited;
FTempStream.Position := 0;
FRichEdit.Lines.SaveToStream(FTempStream);
end;
procedure TfrxRichView.AfterPrint;
begin
FTempStream.Position := 0;
FRichEdit.Lines.LoadFromStream(FTempStream);
inherited;
end;
procedure TfrxRichView.GetData;
var
ss: TStringStream;
i, j, TextLen: Integer;
s1, s2, dc1, dc2: String;
function GetSpecial(const s: String; Pos: Integer): Integer;
var
i: Integer;
begin
Result := 0;
for i := 1 to Pos do
if s[i] in [#10, #13] then
Inc(Result);
end;
function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var
I,X: Integer;
Len, LenSubStr: Integer;
begin
if Offset = 1 then
Result := Pos(SubStr, S)
else
begin
I := Offset;
LenSubStr := Length(SubStr);
Len := Length(S) - LenSubStr + 1;
while I <= Len do
begin
if S[I] = SubStr[1] then
begin
X := 1;
while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do
Inc(X);
if (X = LenSubStr) then
begin
Result := I;
exit;
end;
end;
Inc(I);
end;
Result := 0;
end;
end;
begin
inherited;
if IsDataField then
begin
ss := TStringStream.Create(VarToStr(DataSet.Value[DataField]));
try
FRichEdit.Lines.LoadFromStream(ss);
finally
ss.Free;
end;
end;
if FAllowExpressions then
begin
dc1 := FExpressionDelimiters;
dc2 := Copy(dc1, Pos(',', dc1) + 1, 255);
dc1 := Copy(dc1, 1, Pos(',', dc1) - 1);
with FRichEdit do
try
Lines.BeginUpdate;
i := Pos(dc1, Text);
while i > 0 do
begin
SelStart := i - 1 - GetSpecial(Text, i) div 2;
s1 := frxGetBrackedVariable(Text, dc1, dc2, i, j);
s2 := VarToStr(Report.Calc(s1));
SelLength := j - i + 1;
TextLen := Length(Text) - SelLength;
SelText := s2;
i := PosEx(dc1, Text, i + Length(Text) - TextLen);
end;
finally
Lines.EndUpdate;
end;
end;
if FFlowTo <> nil then
begin
InitPart;
DrawPart;
FTempStream1.Position := 0;
FlowTo.RichEdit.Lines.LoadFromStream(FTempStream1);
FFlowTo.AllowExpressions := False;
end;
end;
function TfrxRichView.CalcHeight: Extended;
var
Range: TFormatRange;
begin
FillChar(Range, SizeOf(TFormatRange), 0);
with Range do
begin
rc := Rect(0, 0, Round((Width - GapX * 2) * 1440 / 96), Round(1000000 * 1440.0 / 96));
rcPage := rc;
if UsePrinterCanvas then
hdc := frxPrinters.Printer.Canvas.Handle
else
hdc := GetDC(0);
hdcTarget := hdc;
chrg.cpMin := 0;
chrg.cpMax := -1;
FRichEdit.Perform(EM_FORMATRANGE, 0, Integer(@Range));
if not UsePrinterCanvas then
ReleaseDC(0, hdc);
if RichEdit.GetTextLen = 0 then
Result := 0
else
Result := Round(rc.Bottom / (1440.0 / 96)) + 2 * GapY + 2;
end;
FRichEdit.Perform(EM_FORMATRANGE, 0, 0);
end;
function TfrxRichView.DrawPart: Extended;
var
Range: TFormatRange;
LastChar: Integer;
begin
{ get remained part of text }
FTempStream1.Position := 0;
FRichEdit.Lines.LoadFromStream(FTempStream1);
if FParaBreak then
begin
// FRichEdit.SelStart := 1;
// FRichEdit.SelLength := 1;
FRichEdit.Paragraph.FirstIndent := 0;
FRichEdit.Paragraph.LeftIndent := 0;
end;
{ calculate the last visible char }
FillChar(Range, SizeOf(TFormatRange), 0);
with Range do
begin
rc := Rect(0, 0, Round((Width - GapX * 2) * 1440 / 96),
Round((Height - GapY * 2) * 1440 / 96));
rcPage := rc;
if UsePrinterCanvas then
hdc := frxPrinters.Printer.Canvas.Handle
else
hdc := GetDC(0);
hdcTarget := hdc;
chrg.cpMin := 0;
chrg.cpMax := -1;
LastChar := FRichEdit.Perform(EM_FORMATRANGE, 0, Integer(@Range));
Result := Round((rcPage.Bottom - rc.Bottom) / (1440.0 / 96)) + 2 * GapY + 0.1;
if not UsePrinterCanvas then
ReleaseDC(0, hdc);
end;
FRichEdit.Perform(EM_FORMATRANGE, 0, 0);
{ text can't fit }
if Result < 0 then
begin
Result := Height;
Exit;
end;
{ copy the outbounds text to the temp stream }
try
if LastChar > 1 then
begin
FRichEdit.SelStart := LastChar - 1;
FRichEdit.SelLength := 1;
FParaBreak := FRichEdit.SelText <> #13;
end;
FRichEdit.SelStart := LastChar;
FRichEdit.SelLength := FRichEdit.GetTextLen - LastChar + 1;
if FRichEdit.SelLength = 1 then
Result := 0;
FTempStream1.Clear;
FRichEdit.StreamMode := [smSelection];
FRichEdit.Lines.SaveToStream(FTempStream1);
FRichEdit.SelText := '';
finally
FRichEdit.StreamMode := [];
end;
end;
procedure TfrxRichView.InitPart;
begin
FTempStream1.Clear;
FRichEdit.Lines.SaveToStream(FTempStream1);
FParaBreak := False;
end;
function TfrxRichView.GetComponentText: String;
var
FTStream: TMemoryStream;
begin
if PlainText then
begin
FTStream := TMemoryStream.Create;
try
FTempStream.Clear;
FRichEdit.Lines.SaveToStream(FTStream);
FRichEdit.PlainText := True;
FRichEdit.Lines.SaveToStream(FTempStream);
SetLength(Result, FTempStream.Size);
FTempStream.Position := 0;
FTempStream.Read(Result[1], FTempStream.Size);
FRichEdit.PlainText := False;
FTStream.Position := 0;
FRichEdit.Lines.LoadFromStream(FTStream);
finally
FTStream.Free;
end;
end
else
begin
FTempStream.Clear;
FRichEdit.Lines.SaveToStream(FTempStream);
SetLength(Result, FTempStream.Size);
FTempStream.Position := 0;
FTempStream.Read(Result[1], FTempStream.Size);
end;
end;
{$IFDEF FR_COM}
function TfrxRichView.LoadViewFromStream(const Stream: IUnknown): HResult; stdcall;
var
ComStream: IStream;
OleStream: TOleStream;
NetStream: _Stream;
ClrStream: TClrStream;
begin
try
Result := Stream.QueryInterface(IStream, ComStream);
if Result = S_OK then
begin
OleStream := TOleStream.Create(ComStream);
ReadData(OleStream);
OleStream.Free;
ComStream := nil;
end
else
begin
Result := Stream.QueryInterface(_Stream, NetStream);
if Result = S_OK then
begin
ClrStream := TClrStream.Create(NetStream);
ReadData(ClrStream);
ClrStream.Free;
NetStream._Release();
end;
end;
except
Result := E_FAIL;
end;
end;
function TfrxRichView.SaveViewToStream(const Stream: IUnknown): HResult; stdcall;
var
ComStream: IStream;
OleStream: TOleStream;
NetStream: _Stream;
ClrStream: TClrStream;
begin
try
Result := Stream.QueryInterface(IStream, ComStream);
if Result = S_OK then
begin
OleStream := TOleStream.Create(ComStream);
WriteData(OleStream);
OleStream.Free;
ComStream := nil;
end
else
begin
Result := Stream.QueryInterface(_Stream, NetStream);
if Result = S_OK then
begin
ClrStream := TClrStream.Create(NetStream);
WriteData(ClrStream);
ClrStream.Free;
NetStream._Release();
end;
end;
except
Result := E_FAIL;
end;
end;
function TfrxRichView.Get_RichAlign(out Value: frxHAlign): HResult; stdcall;
begin
Result := S_OK;
Value := frxHAlign(FRichEdit.Paragraph.Alignment);
end;
function TfrxRichView.Set_RichAlign(Value: frxHAlign): HResult; stdcall;
begin
Result := S_OK;
FRichEdit.SelectAll;
case Value of
hAlignLeft: FRichEdit.Paragraph.Alignment := paLeftJustify;
hAlignRight: FRichEdit.Paragraph.Alignment := paRightJustify;
hAlignCenter: FRichEdit.Paragraph.Alignment := paCenter;
hAlignBlock: FRichEdit.Paragraph.Alignment := paJustify;
else Result := E_FAIL;
end;
end;
function TfrxRichView.Get_WYSIWIG(out Value: WordBool): HResult; stdcall;
begin
Value := FWysiwyg;
Result := S_OK;
end;
function TfrxRichView.Set_WYSIWIG(Value: WordBool): HResult; stdcall;
begin
FWysiwyg := Value;
Result := S_OK;
end;
function TfrxRichView.Get_AllowExpressions(out Value: WordBool): HResult; stdcall;
begin
Value := FAllowExpressions;
Result := S_OK;
end;
function TfrxRichView.Set_AllowExpressions(Value: WordBool): HResult; stdcall;
begin
FAllowExpressions := Value;
Result := S_OK;
end;
{$ENDIF}
initialization
frxObjects.RegisterObject1(TfrxRichView, nil, '', '', 0, 26);
end.
//862fd5d6aa1a637203d9b08a3c0bcfb0