mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-15 17:55:57 +02:00

1. Localization Collate option in the form of print options 2. Fixed search on the generated report is not English texts 3. The expanded diagnostic error messages during the reporting 4. Prohibited creating variables in reports containing the point: for example aaa.bbb: = 1; git-svn-id: trunk@43821 -
12198 lines
314 KiB
ObjectPascal
12198 lines
314 KiB
ObjectPascal
|
|
{*****************************************}
|
|
{ }
|
|
{ FastReport v2.3 }
|
|
{ Report classes }
|
|
{ }
|
|
{ Copyright (c) 1998-99 by Tzyganenko A. }
|
|
{ }
|
|
{*****************************************}
|
|
|
|
unit LR_Class;
|
|
|
|
interface
|
|
|
|
{$I LR_Vers.inc}
|
|
|
|
uses
|
|
SysUtils, Math, {$IFDEF UNIX}CLocale,{$ENDIF} Classes, MaskUtils, Controls, FileUtil,
|
|
Forms, Dialogs, Menus, Variants, DB, Graphics, Printers, osPrinters,
|
|
DOM, XMLWrite, XMLRead, XMLConf, LCLType, LCLIntf, TypInfo, LCLProc, LR_View, LR_Pars,
|
|
LR_Intrp, LR_DSet, LR_DBSet, LR_DBRel, LR_Const, LMessages, DbCtrls;
|
|
|
|
const
|
|
// object flags
|
|
flStretched = $01;
|
|
flWordWrap = $02;
|
|
flWordBreak = $04;
|
|
flAutoSize = $08;
|
|
flHideDuplicates = $10;
|
|
flStartRecord = $20;
|
|
flEndRecord = $40;
|
|
flHideZeros = $80;
|
|
|
|
flBandNewPageAfter = 2;
|
|
flBandPrintifSubsetEmpty = 4;
|
|
flBandPageBreak = 8;
|
|
flBandOnFirstPage = $10;
|
|
flBandOnLastPage = $20;
|
|
flBandRepeatHeader = $40;
|
|
|
|
flPictCenter = 2;
|
|
flPictRatio = 4;
|
|
flWantHook = $8000;
|
|
flIsDuplicate = $4000;
|
|
|
|
// object types
|
|
gtMemo = 0;
|
|
gtPicture = 1;
|
|
gtBand = 2;
|
|
gtSubReport = 3;
|
|
gtLine = 4;
|
|
gtAddIn = 10;
|
|
|
|
//format type
|
|
fmtText = 0;
|
|
fmtNumber = 1;
|
|
fmtDate = 2;
|
|
fmtTime = 3;
|
|
fmtBoolean = 4;
|
|
|
|
type
|
|
TfrDrawMode = (drAll, drCalcHeight, drAfterCalcHeight, drPart);
|
|
TfrBandType = (btReportTitle, btReportSummary,
|
|
btPageHeader, btPageFooter,
|
|
btMasterHeader, btMasterData, btMasterFooter,
|
|
btDetailHeader, btDetailData, btDetailFooter,
|
|
btSubDetailHeader, btSubDetailData, btSubDetailFooter,
|
|
btOverlay, btColumnHeader, btColumnFooter,
|
|
btGroupHeader, btGroupFooter,
|
|
btCrossHeader, btCrossData, btCrossFooter, btNone);
|
|
TfrBandTypes = set of TfrBandType;
|
|
TfrDataSetPosition = (psLocal, psGlobal);
|
|
TfrValueType = (vtNotAssigned, vtDBField, vtOther, vtFRVar);
|
|
TfrPageMode = (pmNormal, pmBuildList);
|
|
TfrBandRecType = (rtShowBand, rtFirst, rtNext);
|
|
TfrRgnType = (rtNormal, rtExtended);
|
|
TfrReportType = (rtSimple, rtMultiple);
|
|
TfrStreamMode = (smDesigning, smPrinting);
|
|
TfrFrameBorder = (frbLeft, frbTop, frbRight, frbBottom);
|
|
TfrFrameBorders = set of TfrFrameBorder;
|
|
TfrFrameStyle = (frsSolid,frsDash, frsDot, frsDashDot, frsDashDotDot,frsDouble);
|
|
TfrPageType = (ptReport, ptDialog); //todo: - remove this
|
|
TfrReportOption = (roIgnoreFieldNotFound, roIgnoreSymbolNotFound, roHideDefaultFilter);
|
|
TfrReportOptions = set of TfrReportOption;
|
|
TfrObjectType = (otlReportView, otlUIControl);
|
|
|
|
TlrDesignOption = (doUndoDisable);
|
|
TlrDesignOptions = set of TlrDesignOption;
|
|
|
|
TfrView = class;
|
|
TfrBand = class;
|
|
TfrPage = class;
|
|
TfrReport = class;
|
|
TfrExportFilter = class;
|
|
|
|
TDetailEvent = procedure(const ParName: String; var ParValue: Variant) of object;
|
|
TEnterRectEvent = procedure(Memo: TStringList; View: TfrView) of object;
|
|
TBeginDocEvent = procedure of object;
|
|
TEndDocEvent = procedure of object;
|
|
TBeginPageEvent = procedure(pgNo: Integer) of object;
|
|
TEndPageEvent = procedure(pgNo: Integer) of object;
|
|
TBeginBandEvent = procedure(Band: TfrBand) of object;
|
|
TEndBandEvent = procedure(Band: TfrBand) of object;
|
|
TfrProgressEvent = procedure(n: Integer) of object;
|
|
TBeginColumnEvent = procedure(Band: TfrBand) of object;
|
|
TPrintColumnEvent = procedure(ColNo: Integer; var Width: Integer) of object;
|
|
TManualBuildEvent = procedure(Page: TfrPage) of object;
|
|
TObjectClickEvent = procedure(View: TfrView) of object;
|
|
TMouseOverObjectEvent = procedure(View: TfrView; var ACursor: TCursor) of object;
|
|
|
|
TfrHighlightAttr = packed record
|
|
FontStyle: Word;
|
|
FontColor, FillColor: TColor;
|
|
end;
|
|
|
|
// print info about page size, margins e.t.c
|
|
TfrPrnInfo = record
|
|
PPgw, PPgh, Pgw, Pgh : Integer; // page width/height (printer/screen)
|
|
POfx, POfy, Ofx, Ofy : Integer; // offset x/y
|
|
PPw, PPh, Pw, Ph : Integer; // printable width/height
|
|
ResX, ResY : Integer; // printer resolution
|
|
end;
|
|
|
|
PfrPageInfo = ^TfrPageInfo;
|
|
TfrPageInfo = packed record // pages of a preview
|
|
R : TRect;
|
|
pgSize : Word;
|
|
pgWidth : Integer;
|
|
pgHeight : Integer;
|
|
pgOr : TPrinterOrientation;
|
|
pgMargins : Boolean;
|
|
PrnInfo : TfrPrnInfo;
|
|
Visible : Boolean;
|
|
Stream : TMemoryStream;
|
|
Page : TfrPage;
|
|
end;
|
|
|
|
PfrBandRec = ^TfrBandRec;
|
|
TfrBandRec = packed record
|
|
Band : TfrBand;
|
|
Action : TfrBandRecType;
|
|
end;
|
|
|
|
TLayoutOrder = (loColumns, loRows);
|
|
|
|
TfrMemoStrings =Class(TStringList);
|
|
TfrScriptStrings=Class(TStringList);
|
|
|
|
TfrDialogForm = Class(TForm);
|
|
|
|
{ TLrXMLConfig }
|
|
|
|
TLrXMLConfig = class (TXMLConfig)
|
|
public
|
|
procedure LoadFromStream(const Stream: TStream);
|
|
procedure SaveToStream(const Stream: TStream);
|
|
procedure SetValue(const APath: string; const AValue: string); overload;
|
|
function GetValue(const APath: string; const ADefault: string): string; overload;
|
|
end;
|
|
|
|
{ TfrObject }
|
|
|
|
TfrObject = Class(TPersistent)
|
|
private
|
|
fMemo : TfrMemoStrings;
|
|
fName : string;
|
|
fScript : TfrScriptStrings;
|
|
fVisible: Boolean;
|
|
fUpdate : Integer;
|
|
|
|
procedure SetMemo(const AValue: TfrMemoStrings);
|
|
procedure SetScript(const AValue: TfrScriptStrings);
|
|
protected
|
|
FDesignOptions:TlrDesignOptions;
|
|
BaseName : String;
|
|
OwnerPage:TfrPage;
|
|
|
|
function GetSaveProperty(const Prop : String; aObj : TPersistent=nil) : string;
|
|
procedure RestoreProperty(const Prop,aValue : String; aObj : TPersistent=nil);
|
|
procedure SetName(const AValue: string); virtual;
|
|
procedure AfterLoad;virtual;
|
|
function ExecMetod(const AName: String; p1, p2, p3: Variant; var Val: Variant):boolean;virtual;
|
|
function GetLeft: Integer;virtual;
|
|
function GetTop: Integer;virtual;
|
|
function GetWidth: Integer;virtual;
|
|
function GetHeight: Integer;virtual;
|
|
procedure SetLeft(AValue: Integer);virtual;
|
|
procedure SetTop(AValue: Integer);virtual;
|
|
procedure SetWidth(AValue: Integer);virtual;
|
|
procedure SetHeight(AValue: Integer);virtual;
|
|
procedure SetVisible(AValue: Boolean);virtual;
|
|
function GetText:string;virtual;
|
|
procedure SetText(AValue:string);virtual;
|
|
public
|
|
x, y, dx, dy: Integer;
|
|
|
|
constructor Create(AOwnerPage:TfrPage); virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure Assign(From: TfrView); virtual; overload;
|
|
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
|
|
procedure CreateUniqueName;
|
|
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); virtual;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); virtual;
|
|
|
|
property Memo : TfrMemoStrings read fMemo write SetMemo;
|
|
property Script : TfrScriptStrings read fScript write SetScript;
|
|
property Left : Integer read GetLeft write SetLeft;
|
|
property Top : Integer read GetTop write SetTop;
|
|
property Width : Integer read GetWidth write SetWidth;
|
|
property Height : Integer read GetHeight write SetHeight;
|
|
property DesignOptions:TlrDesignOptions read FDesignOptions;
|
|
published
|
|
property Name : string read fName write SetName;
|
|
property Visible: Boolean read fVisible write SetVisible;
|
|
end;
|
|
|
|
{ TfrView }
|
|
|
|
TfrView = class(TfrObject)
|
|
private
|
|
fFillColor : TColor;
|
|
fCanvas : TCanvas;
|
|
fFrameColor: TColor;
|
|
fFrames : TfrFrameBorders;
|
|
fFrameStyle: TfrFrameStyle;
|
|
fFrameWidth: Double;
|
|
fStreamMode: TfrStreamMode;
|
|
fFormat : Integer;
|
|
fFormatStr : string;
|
|
fFrameTyp : word;
|
|
FTag: string;
|
|
FURLInfo: string;
|
|
function GetLeft: Double;
|
|
function GetStretched: Boolean;
|
|
function GetTop: Double;
|
|
procedure P1Click(Sender: TObject);
|
|
procedure SetFillColor(const AValue: TColor);
|
|
procedure SetFormat(const AValue: Integer);
|
|
procedure SetFormatStr(const AValue: String);
|
|
procedure SetFrameColor(const AValue: TColor);
|
|
procedure SetFrames(const AValue: TfrFrameBorders);
|
|
procedure SetFrameStyle(const AValue: TfrFrameStyle);
|
|
procedure SetFrameWidth(const AValue: Double);
|
|
procedure SetStretched(const AValue: Boolean);
|
|
protected
|
|
SaveX, SaveY, SaveDX, SaveDY: Integer;
|
|
SaveFW: Double;
|
|
|
|
gapx, gapy: Integer;
|
|
Memo1: TStringList;
|
|
FDataSet: TfrTDataSet;
|
|
FField: String;
|
|
olddy: Integer;
|
|
oldy: Integer;
|
|
|
|
procedure ShowBackGround; virtual;
|
|
procedure ShowFrame; virtual;
|
|
procedure BeginDraw(ACanvas: TCanvas);
|
|
procedure GetBlob(b: TfrTField); virtual;
|
|
procedure OnHook(View: TfrView); virtual;
|
|
procedure BeforeChange;
|
|
procedure AfterChange;
|
|
procedure AfterCreate;virtual;
|
|
procedure ResetLastValue; virtual;
|
|
function GetFrames: TfrFrameBorders; virtual;
|
|
procedure ModifyFlag(aFlag: Word; aValue:Boolean);
|
|
procedure MenuItemCheckFlag(Sender:TObject; aFlag: Word);
|
|
procedure SetHeight(const AValue: Double);virtual;
|
|
procedure SetLeft(const AValue: Double);virtual;
|
|
procedure SetTop(const AValue: Double);virtual;
|
|
procedure SetWidth(const AValue: Double);virtual;
|
|
function GetHeight: Double;virtual;
|
|
function GetWidth: Double;virtual;
|
|
public
|
|
Parent: TfrBand;
|
|
ID: Integer;
|
|
Typ: Byte;
|
|
Selected: Boolean;
|
|
OriginalRect: TRect;
|
|
ScaleX, ScaleY: Double; // used for scaling objects in preview
|
|
OffsX, OffsY: Integer; //
|
|
IsPrinting: Boolean;
|
|
Flags: Word;
|
|
DRect: TRect;
|
|
ParentBandType: TfrBandType; // identify parent band type on exporting view
|
|
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Assign(From: TfrView); override;
|
|
procedure CalcGaps; virtual;
|
|
procedure RestoreCoord; virtual;
|
|
procedure Draw(aCanvas: TCanvas); virtual; abstract;
|
|
procedure Print(Stream: TStream); virtual;
|
|
procedure ExportData; virtual;
|
|
procedure LoadFromStream(Stream: TStream); virtual;
|
|
procedure SaveToStream(Stream: TStream); virtual;
|
|
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); override;
|
|
|
|
procedure Resized; virtual;
|
|
procedure DefinePopupMenu(Popup: TPopupMenu); virtual;
|
|
function GetClipRgn(rt: TfrRgnType): HRGN; virtual;
|
|
procedure SetBounds(aLeft, aTop, aWidth, aHeight: Integer);
|
|
|
|
function PointInView(aX,aY : Integer) : Boolean; virtual;
|
|
procedure Invalidate;
|
|
|
|
property Canvas : TCanvas read fCanvas write fCanvas;
|
|
|
|
property FillColor : TColor read fFillColor write SetFillColor;
|
|
property Stretched : Boolean read GetStretched write SetStretched;
|
|
|
|
property Frames : TfrFrameBorders read GetFrames write SetFrames;
|
|
property FrameColor : TColor read fFrameColor write SetFrameColor;
|
|
property FrameStyle : TfrFrameStyle read fFrameStyle write SetFrameStyle;
|
|
property FrameWidth : Double read fFrameWidth write SetFrameWidth;
|
|
property Format : Integer read fFormat write SetFormat;
|
|
property FormatStr : String read fFormatStr write SetFormatStr;
|
|
|
|
property StreamMode: TfrStreamMode read fStreamMode write fStreamMode;
|
|
|
|
published
|
|
property Left: double read GetLeft write SetLeft;
|
|
property Top: double read GetTop write SetTop;
|
|
property Tag: string read FTag write FTag;
|
|
property URLInfo: string read FURLInfo write FURLInfo;
|
|
property Width: double read GetWidth write SetWidth;
|
|
property Height: double read GetHeight write SetHeight;
|
|
end;
|
|
TfrViewClass = Class of TFRView;
|
|
|
|
TfrStretcheable = class(TfrView)
|
|
protected
|
|
ActualHeight: Integer;
|
|
DrawMode: TfrDrawMode;
|
|
|
|
function CalcHeight: Integer; virtual; abstract;
|
|
function MinHeight: Integer; virtual; abstract;
|
|
function RemainHeight: Integer; virtual; abstract;
|
|
published
|
|
property Stretched;
|
|
end;
|
|
|
|
{ TfrControl }
|
|
|
|
TfrControl = class(TfrView)
|
|
protected
|
|
procedure PaintDesignControl; virtual;abstract;
|
|
public
|
|
procedure UpdateControlPosition; virtual;
|
|
procedure AttachToParent; virtual;
|
|
function OwnerForm:TWinControl; virtual;
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
procedure Draw(ACanvas: TCanvas); override;
|
|
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
|
published
|
|
//property Restrictions;
|
|
end;
|
|
|
|
{ TfrNonVisualControl }
|
|
|
|
TfrNonVisualControl = class(TfrControl)
|
|
protected
|
|
ControlImage: TCustomBitmap;
|
|
procedure PaintDesignControl; override;
|
|
public
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
procedure Draw(ACanvas: TCanvas); override;
|
|
end;
|
|
|
|
|
|
{ TfrMemoView }
|
|
|
|
TfrMemoView = class(TfrStretcheable)
|
|
private
|
|
fFont : TFont;
|
|
fLastValue : TStringList;
|
|
|
|
function GetAlignment: TAlignment;
|
|
function GetAngle: Byte;
|
|
function GetAutoSize: Boolean;
|
|
function GetHideDuplicates: Boolean;
|
|
function GetHideZeroValues: Boolean;
|
|
function GetIsLastValueSet: boolean;
|
|
function GetJustify: boolean;
|
|
function GetLayout: TTextLayout;
|
|
function GetWordBreak: Boolean;
|
|
function GetWordWrap: Boolean;
|
|
procedure P1Click(Sender: TObject);
|
|
procedure P2Click(Sender: TObject);
|
|
procedure P3Click(Sender: TObject);
|
|
procedure P4Click(Sender: TObject);
|
|
procedure P5Click(Sender: TObject);
|
|
procedure P6Click(Sender: TObject);
|
|
procedure SetAlignment(const AValue: TAlignment);
|
|
procedure SetAngle(const AValue: Byte);
|
|
procedure SetAutoSize(const AValue: Boolean);
|
|
procedure SetFont(Value: TFont);
|
|
procedure SetHideDuplicates(const AValue: Boolean);
|
|
procedure SetHideZeroValues(AValue: Boolean);
|
|
procedure SetIsLastValueSet(const AValue: boolean);
|
|
procedure SetJustify(AValue: boolean);
|
|
procedure SetLayout(const AValue: TTextLayout);
|
|
procedure SetWordBreak(AValue: Boolean);
|
|
procedure SetWordWrap(const AValue: Boolean);
|
|
protected
|
|
Streaming: Boolean;
|
|
TextHeight: Integer;
|
|
CurStrNo: Integer;
|
|
Exporting: Boolean;
|
|
|
|
procedure ExpandVariables;
|
|
procedure AssignFont(aCanvas: TCanvas);
|
|
procedure WrapMemo;
|
|
procedure ShowMemo;
|
|
function CalcWidth(aMemo: TStringList): Integer;
|
|
function CalcHeight: Integer; override;
|
|
function MinHeight: Integer; override;
|
|
function RemainHeight: Integer; override;
|
|
procedure GetBlob(b: TfrTField); override;
|
|
procedure FontChange({%H-}sender: TObject);
|
|
procedure ResetLastValue; override;
|
|
|
|
property IsLastValueSet: boolean read GetIsLastValueSet write SetIsLastValueSet;
|
|
public
|
|
Adjust: Integer; // bit format xxxLLRAA: LL=Layout, R=Rotated, AA=Alignment
|
|
Highlight: TfrHighlightAttr;
|
|
HighlightStr: String;
|
|
LineSpacing, CharacterSpacing: Integer;
|
|
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Assign(From: TfrView); override;
|
|
procedure Draw(aCanvas: TCanvas); override;
|
|
procedure Print(Stream: TStream); override;
|
|
procedure ExportData; override;
|
|
procedure LoadFromStream(Stream: TStream); override;
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SaveToStream(Stream: TStream); override;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
|
|
|
procedure MonitorFontChanges;
|
|
property Justify: boolean read GetJustify write SetJustify;
|
|
|
|
published
|
|
property Font : TFont read fFont write SetFont;
|
|
property Alignment : TAlignment read GetAlignment write SetAlignment;
|
|
property Layout : TTextLayout read GetLayout write SetLayout;
|
|
property Angle : Byte read GetAngle write SetAngle;
|
|
property WordBreak : Boolean read GetWordBreak write SetWordBreak;
|
|
property WordWrap : Boolean read GetWordWrap write SetWordWrap;
|
|
property AutoSize : Boolean read GetAutoSize write SetAutoSize;
|
|
property HideDuplicates: Boolean read GetHideDuplicates write SetHideDuplicates;
|
|
property HideZeroValues : Boolean read GetHideZeroValues write SetHideZeroValues;
|
|
|
|
property FillColor;
|
|
property Memo;
|
|
property Script;
|
|
property Frames;
|
|
property FrameColor;
|
|
property FrameStyle;
|
|
property FrameWidth;
|
|
property Format;
|
|
property FormatStr;
|
|
end;
|
|
|
|
{ TfrBandView }
|
|
|
|
TfrBandView = class(TfrView)
|
|
private
|
|
fDataSetStr : String;
|
|
fBandType : TfrBandType;
|
|
fCondition : String;
|
|
|
|
procedure P1Click(Sender: TObject);
|
|
procedure P2Click(Sender: TObject);
|
|
procedure P3Click(Sender: TObject);
|
|
procedure P4Click(Sender: TObject);
|
|
procedure P5Click(Sender: TObject);
|
|
procedure P6Click(Sender: TObject);
|
|
function GetTitleRect: TRect;
|
|
function TitleSize: Integer;
|
|
procedure CalcTitleSize;
|
|
public
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
|
|
procedure Assign(From: TfrView); override;
|
|
|
|
procedure LoadFromStream(Stream: TStream); override;
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SaveToStream(Stream: TStream); override;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); override;
|
|
|
|
|
|
procedure Draw(aCanvas: TCanvas); override;
|
|
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
|
function GetClipRgn(rt: TfrRgnType): HRGN; override;
|
|
|
|
function PointInView(aX,aY : Integer) : Boolean; override;
|
|
|
|
|
|
published
|
|
property DataSet: String read fDataSetStr write fDataSetStr;
|
|
property GroupCondition: String read fCondition write fCondition;
|
|
|
|
property BandType: TfrBandType read fBandType write fBandType;
|
|
|
|
property Script;
|
|
property Stretched;
|
|
end;
|
|
|
|
{ TfrSubReportView }
|
|
|
|
TfrSubReportView = class(TfrView)
|
|
public
|
|
SubPage: Integer;
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
procedure Assign(From: TfrView); override;
|
|
procedure Draw(aCanvas: TCanvas); override;
|
|
procedure LoadFromStream(Stream: TStream); override;
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SaveToStream(Stream: TStream); override;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure DefinePopupMenu({%H-}Popup: TPopupMenu); override;
|
|
end;
|
|
|
|
{ TfrPictureView }
|
|
|
|
TfrPictureView = class(TfrView)
|
|
private
|
|
fPicture: TPicture;
|
|
FSharedName: string;
|
|
|
|
function GetCentered: boolean;
|
|
function GetKeepAspect: boolean;
|
|
procedure P1Click(Sender: TObject);
|
|
procedure P2Click(Sender: TObject);
|
|
function GetPictureType: byte;
|
|
function PictureTypeToGraphic(b: Byte): TGraphic;
|
|
function ExtensionToGraphic(const Ext: string): TGraphic;
|
|
procedure SetCentered(AValue: boolean);
|
|
procedure SetKeepAspect(AValue: boolean);
|
|
function StreamToGraphic(M: TMemoryStream): TGraphic;
|
|
procedure SetPicture(const AValue: TPicture);
|
|
protected
|
|
procedure GetBlob(b: TfrTField); override;
|
|
public
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure Assign(From: TfrView); override;
|
|
procedure Draw(aCanvas: TCanvas); override;
|
|
procedure LoadFromStream(Stream: TStream); override;
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SaveToStream(Stream: TStream); override;
|
|
procedure SaveToXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure DefinePopupMenu(Popup: TPopupMenu); override;
|
|
published
|
|
property Picture : TPicture read fPicture write SetPicture;
|
|
|
|
property KeepAspect:boolean read GetKeepAspect write SetKeepAspect;
|
|
property Centered: boolean read GetCentered write SetCentered;
|
|
property Memo;
|
|
property Script;
|
|
property Frames;
|
|
property FrameColor;
|
|
property FrameStyle;
|
|
property FrameWidth;
|
|
property Stretched;
|
|
property SharedName: string read FSharedName write FSharedName;
|
|
property FillColor : TColor read fFillColor write SetFillColor;
|
|
end;
|
|
|
|
{ TfrLineView }
|
|
|
|
TfrLineView = class(TfrView)
|
|
protected
|
|
function GetFrames: TfrFrameBorders; override;
|
|
public
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
|
|
procedure Draw(aCanvas: TCanvas); override;
|
|
function GetClipRgn(rt: TfrRgnType): HRGN; override;
|
|
function PointInView(aX,aY: Integer): Boolean; override;
|
|
|
|
published
|
|
property FrameColor;
|
|
property FrameStyle;
|
|
property FrameWidth;
|
|
property Stretched;
|
|
end;
|
|
|
|
TfrRect = Class(TPersistent)
|
|
private
|
|
fBottom: Integer;
|
|
fLeft: Integer;
|
|
fRight: Integer;
|
|
fTop: Integer;
|
|
function GetRect: TRect;
|
|
procedure SetRect(const AValue: TRect);
|
|
public
|
|
property AsRect : TRect read GetRect write SetRect;
|
|
|
|
published
|
|
property Left : Integer read fLeft write fLeft;
|
|
property Top : Integer read fTop write fTop;
|
|
property Right: Integer read fRight write fRight;
|
|
property Bottom : Integer read fBottom write fBottom;
|
|
end;
|
|
|
|
TfrBand = class(TfrObject)
|
|
private
|
|
Parent: TfrPage;
|
|
View: TfrView;
|
|
Flags: Word;
|
|
Next, Prev: TfrBand;
|
|
SubIndex, MaxY: Integer;
|
|
EOFReached: Boolean;
|
|
EOFArr: Array[0..31] of Boolean;
|
|
Positions: Array[TfrDatasetPosition] of Integer;
|
|
LastGroupValue: Variant;
|
|
HeaderBand, FooterBand, LastBand: TfrBand;
|
|
Values: TStringList;
|
|
Count: Integer;
|
|
DisableInit: Boolean;
|
|
CalculatedHeight: Integer;
|
|
|
|
procedure InitDataSet(const Desc: String);
|
|
procedure DoError(const AErrorMsg: String);
|
|
function CalcHeight: Integer;
|
|
procedure StretchObjects(MaxHeight: Integer);
|
|
procedure UnStretchObjects;
|
|
procedure DrawObject(t: TfrView);
|
|
procedure PrepareSubReports;
|
|
procedure DoSubReports;
|
|
function DrawObjects: Boolean;
|
|
procedure DrawCrossCell(Parnt: TfrBand; CurX: Integer);
|
|
procedure DrawCross;
|
|
function CheckPageBreak(ay, ady: Integer; PBreak: Boolean): Boolean;
|
|
function CheckNextColumn: boolean;
|
|
procedure DrawPageBreak;
|
|
function HasCross: Boolean;
|
|
function DoCalcHeight: Integer;
|
|
procedure DoDraw;
|
|
function Draw: Boolean;
|
|
procedure InitValues;
|
|
procedure DoAggregate;
|
|
procedure ResetLastValues;
|
|
function getName: string;
|
|
public
|
|
maxdy: Integer;
|
|
|
|
Typ: TfrBandType;
|
|
PrintIfSubsetEmpty, NewPageAfter, Stretched, PageBreak: Boolean;
|
|
Objects: TFpList;
|
|
DataSet: TfrDataSet;
|
|
IsVirtualDS: Boolean;
|
|
VCDataSet: TfrDataSet;
|
|
IsVirtualVCDS: Boolean;
|
|
GroupCondition: String;
|
|
ForceNewPage, ForceNewColumn: Boolean;
|
|
|
|
constructor Create(ATyp: TfrBandType; AParent: TfrPage); overload;
|
|
destructor Destroy; override;
|
|
function IsDataBand: boolean;
|
|
property Name: string read getName;
|
|
end;
|
|
|
|
TfrValue = class
|
|
public
|
|
Typ : TfrValueType;
|
|
OtherKind : Integer; // for vtOther - typ, for vtDBField - format
|
|
DataSet : String; // for vtDBField
|
|
Field : String; // here is an expression for vtOther
|
|
DSet : TfrTDataSet;
|
|
end;
|
|
|
|
{ TfrValues }
|
|
|
|
TfrValues = class(TPersistent)
|
|
private
|
|
FItems: TStringList;
|
|
function GetValue(Index: Integer): TfrValue;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
|
|
function AddValue: Integer;
|
|
function FindVariable(const s: String): TfrValue;
|
|
procedure ReadBinaryData(Stream: TStream);
|
|
procedure ReadBinaryDataFromXML(XML: TLrXMLConfig; const Path: String);
|
|
procedure WriteBinaryData(Stream: TStream);
|
|
procedure WriteBinaryDataToXML(XML: TLrXMLConfig; const Path: String);
|
|
procedure Clear;
|
|
|
|
property Items: TStringList read FItems write FItems;
|
|
property Objects[Index: Integer]: TfrValue read GetValue;
|
|
end;
|
|
|
|
{ TfrPage }
|
|
|
|
TfrPage = class(TfrObject)
|
|
private
|
|
Bands : Array[TfrBandType] of TfrBand;
|
|
fColCount : Integer;
|
|
fColGap : Integer;
|
|
fColWidth : Integer;
|
|
fLastBandType : TfrBandType;
|
|
fLastRowHeight : Integer;
|
|
fMargins : TfrRect;
|
|
fOrientation : TPrinterOrientation;
|
|
fPrintToPrevPage : Boolean;
|
|
fRowStarted : boolean;
|
|
fUseMargins : Boolean;
|
|
Skip : Boolean;
|
|
InitFlag : Boolean;
|
|
CurColumn : Integer;
|
|
LastStaticColumnY : Integer;
|
|
XAdjust : Integer;
|
|
List : TFpList;
|
|
Mode : TfrPageMode;
|
|
PlayFrom : Integer;
|
|
LastBand : TfrBand;
|
|
ColPos : Integer;
|
|
CurPos : Integer;
|
|
PageType : TfrPageType; //todo: - remove this
|
|
fLayoutOrder : TLayoutOrder;
|
|
procedure DoAggregate(a: Array of TfrBandType);
|
|
procedure AddRecord(b: TfrBand; rt: TfrBandRecType);
|
|
procedure ClearRecList;
|
|
function PlayRecList: Boolean;
|
|
procedure DrawPageFooters;
|
|
function BandExists(b: TfrBand): Boolean;
|
|
procedure LoadFromStream(Stream: TStream);
|
|
procedure SaveToStream(Stream: TStream);
|
|
|
|
procedure ShowBand(b: TfrBand);
|
|
protected
|
|
procedure InitReport; virtual;
|
|
procedure DoneReport; virtual;
|
|
procedure TossObjects; virtual;
|
|
procedure PrepareObjects; virtual;
|
|
procedure FormPage; virtual;
|
|
procedure AfterPrint; virtual;
|
|
procedure AfterLoad;override;
|
|
public
|
|
pgSize : Integer;
|
|
PrnInfo : TfrPrnInfo;
|
|
Objects : TFpList;
|
|
RTObjects : TFpList;
|
|
CurY : Integer;
|
|
CurBottomY: Integer;
|
|
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
|
|
constructor Create(ASize, AWidth, AHeight: Integer; AOr: TPrinterOrientation);
|
|
constructor CreatePage; virtual;
|
|
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SavetoXML(XML: TLrXMLConfig; const Path: String); override;
|
|
|
|
function TopMargin: Integer;
|
|
function BottomMargin: Integer;
|
|
function LeftMargin: Integer;
|
|
function RightMargin: Integer;
|
|
procedure Clear;
|
|
procedure Delete(Index: Integer);
|
|
function FindObjectByID(ID: Integer): Integer;
|
|
function FindObject(aName: String): TfrObject;
|
|
function FindRTObject(const aName: String): TfrObject;
|
|
procedure ChangePaper(ASize, AWidth, AHeight: Integer; AOr: TPrinterOrientation);
|
|
procedure ShowBandByName(const s: String);
|
|
procedure ShowBandByType(bt: TfrBandType);
|
|
procedure NewPage;
|
|
procedure NewColumn(Band: TfrBand);
|
|
procedure NextColumn({%H-}Band: TFrBand);
|
|
function RowsLayout: boolean;
|
|
procedure StartColumn;
|
|
procedure StartRowsLayoutNonDataBand(Band: TfrBand);
|
|
function AdvanceRow(Band: TfrBand): boolean;
|
|
|
|
property ColCount : Integer read fColCount write fColCount;
|
|
property ColWidth : Integer read fColWidth write fColWidth;
|
|
property ColGap : Integer read fColGap write fColGap;
|
|
property UseMargins : Boolean read fUseMargins write fUseMargins;
|
|
property Margins : TfrRect read fMargins write fMargins;
|
|
property PrintToPrevPage : Boolean read fPrintToPrevPage write fPrintToPrevPage;
|
|
property Orientation : TPrinterOrientation read fOrientation write fOrientation;
|
|
property LayoutOrder: TLayoutOrder read fLayoutOrder write fLayoutOrder;
|
|
property LastRowHeight: Integer read fLastRowHeight write fLastRowHeight;
|
|
property RowStarted: boolean read fRowStarted write fRowStarted;
|
|
property LastBandType: TfrBandType read fLastBandType write fLastbandType;
|
|
|
|
published
|
|
property Script;
|
|
property Height;
|
|
property Width;
|
|
end;
|
|
|
|
TFrPageClass = Class of TfrPage;
|
|
|
|
{ TfrPageReport }
|
|
|
|
TfrPageReport = Class(TfrPage)
|
|
public
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SavetoXML(XML: TLrXMLConfig; const Path: String); override;
|
|
|
|
constructor CreatePage; override;
|
|
published
|
|
property ColCount;
|
|
property ColWidth;
|
|
property ColGap;
|
|
property UseMargins;
|
|
property Margins;
|
|
property PrintToPrevPage;
|
|
property Orientation;
|
|
property LayoutOrder;
|
|
end;
|
|
|
|
{ TfrPageDialog }
|
|
|
|
TfrPageDialog = Class(TfrPage)
|
|
private
|
|
fHasVisibleControls : Boolean;
|
|
FForm : TfrDialogForm;
|
|
procedure EditFormDestroy(Sender: TObject);
|
|
function GetCaption: string;
|
|
procedure SetCaption(AValue: string);
|
|
procedure UpdateControlPosition;
|
|
protected
|
|
procedure SetName(const AValue: string); override;
|
|
procedure PrepareObjects; override;
|
|
procedure InitReport; override;
|
|
procedure SetLeft(AValue: Integer);override;
|
|
procedure SetTop(AValue: Integer);override;
|
|
procedure SetWidth(AValue: Integer);override;
|
|
procedure SetHeight(AValue: Integer);override;
|
|
procedure ExecScript;
|
|
public
|
|
constructor Create(AOwnerPage:TfrPage); override;
|
|
destructor Destroy; override;
|
|
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String); override;
|
|
procedure SavetoXML(XML: TLrXMLConfig; const Path: String); override;
|
|
property Form:TfrDialogForm read FForm;
|
|
published
|
|
property Caption : string read GetCaption write SetCaption;
|
|
property Left;
|
|
property Top;
|
|
end;
|
|
|
|
{ TfrPages }
|
|
|
|
TfrPages = class(TObject)
|
|
private
|
|
FPages: TFpList;
|
|
Parent: TfrReport;
|
|
|
|
function GetCount: Integer;
|
|
function GetPages(Index: Integer): TfrPage;
|
|
procedure AfterLoad;
|
|
public
|
|
constructor Create(AParent: TfrReport);
|
|
destructor Destroy; override;
|
|
|
|
procedure Clear;
|
|
procedure Add(const aClassName : string='TfrPageReport');
|
|
procedure Delete(Index: Integer);
|
|
procedure LoadFromStream(Stream: TStream);
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
procedure SaveToStream(Stream: TStream);
|
|
procedure SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
function PageByName(APageName:string):TfrPage;
|
|
|
|
property Pages[Index: Integer]: TfrPage read GetPages; default;
|
|
property Count: Integer read GetCount;
|
|
end;
|
|
|
|
{ TfrEMFPages }
|
|
|
|
TfrEMFPages = class(TObject)
|
|
private
|
|
FPages: TFpList;
|
|
Parent: TfrReport;
|
|
function GetCount: Integer;
|
|
function GetPages(Index: Integer): PfrPageInfo;
|
|
procedure ExportData(Index: Integer);
|
|
procedure PageToObjects(Index: Integer);
|
|
public
|
|
constructor Create(AParent: TfrReport);
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
procedure ObjectsToPage(Index: Integer);
|
|
procedure Draw(Index: Integer; Canvas: TCanvas; DrawRect: TRect);
|
|
procedure Add(APage: TfrPage);
|
|
procedure Insert(Index: Integer; APage: TfrPage);
|
|
procedure Delete(Index: Integer);
|
|
|
|
function DoMouseClick(Index: Integer; pt: TPoint; var AInfo: String): Boolean;
|
|
function DoMouseMove(Index: Integer; pt: TPoint; var Cursor: TCursor; var AInfo: String): Boolean;
|
|
|
|
procedure LoadFromStream(AStream: TStream);
|
|
procedure AddPagesFromStream(AStream: TStream; AReadHeader: boolean=true);
|
|
procedure LoadFromXML({%H-}XML: TLrXMLConfig; const {%H-}Path: String);
|
|
procedure SaveToStream(AStream: TStream);
|
|
procedure SavePageToStream(PageNo:Integer; AStream: TStream);
|
|
procedure SaveToXML({%H-}XML: TLrXMLConfig; const {%H-}Path: String);
|
|
property Pages[Index: Integer]: PfrPageInfo read GetPages; default;
|
|
property Count: Integer read GetCount;
|
|
end;
|
|
|
|
{ TfrExportFilter }
|
|
|
|
TExportFilterSetup = procedure(Sender: TfrExportFilter) of object;
|
|
|
|
TfrExportFilter = class(TObject)
|
|
private
|
|
FOnSetup: TExportFilterSetup;
|
|
FBandTypes: TfrBandTypes;
|
|
FUseProgressBar: boolean;
|
|
FLineIndex: Integer;
|
|
protected
|
|
Stream: TStream;
|
|
Lines: TFpList;
|
|
procedure ClearLines;
|
|
procedure Setup; virtual;
|
|
function AddData({%H-}x, {%H-}y: Integer; view: TfrView): pointer; virtual;
|
|
procedure NewRec(View: TfrView; const AText:string; var P:Pointer); virtual;
|
|
procedure AddRec(ALineIndex: Integer; ARec: Pointer); virtual;
|
|
function GetviewText(View:TfrView): string; virtual;
|
|
function CheckView({%H-}View:TfrView): boolean; virtual;
|
|
public
|
|
constructor Create(AStream: TStream); virtual;
|
|
destructor Destroy; override;
|
|
procedure OnBeginDoc; virtual;
|
|
procedure OnEndDoc; virtual;
|
|
procedure OnBeginPage; virtual;
|
|
procedure OnEndPage; virtual;
|
|
procedure OnData({%H-}x, {%H-}y: Integer; {%H-}View: TfrView); virtual;
|
|
procedure OnText({%H-}x, {%H-}y: Integer; const {%H-}text: String; {%H-}View: TfrView); virtual;
|
|
procedure OnExported({%H-}x, {%H-}y: Integer; {%H-}View: TfrView); virtual;
|
|
|
|
property BandTypes: TfrBandTypes read FBandTypes write FBandTypes;
|
|
property UseProgressbar: boolean read FUseProgressBar write FUseProgressBar;
|
|
property OnSetup: TExportFilterSetup read FOnSetup write FOnSetup;
|
|
end;
|
|
|
|
TfrExportFilterClass = class of TfrExportFilter;
|
|
|
|
TfrDataType = (dtDataSet,dtDataSource);
|
|
|
|
{ TfrReport }
|
|
|
|
TfrReport = class(TComponent)
|
|
private
|
|
FDataType: TfrDataType;
|
|
FDefaultCollate: boolean;
|
|
FOnDBImageRead: TOnDBImageRead;
|
|
FDefaultCopies: Integer;
|
|
FMouseOverObject: TMouseOverObjectEvent;
|
|
FObjectClick: TObjectClickEvent;
|
|
FOnExportFilterSetup: TExportFilterSetup;
|
|
FPages: TfrPages;
|
|
FEMFPages: TfrEMFPages;
|
|
FReportAutor: string;
|
|
FReportCreateDate: TDateTime;
|
|
FReportLastChange: TDateTime;
|
|
FReportOptions: TfrReportOptions;
|
|
FReportVersionBuild: string;
|
|
FReportVersionMajor: string;
|
|
FReportVersionMinor: string;
|
|
FReportVersionRelease: string;
|
|
FScript: TfrScriptStrings;
|
|
FVars: TStrings;
|
|
FVal: TfrValues;
|
|
FDataset: TfrDataset;
|
|
FGrayedButtons: Boolean;
|
|
FReportType: TfrReportType;
|
|
FShowProgress: Boolean;
|
|
FModalPreview: Boolean;
|
|
FModifyPrepared: Boolean;
|
|
FStoreInDFM: Boolean;
|
|
FStoreInForm: Boolean;
|
|
FPreview: TfrPreview;
|
|
FPreviewButtons: TfrPreviewButtons;
|
|
FInitialZoom: TfrPreviewZoom;
|
|
FOnBeginDoc: TBeginDocEvent;
|
|
FOnEndDoc: TEndDocEvent;
|
|
FOnBeginPage: TBeginPageEvent;
|
|
FOnEndPage: TEndPageEvent;
|
|
FOnBeginBand: TBeginBandEvent;
|
|
FOnEndBand: TEndBandEvent;
|
|
FOnGetValue: TDetailEvent;
|
|
FOnEnterRect: TEnterRectEvent;
|
|
FOnProgress: TfrProgressEvent;
|
|
FOnFunction: TFunctionEvent;
|
|
FOnBeginColumn: TBeginColumnEvent;
|
|
FOnPrintColumn: TPrintColumnEvent;
|
|
FOnManualBuild: TManualBuildEvent;
|
|
FCurrentFilter: TfrExportFilter;
|
|
FPageNumbers : String;
|
|
FCopies : Integer;
|
|
FCurPage : TfrPage;
|
|
|
|
// FDefaultTitle : String;
|
|
FTitle : String;
|
|
FSubject : string;
|
|
FKeyWords : string;
|
|
FComments : TStringList;
|
|
FDFMStream : TStream;
|
|
FXMLReport : string;
|
|
fDefExportFilterClass: string;
|
|
fDefExportFileName: string;
|
|
|
|
function FormatValue(V: Variant; AFormat: Integer; const AFormatStr: String): String;
|
|
// function GetLRTitle: String;
|
|
|
|
procedure OnGetParsFunction(const aName: String; p1, p2, p3: Variant;
|
|
var val: Variant);
|
|
function DoInterpFunction(const aName: String; p1, p2, p3: Variant;
|
|
var val: Variant):boolean;
|
|
procedure PrepareDataSets;
|
|
procedure BuildBeforeModal(Sender: TObject);
|
|
procedure ExportBeforeModal(Sender: TObject);
|
|
procedure PrintBeforeModal(Sender: TObject);
|
|
function DoPrepareReport: Boolean;
|
|
procedure DoBuildReport; virtual;
|
|
procedure DoPrintReport(const PageNumbers: String; Copies: Integer);
|
|
procedure SetComments(const AValue: TStringList);
|
|
procedure SetPrinterTo(const PrnName: String);
|
|
procedure SetScript(AValue: TfrScriptStrings);
|
|
procedure SetVars(Value: TStrings);
|
|
procedure ClearAttribs;
|
|
function FindObjectByName(AName:string):TfrObject;
|
|
procedure ExecScript;
|
|
protected
|
|
procedure DoBeginBand(Band: TfrBand); virtual;
|
|
procedure DoBeginColumn(Band: TfrBand); virtual;
|
|
procedure DoBeginDoc; virtual;
|
|
procedure DoBeginPage(pgNo: Integer); virtual;
|
|
procedure DoEndBand(Band: TfrBand); virtual;
|
|
procedure DoEndDoc; virtual;
|
|
procedure DoEndPage(pgNo: Integer); virtual;
|
|
procedure DoEnterRect(Memo: TStringList; View: TfrView); virtual;
|
|
procedure DoGetValue(const ParName: String; var ParValue: Variant); virtual;
|
|
procedure DoPrintColumn(ColNo: Integer; var Width: Integer); virtual;
|
|
procedure DoUserFunction(const AName: String; p1, p2, p3: Variant; var Val: Variant); virtual;
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
procedure ReadBinaryData(Stream: TStream);
|
|
procedure ReadStoreInDFM(Reader: TReader);
|
|
procedure ReadReportXML(Reader: TReader);
|
|
procedure WriteReportXML(Writer: TWriter);
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure Loaded; override;
|
|
public
|
|
CanRebuild : Boolean; // true, if report can be rebuilded
|
|
Terminated : Boolean;
|
|
PrintToDefault, DoublePass: WordBool;
|
|
FinalPass : Boolean;
|
|
FileName : String;
|
|
ExportFilename : string; // filename used when exporting a report
|
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Clear;
|
|
// service methods
|
|
function FindVariable(Variable: String): Integer;
|
|
procedure GetVariableValue(const s: String; var aValue: Variant);
|
|
procedure GetVarList(CatNo: Integer; List: TStrings);
|
|
procedure GetIntrpValue(AName: String; var AValue: Variant);
|
|
procedure GetCategoryList(List: TStrings);
|
|
function FindObject(const aName: String): TfrObject;
|
|
// internal events used through report building
|
|
procedure InternalOnEnterRect(Memo: TStringList; View: TfrView);
|
|
procedure InternalOnExportData(View: TfrView);
|
|
procedure InternalOnExportText(x, y: Integer; const text: String; View: TfrView);
|
|
procedure InternalOnExported(View: TfrView);
|
|
procedure InternalOnGetValue(ParName: String; var ParValue: String);
|
|
procedure InternalOnProgress(Percent: Integer);
|
|
procedure FillQueryParams;
|
|
// load/save methods
|
|
procedure LoadFromStream(Stream: TStream);
|
|
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
procedure SaveToStream(Stream: TStream);
|
|
procedure LoadFromFile(const FName: String);
|
|
procedure LoadFromXMLFile(const Fname: String);
|
|
procedure LoadFromXMLStream(const Stream: TStream);
|
|
procedure SaveToFile(FName: String);
|
|
procedure SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
procedure SaveToXMLFile(const FName: String);
|
|
procedure SaveToXMLStream(const Stream: TStream);
|
|
|
|
procedure LoadFromDB(Table: TDataSet; DocN: Integer);
|
|
procedure SaveToDB(Table: TDataSet; DocN: Integer);
|
|
|
|
procedure LoadTemplate(const fname: String; comm: TStrings;
|
|
Bmp: TBitmap; Load: Boolean);
|
|
procedure LoadTemplateXML(const fname: String; comm: TStrings;
|
|
Bmp: TBitmap; Load: Boolean);
|
|
procedure SaveTemplate(const fname: String; comm: TStrings; Bmp: TBitmap);
|
|
procedure SaveTemplateXML(const fname: String; Desc: TStrings; Bmp: TBitmap);
|
|
procedure LoadPreparedReport(const FName: String);
|
|
procedure SavePreparedReport(const FName: String);
|
|
// report manipulation methods
|
|
function DesignReport: Integer;
|
|
function PrepareReport: Boolean;
|
|
procedure ExportTo(FilterClass: TfrExportFilterClass; aFileName: String);
|
|
procedure ShowReport;
|
|
procedure ShowPreparedReport;
|
|
procedure PrintPreparedReport(const PageNumbers: String; Copies: Integer);
|
|
function ChangePrinter(OldIndex, NewIndex: Integer): Boolean;
|
|
procedure EditPreparedReport(PageIndex: Integer);
|
|
//
|
|
property Subject : string read FSubject write FSubject;
|
|
property KeyWords : string read FKeyWords write FKeyWords;
|
|
property Comments : TStringList read FComments write SetComments;
|
|
property ReportAutor : string read FReportAutor write FReportAutor;
|
|
property ReportVersionMajor : string read FReportVersionMajor write FReportVersionMajor;
|
|
property ReportVersionMinor : string read FReportVersionMinor write FReportVersionMinor;
|
|
property ReportVersionRelease : string read FReportVersionRelease write FReportVersionRelease;
|
|
property ReportVersionBuild : string read FReportVersionBuild write FReportVersionBuild;
|
|
property ReportCreateDate : TDateTime read FReportCreateDate write FReportCreateDate;
|
|
property ReportLastChange : TDateTime read FReportLastChange write FReportLastChange;
|
|
//
|
|
property Pages: TfrPages read FPages;
|
|
property EMFPages: TfrEMFPages read FEMFPages write FEMFPages;
|
|
property Variables: TStrings read FVars write SetVars;
|
|
property Values: TfrValues read FVal write FVal;
|
|
property Script : TfrScriptStrings read FScript write SetScript;
|
|
//
|
|
property DefExportFilterClass: string read fDefExportFilterClass write fDefExportFilterClass;
|
|
property DefExportFileName: string read fDefExportFileName write fDefExportFileName;
|
|
|
|
property DefaultCollate : boolean read FDefaultCollate write FDefaultCollate;
|
|
|
|
published
|
|
property Dataset: TfrDataset read FDataset write FDataset;
|
|
property DefaultCopies: Integer read FDefaultCopies write FDefaultCopies default 1;
|
|
property GrayedButtons: Boolean read FGrayedButtons write FGrayedButtons default False;
|
|
property InitialZoom: TfrPreviewZoom read FInitialZoom write FInitialZoom;
|
|
property ModalPreview: Boolean read FModalPreview write FModalPreview default True;
|
|
property ModifyPrepared: Boolean read FModifyPrepared write FModifyPrepared default True;
|
|
property Options: TfrReportOptions read FReportOptions write FReportOptions;
|
|
property Preview: TfrPreview read FPreview write FPreview;
|
|
property PreviewButtons: TfrPreviewButtons read FPreviewButtons write FPreviewButtons;
|
|
property ReportType: TfrReportType read FReportType write FReportType default rtSimple;
|
|
property ShowProgress: Boolean read FShowProgress write FShowProgress default True;
|
|
property StoreInForm: Boolean read FStoreInForm write FStoreInForm default False;
|
|
property DataType : TfrDataType read FDataType write FDataType;
|
|
|
|
property Title: String read FTitle write FTitle;
|
|
|
|
property OnBeginDoc: TBeginDocEvent read FOnBeginDoc write FOnBeginDoc;
|
|
property OnEndDoc: TEndDocEvent read FOnEndDoc write FOnEndDoc;
|
|
property OnBeginPage: TBeginPageEvent read FOnBeginPage write FOnBeginPage;
|
|
property OnEndPage: TEndPageEvent read FOnEndPage write FOnEndPage;
|
|
property OnBeginBand: TBeginBandEvent read FOnBeginBand write FOnBeginBand;
|
|
property OnEndBand: TEndBandEvent read FOnEndBand write FOnEndBand;
|
|
property OnGetValue: TDetailEvent read FOnGetValue write FOnGetValue;
|
|
property OnEnterRect: TEnterRectEvent read FOnEnterRect write FOnEnterRect;
|
|
property OnUserFunction: TFunctionEvent read FOnFunction write FOnFunction;
|
|
property OnProgress: TfrProgressEvent read FOnProgress write FOnProgress;
|
|
property OnBeginColumn: TBeginColumnEvent read FOnBeginColumn write FOnBeginColumn;
|
|
property OnPrintColumn: TPrintColumnEvent read FOnPrintColumn write FOnPrintColumn;
|
|
property OnManualBuild: TManualBuildEvent read FOnManualBuild write FOnManualBuild;
|
|
property OnExportFilterSetup: TExportFilterSetup read FOnExportFilterSetup write FOnExportFilterSetup;
|
|
// If wanted, you can use your own handler to determine the graphic class of the image
|
|
property OnDBImageRead: TOnDBImageRead read FOnDBImageRead write FOnDBImageRead;
|
|
property OnObjectClick: TObjectClickEvent read FObjectClick write FObjectClick;
|
|
property OnMouseOverObject: TMouseOverObjectEvent read FMouseOverObject write FMouseOverObject;
|
|
end;
|
|
|
|
TfrCompositeReport = class(TfrReport)
|
|
private
|
|
procedure DoBuildReport; override;
|
|
public
|
|
Reports: TFpList;
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TfrReportDesigner }
|
|
|
|
TfrReportDesigner = class(TForm)
|
|
private
|
|
FModified: Boolean;
|
|
protected
|
|
procedure SetModified(AValue: Boolean);virtual;
|
|
public
|
|
Page: TfrPage;
|
|
PreparedReportEditor:boolean;
|
|
procedure {%H-}RegisterObject(ButtonBmp: TBitmap; const ButtonHint: String;
|
|
ButtonTag: Integer; ObjectType:TfrObjectType); virtual; abstract;
|
|
procedure {%H-}RegisterTool(const MenuCaption: String; ButtonBmp: TBitmap;
|
|
NotifyOnClick: TNotifyEvent); virtual; abstract;
|
|
procedure {%H-}BeforeChange; virtual; abstract;
|
|
procedure {%H-}AfterChange; virtual; abstract;
|
|
procedure {%H-}RedrawPage; virtual; abstract;
|
|
//
|
|
function {%H-}PointsToUnits(x: Integer): Double; virtual; abstract;
|
|
function {%H-}UnitsToPoints(x: Double): Integer; virtual; abstract;
|
|
property Modified: Boolean read FModified write SetModified;
|
|
end;
|
|
|
|
TfrDataManager = class(TObject)
|
|
public
|
|
procedure Clear; virtual; abstract;
|
|
procedure LoadFromStream(Stream: TStream); virtual; abstract;
|
|
procedure LoadFromXML(XML:TLrXMLConfig; const Path: String); virtual; abstract;
|
|
procedure SaveToStream(Stream: TStream); virtual; abstract;
|
|
procedure SaveToXML(XML:TLrXMLConfig; const Path: String); virtual; abstract;
|
|
procedure BeforePreparing; virtual; abstract;
|
|
procedure AfterPreparing; virtual; abstract;
|
|
procedure PrepareDataSet(ds: TfrTDataSet); virtual; abstract;
|
|
function ShowParamsDialog: Boolean; virtual; abstract;
|
|
procedure AfterParamsDialog; virtual; abstract;
|
|
end;
|
|
|
|
TfrObjEditorForm = class(TForm)
|
|
public
|
|
procedure ShowEditor({%H-}t: TfrView); virtual;
|
|
end;
|
|
|
|
TfrFunctionDescription = class(TObject)
|
|
funName:string;
|
|
funGroup:string;
|
|
funDescription:string;
|
|
end;
|
|
|
|
{ TfrFunctionLibrary }
|
|
|
|
TfrFunctionLibrary = class(TObject)
|
|
private
|
|
List, Extra: TStringList;
|
|
function GetCount: integer;
|
|
function GetDescription(AIndex: Integer): TfrFunctionDescription;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
function OnFunction(const FName: String; p1, p2, p3: Variant;
|
|
var val: Variant): Boolean;
|
|
procedure {%H-}DoFunction(FNo: Integer; p1, p2, p3: Variant; var val: Variant);
|
|
virtual; abstract;
|
|
procedure UpdateDescriptions; virtual;
|
|
procedure Add(const funName:string; IsExtra:boolean=false);
|
|
procedure AddFunctionDesc(const funName, funGroup, funDescription:string);
|
|
property FunctionCount:integer read GetCount;
|
|
property Description[AIndex:Integer]:TfrFunctionDescription read GetDescription;
|
|
end;
|
|
|
|
TfrCompressor = class(TObject)
|
|
public
|
|
Enabled: Boolean;
|
|
procedure Compress({%H-}StreamIn, {%H-}StreamOut: TStream); virtual;
|
|
procedure DeCompress({%H-}StreamIn, {%H-}StreamOut: TStream); virtual;
|
|
end;
|
|
|
|
TfrAddinInitProc = procedure;
|
|
|
|
|
|
function frCreateObject(Typ: Byte; const ClassName: String; AOwnerPage:TfrPage): TfrView;
|
|
procedure frRegisterObject(ClassRef: TFRViewClass; ButtonBmp: TBitmap;
|
|
const ButtonHint: String; EditorForm: TfrObjEditorForm; ObjectType:TfrObjectType; InitProc:TfrAddinInitProc);
|
|
procedure frRegisterObject(ClassRef: TFRViewClass; ButtonBmp: TBitmap;
|
|
const ButtonHint: String; EditorForm: TfrObjEditorForm; InitProc:TfrAddinInitProc=nil);
|
|
|
|
procedure frSetAddinEditor(ClassRef: TfrViewClass; EditorForm: TfrObjEditorForm);
|
|
procedure frSetAddinIcon(ClassRef: TfrViewClass; ButtonBmp: TBitmap);
|
|
procedure frSetAddinHint(ClassRef: TfrViewClass; ButtonHint: string);
|
|
procedure frRegisterExportFilter(ClassRef: TfrExportFilterClass;
|
|
const FilterDesc, FilterExt: String);
|
|
procedure frRegisterFunctionLibrary(ClassRef: TClass);
|
|
procedure frRegisterTool(const MenuCaption: String; ButtonBmp: TBitmap; OnClick: TNotifyEvent);
|
|
function GetDefaultDataSet: TfrTDataSet;
|
|
procedure SetBit(var w: Word; e: Boolean; m: Integer);
|
|
function frGetBandName(BandType: TfrBandType): string;
|
|
procedure frSelectHyphenDictionary(ADict: string);
|
|
|
|
const
|
|
lrTemplatePath = 'LazReportTemplate/';
|
|
frCurrentVersion = 26;
|
|
// version 2.5: lazreport: added to binary stream ParentBandType variable
|
|
// on TfrView, used to extend export facilities
|
|
// version 2.6: lazreport: added to binary stream Tag property on TfrView
|
|
|
|
frSpecCount = 9;
|
|
frSpecFuncs: Array[0..frSpecCount - 1] of String = ('PAGE#', '',
|
|
'DATE', 'TIME', 'LINE#', 'LINETHROUGH#', 'COLUMN#', 'CURRENT#', 'TOTALPAGES');
|
|
frColors: Array[0..15] of TColor =
|
|
(clWhite, clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal,
|
|
clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua);
|
|
frAllFrames=[frbLeft, frbTop, frbRight, frbBottom];
|
|
|
|
frUnwrapRead: boolean = false; // TODO: remove this for 0.9.28
|
|
|
|
type
|
|
PfrTextRec = ^TfrTextRec;
|
|
TfrTextRec = record
|
|
Next: PfrTextRec;
|
|
X: Integer;
|
|
W: Integer;
|
|
Text: string;
|
|
FontName: String[32];
|
|
FontSize, FontStyle, FontColor, FontCharset, FillColor: Integer;
|
|
Alignment: TAlignment;
|
|
Borders: TfrFrameBorders;
|
|
BorderColor: TColor;
|
|
BorderStyle: TfrFrameStyle;
|
|
BorderWidth: Integer;
|
|
Typ: Byte;
|
|
end;
|
|
|
|
TfrAddInObjectInfo = record
|
|
ClassRef: TfrViewClass;
|
|
EditorForm: TfrObjEditorForm;
|
|
ButtonBmp: TBitmap;
|
|
ButtonHint: String;
|
|
InitializeProc: TfrAddinInitProc;
|
|
ObjectType:TfrObjectType;
|
|
end;
|
|
|
|
TfrExportFilterInfo = record
|
|
ClassRef: TfrExportFilterClass;
|
|
FilterDesc, FilterExt: String;
|
|
end;
|
|
|
|
TfrFunctionInfo = record
|
|
FunctionLibrary: TfrFunctionLibrary;
|
|
end;
|
|
|
|
TfrToolsInfo = record
|
|
Caption: String;
|
|
ButtonBmp: TBitmap;
|
|
OnClick: TNotifyEvent;
|
|
end;
|
|
|
|
var
|
|
frDesigner: TfrReportDesigner; // designer reference
|
|
frDataManager: TfrDataManager; // data manager reference
|
|
frParser: TfrParser; // parser reference
|
|
frInterpretator: TfrInterpretator; // interpretator reference
|
|
frVariables: TfrVariables; // report variables reference
|
|
frCompressor: TfrCompressor; // compressor reference
|
|
CurReport: TfrReport; // currently proceeded report
|
|
MasterReport: TfrReport; // reference to main composite report
|
|
CurView: TfrView; // currently proceeded view
|
|
CurBand: TfrBand; // currently proceeded band
|
|
CurPage: TfrPage; // currently proceeded page
|
|
DocMode: (dmDesigning, dmPrinting); // current mode
|
|
DisableDrawing: Boolean;
|
|
frAddIns: Array[0..31] of TfrAddInObjectInfo; // add-in objects
|
|
frAddInsCount: Integer;
|
|
frFilters: Array[0..31] of TfrExportFilterInfo; // export filters
|
|
frFiltersCount: Integer;
|
|
frFunctions: Array[0..31] of TfrFunctionInfo; // function libraries
|
|
frFunctionsCount: Integer;
|
|
frTools: Array[0..31] of TfrToolsInfo; // tools
|
|
frToolsCount: Integer;
|
|
PageNo: Integer; // current page number in Building mode
|
|
frCharset: 0..255;
|
|
frBandNames: Array[btReportTitle..btNone] of String;
|
|
frSpecArr: Array[0..frSpecCount - 1] of String;
|
|
frDateFormats, frTimeFormats: Array[0..3] of String;
|
|
frVersion: Byte; // version of currently loaded report
|
|
SMemo: TStringList; // temporary memo used during TfrView drawing
|
|
ShowBandTitles: Boolean = True;
|
|
ProcedureInitDesigner : Procedure = nil;
|
|
|
|
(*
|
|
FRE_COMPATIBLEREAD variable added for migrating from older versions
|
|
of FreeReport and will be removed in next releases as soon as possible.
|
|
*)
|
|
{$IFDEF FREEREP2217READ}
|
|
FRE_COMPATIBLE_READ: Boolean = False;
|
|
{$ENDIF}
|
|
LRE_OLDV25_FRF_READ: Boolean = False; // read broken frf v25 reports, bug 25037
|
|
|
|
implementation
|
|
|
|
uses
|
|
strutils, LR_Fmted, LR_Prntr, LR_Progr, LR_Utils, DateUtils
|
|
{$IFDEF JPEG}, JPEG {$ENDIF}, lr_hyphen;
|
|
|
|
type
|
|
|
|
{ TfrStdFunctionLibrary }
|
|
|
|
TfrStdFunctionLibrary = class(TfrFunctionLibrary)
|
|
public
|
|
constructor Create; override;
|
|
procedure UpdateDescriptions; override;
|
|
procedure DoFunction(FNo: Integer; p1, p2, p3: Variant; var val: Variant); override;
|
|
end;
|
|
|
|
{ TInterpretator }
|
|
|
|
TInterpretator = class(TfrInterpretator)
|
|
protected
|
|
public
|
|
procedure GetValue(const Name: String; var Value: Variant); override;
|
|
procedure SetValue(const Name: String; Value: Variant); override;
|
|
procedure DoFunction(const name: String; p1, p2, p3: Variant;
|
|
var val: Variant); override;
|
|
end;
|
|
|
|
|
|
var
|
|
VHeight: Integer; // used for height calculation of TfrMemoView
|
|
SBmp: TBitmap; // small bitmap used by TfrBandView drawing
|
|
TempBmp: TBitmap; // temporary bitmap used by TfrMemoView
|
|
CurDate, CurTime: TDateTime; // date/time of report starting
|
|
CurValue: Variant; // used for highlighting
|
|
AggrBand: TfrBand = nil; // used for aggregate functions
|
|
CurVariable: String;
|
|
IsColumns: Boolean;
|
|
SavedAllPages: Integer; // number of pages in entire report
|
|
ErrorFlag: Boolean; // error occured through TfrView drawing
|
|
ErrorStr: String; // error description
|
|
SubValue: String; // used in GetValue event handler
|
|
ObjID: Integer = 0;
|
|
BoolStr: Array[0..3] of String;
|
|
HookList: TFpList;
|
|
FRInitialized: Boolean = False;
|
|
|
|
// variables used through report building
|
|
PrevY, PrevBottomY, ColumnXAdjust: Integer;
|
|
Append, WasPF: Boolean;
|
|
CompositeMode: Boolean;
|
|
MaxTitleSize: Integer = 0;
|
|
FHyp: THyphen = nil;
|
|
|
|
{-----------------------------------------------------------------------------}
|
|
const
|
|
PropCount = 6;
|
|
PropNames: Array[0..PropCount - 1] of String =
|
|
('Text','FontName', 'FontSize', 'FontStyle', 'FontColor', 'Adjust');
|
|
|
|
ColNames: Array[0..16] of String =
|
|
('clWhite', 'clBlack', 'clMaroon', 'clGreen', 'clOlive', 'clNavy',
|
|
'clPurple', 'clTeal', 'clGray', 'clSilver', 'clRed', 'clLime',
|
|
'clYellow', 'clBlue', 'clFuchsia', 'clAqua', 'clTransparent');
|
|
|
|
{$IFDEF DebugLR}
|
|
function Bandtyp2str(typ: TfrBandType): string;
|
|
begin
|
|
WriteStr(Result, typ);
|
|
end;
|
|
|
|
function BandInfo(Band: TfrBand): string;
|
|
begin
|
|
result := format('"%s":%s typ=%s',[Band.Name, dbgsname(band), BandTyp2str(Band.typ)]);
|
|
end;
|
|
|
|
function ViewInfo(View: TfrView): string;
|
|
begin
|
|
result := format('"%s":%s typ=%s',[View.Name, dbgsname(View), frTypeObjectToStr(View.Typ)]);
|
|
end;
|
|
|
|
function ViewInfoDim(View: TfrView): string;
|
|
begin
|
|
with View do
|
|
result := sysutils.format('"%s":%s typ=%s DIM:%d %d %d %d',
|
|
[Name, dbgsname(View), frTypeObjectToStr(Typ), x, y, dx, dy]);
|
|
end;
|
|
|
|
function VarStr(V:Variant): string;
|
|
begin
|
|
if VarIsNull(v) then
|
|
result := '{null}'
|
|
else
|
|
if VarIsEmpty(v) then
|
|
result := '{empty}'
|
|
else begin
|
|
if VarIsStr(v) then
|
|
result := quotedstr(v)
|
|
else
|
|
result := v;
|
|
end;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
function DoFindObjMetod(S: string; out AObjProp: string
|
|
): TfrObject;
|
|
begin
|
|
Result:=nil;
|
|
if Assigned(CurReport) and (Pos('.', S)>0) then
|
|
begin
|
|
AObjProp:=S;
|
|
Result:=CurReport.FindObject(Copy2SymbDel(AObjProp, '.'));
|
|
end;
|
|
end;
|
|
|
|
procedure UpdateLibraryDescriptions;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:=0 to frFunctionsCount-1 do
|
|
frFunctions[i].FunctionLibrary.UpdateDescriptions;
|
|
end;
|
|
|
|
procedure UpdateObjectStringResources;
|
|
begin
|
|
frCharset := StrToInt(sCharset);
|
|
|
|
frBandNames[btReportTitle] := sBand1;
|
|
frBandNames[btReportSummary] := sBand2;
|
|
frBandNames[btPageHeader] := sBand3;
|
|
frBandNames[btPageFooter] := sBand4;
|
|
frBandNames[btMasterHeader] := sBand5;
|
|
frBandNames[btMasterData] := sBand6;
|
|
frBandNames[btMasterFooter] := sBand7;
|
|
frBandNames[btDetailHeader] := sBand8;
|
|
frBandNames[btDetailData] := sBand9;
|
|
frBandNames[btDetailFooter] := sBand10;
|
|
frBandNames[btSubDetailHeader] := sBand11;
|
|
frBandNames[btSubDetailData] := sBand12;
|
|
frBandNames[btSubDetailFooter] := sBand13;
|
|
frBandNames[btOverlay] := sBand14;
|
|
frBandNames[btColumnHeader] := sBand15;
|
|
frBandNames[btColumnFooter] := sBand16;
|
|
frBandNames[btGroupHeader] := sBand17;
|
|
frBandNames[btGroupFooter] := sBand18;
|
|
frBandNames[btCrossHeader] := sBand19;
|
|
frBandNames[btCrossData] := sBand20;
|
|
frBandNames[btCrossFooter] := sBand21;
|
|
frBandNames[btNone] := sBand22;
|
|
|
|
frSpecArr[0] := sVar1;
|
|
frSpecArr[1] := sVar2;
|
|
frSpecArr[2] := sVar3;
|
|
frSpecArr[3] := sVar4;
|
|
frSpecArr[4] := sVar5;
|
|
frSpecArr[5] := sVar6;
|
|
frSpecArr[6] := sVar7;
|
|
frSpecArr[7] := sVar8;
|
|
frSpecArr[8] := sVar9;
|
|
|
|
BoolStr[0] :=SFormat51;
|
|
BoolStr[1] :=SFormat52;
|
|
BoolStr[2] :=SFormat53;
|
|
BoolStr[3] :=SFormat54;
|
|
|
|
frDateFormats[0] :=sDateFormat1;
|
|
frDateFormats[1] :=sDateFormat2;
|
|
frDateFormats[2] :=sDateFormat3;
|
|
frDateFormats[3] :=sDateFormat4;
|
|
|
|
frTimeFormats[0] :=sTimeFormat1;
|
|
frTimeFormats[1] :=sTimeFormat2;
|
|
frTimeFormats[2] :=sTimeFormat3;
|
|
frTimeFormats[3] :=sTimeFormat4;
|
|
|
|
UpdateLibraryDescriptions;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
function frCreateObject(Typ: Byte; const ClassName: String; AOwnerPage:TfrPage): TfrView;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
case Typ of
|
|
gtMemo: Result := TfrMemoView.Create(AOwnerPage);
|
|
gtPicture: Result := TfrPictureView.Create(AOwnerPage);
|
|
gtBand: Result := TfrBandView.Create(AOwnerPage);
|
|
gtSubReport: Result := TfrSubReportView.Create(AOwnerPage);
|
|
gtLine: Result := TfrLineView.Create(AOwnerPage);
|
|
gtAddIn:
|
|
begin
|
|
for i := 0 to frAddInsCount - 1 do
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('frCreateObject classname compare %s=%s',[frAddIns[i].ClassRef.ClassName,ClassName]);
|
|
{$ENDIF}
|
|
|
|
if frAddIns[i].ClassRef.ClassName = ClassName then
|
|
begin
|
|
Result := frAddIns[i].ClassRef.Create(AOwnerPage);
|
|
// Result.Create;
|
|
Result.Typ := gtAddIn;
|
|
break;
|
|
end;
|
|
end;
|
|
if Result = nil then
|
|
raise EClassNotFound.Create(Format(sClassObjectNotFound,[ClassName]));
|
|
end;
|
|
end;
|
|
|
|
if Result <> nil then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('frCreateObject instance classname=%s',[ClassName]);
|
|
{$ENDIF}
|
|
|
|
Result.ID := ObjID;
|
|
Inc(ObjID);
|
|
Result.AfterCreate;
|
|
end;
|
|
end;
|
|
|
|
procedure frRegisterObject(ClassRef: TFRViewClass; ButtonBmp: TBitmap;
|
|
const ButtonHint: String; EditorForm: TfrObjEditorForm;
|
|
ObjectType: TfrObjectType; InitProc: TfrAddinInitProc);
|
|
begin
|
|
frAddIns[frAddInsCount].ClassRef := ClassRef;
|
|
frAddIns[frAddInsCount].EditorForm := EditorForm;
|
|
frAddIns[frAddInsCount].ButtonBmp := ButtonBmp;
|
|
frAddIns[frAddInsCount].ButtonHint := ButtonHint;
|
|
frAddIns[frAddInsCount].InitializeProc := InitProc;
|
|
frAddIns[frAddInsCount].ObjectType:=ObjectType;
|
|
if frDesigner <> nil then begin
|
|
if Assigned(InitProc) then
|
|
InitProc;
|
|
frDesigner.RegisterObject(ButtonBmp, ButtonHint,
|
|
Integer(gtAddIn) + frAddInsCount, ObjectType);
|
|
end;
|
|
Inc(frAddInsCount);
|
|
end;
|
|
|
|
procedure frRegisterObject(ClassRef: TfrViewClass; ButtonBmp: TBitmap;
|
|
const ButtonHint: String; EditorForm: TfrObjEditorForm; InitProc:TfrAddinInitProc=nil);
|
|
begin
|
|
frRegisterObject(ClassRef, ButtonBmp, ButtonHint, EditorForm, otlReportView, InitProc);
|
|
end;
|
|
|
|
function frGetAddinIndex(ClassRef: TfrViewClass): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
result := -1;
|
|
for i:=0 to frAddinsCount-1 do
|
|
if frAddIns[i].ClassRef = ClassRef then
|
|
begin
|
|
result := i;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function frGetExportFilterIndex(AClassRef: TfrExportFilterClass; const AFilterExt:string): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
result := -1;
|
|
for i:=0 to Length(frFilters)-1 do
|
|
with frFilters[i] do
|
|
if (ClassRef=AClassRef) and (FilterExt=AFilterExt) then
|
|
begin
|
|
result := i;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
procedure frSetAddinEditor(ClassRef: TfrViewClass; EditorForm: TfrObjEditorForm);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := frGetAddinIndex(ClassRef);
|
|
if i>=0 then
|
|
frAddins[i].EditorForm := EditorForm
|
|
else
|
|
raise Exception.CreateFmt(sClassObjectNotFound,[Classref.ClassName]);
|
|
end;
|
|
|
|
procedure frSetAddinIcon(ClassRef: TfrViewClass; ButtonBmp: TBitmap);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := frGetAddinIndex(ClassRef);
|
|
if i>=0 then
|
|
frAddins[i].ButtonBmp := ButtonBmp
|
|
else
|
|
raise Exception.CreateFmt(sClassObjectNotFound,[Classref.ClassName]);
|
|
end;
|
|
|
|
procedure frSetAddinHint(ClassRef: TfrViewClass; ButtonHint: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := frGetAddinIndex(ClassRef);
|
|
if i>=0 then
|
|
frAddins[i].ButtonHint := ButtonHint
|
|
else
|
|
raise Exception.CreateFmt(sClassObjectNotFound,[Classref.ClassName]);
|
|
end;
|
|
|
|
procedure frRegisterExportFilter(ClassRef: TfrExportFilterClass;
|
|
const FilterDesc, FilterExt: String);
|
|
begin
|
|
if frGetExportFilterIndex(ClassRef, FilterExt)<0 then
|
|
begin
|
|
frFilters[frFiltersCount].ClassRef := ClassRef;
|
|
frFilters[frFiltersCount].FilterDesc := FilterDesc;
|
|
frFilters[frFiltersCount].FilterExt := FilterExt;
|
|
Inc(frFiltersCount);
|
|
end;
|
|
end;
|
|
|
|
procedure frRegisterFunctionLibrary(ClassRef: TClass);
|
|
begin
|
|
frFunctions[frFunctionsCount].FunctionLibrary :=
|
|
TfrFunctionLibrary(ClassRef.NewInstance);
|
|
frFunctions[frFunctionsCount].FunctionLibrary.Create;
|
|
Inc(frFunctionsCount);
|
|
end;
|
|
|
|
procedure frRegisterTool(const MenuCaption: String; ButtonBmp: TBitmap; OnClick: TNotifyEvent);
|
|
begin
|
|
frTools[frToolsCount].Caption := MenuCaption;
|
|
frTools[frToolsCount].ButtonBmp := ButtonBmp;
|
|
frTools[frToolsCount].OnClick := OnClick;
|
|
if frDesigner <> nil then
|
|
frDesigner.RegisterTool(MenuCaption, ButtonBmp, OnClick);
|
|
Inc(frToolsCount);
|
|
end;
|
|
|
|
function Create90Font(Font: TFont): HFont;
|
|
var
|
|
F: TLogFont;
|
|
begin
|
|
GetObject(Font.Handle, SizeOf(TLogFont), @F);
|
|
F.lfEscapement := 900;
|
|
F.lfOrientation := 900;
|
|
Result := CreateFontIndirect(F);
|
|
end;
|
|
|
|
function GetDefaultDataSet: TfrTDataSet;
|
|
var
|
|
FRDataset: TfrDataset;
|
|
begin
|
|
Result := nil;
|
|
if Assigned(CurPage) and (CurPage is TfrPageReport) then
|
|
begin
|
|
FRDataset := nil;
|
|
if CurBand <> nil then
|
|
begin
|
|
case CurBand.Typ of
|
|
btMasterData, btReportSummary, btMasterFooter,
|
|
btGroupHeader, btGroupFooter:
|
|
FRDataset := CurPage.Bands[btMasterData].DataSet;
|
|
btDetailData, btDetailFooter:
|
|
FRDataset := CurPage.Bands[btDetailData].DataSet;
|
|
btSubDetailData, btSubDetailFooter:
|
|
FRDataset := CurPage.Bands[btSubDetailData].DataSet;
|
|
btCrossData, btCrossFooter:
|
|
FRDataset := CurPage.Bands[btCrossData].DataSet;
|
|
end;
|
|
end;
|
|
if FRDataset is TfrDBDataset then
|
|
Result := TfrDBDataSet(FRDataset).GetDataSet
|
|
end;
|
|
end;
|
|
|
|
function ReadString(Stream: TStream): String;
|
|
begin
|
|
if frVersion >= 23 then
|
|
{$IFDEF FREEREP2217READ}
|
|
Result := frReadString(Stream) // load in current format
|
|
else
|
|
if (frVersion = 22) and FRE_COMPATIBLE_READ then
|
|
Result := frReadString2217(Stream) // load in bad format
|
|
else
|
|
{$ELSE}
|
|
Result := frReadString(Stream) else
|
|
{$ENDIF}
|
|
Result := frReadString22(Stream);
|
|
end;
|
|
|
|
procedure ReadMemo(Stream: TStream; Memo: TStrings);
|
|
begin
|
|
if frVersion >= 23 then
|
|
{$IFDEF FREEREP2217READ}
|
|
frReadMemo(Stream, Memo) // load in current format
|
|
else
|
|
if (frVersion = 22) and FRE_COMPATIBLE_READ then
|
|
Memo.Text := frReadMemoText2217(Stream) // load in bad format
|
|
else
|
|
{$ELSE}
|
|
frReadMemo(Stream, Memo) else
|
|
{$ENDIF}
|
|
frReadMemo22(Stream, Memo);
|
|
end;
|
|
|
|
procedure CreateDS(const Desc: String; var DataSet: TfrDataSet; var IsVirtualDS: Boolean);
|
|
begin
|
|
if (Desc <> '') and (Desc[1] in ['1'..'9']) then
|
|
begin
|
|
DataSet := TfrUserDataSet.Create(nil);
|
|
DataSet.RangeEnd := reCount;
|
|
DataSet.RangeEndCount := StrToInt(Desc);
|
|
IsVirtualDS := True;
|
|
end
|
|
else
|
|
DataSet := frFindComponent(CurReport.Owner, Desc) as TfrDataSet;
|
|
if DataSet <> nil then
|
|
DataSet.Init;
|
|
end;
|
|
|
|
// locale neutral StrToFloatDef
|
|
function StringToFloatDef(const S:String; const ADefault:Double): Double;
|
|
var
|
|
Code: Integer;
|
|
begin
|
|
if S='' then
|
|
Code:=1
|
|
else
|
|
Val(S, Result, Code);
|
|
if Code>0 then
|
|
Result:=ADefault;
|
|
end;
|
|
|
|
procedure SetBit(var w: Word; e: Boolean; m: Integer);
|
|
begin
|
|
if e then
|
|
w:=w or m
|
|
else
|
|
w:=w and not m;
|
|
end;
|
|
|
|
function frGetBandName(BandType: TfrBandType): string;
|
|
begin
|
|
result := GetEnumName(TypeInfo(TFrBandType), ord(BandType));
|
|
result := copy(result, 3, Length(result));
|
|
end;
|
|
|
|
procedure frSelectHyphenDictionary(ADict: string);
|
|
begin
|
|
if FHyp = nil then
|
|
FHyp := THyphen.create;
|
|
FHyp.Dictionary:=ADict;
|
|
try
|
|
FHyp.BreakWord('lazreport');
|
|
except
|
|
on E:EHyphenationException do
|
|
DebugLn('Error: ', e.message,'. Hyphenation support will be disabled');
|
|
end;
|
|
end;
|
|
|
|
procedure CanvasTextRectJustify(const Canvas:TCanvas;
|
|
const ARect: TRect; X1, X2, Y: integer; const Text: string;
|
|
Trimmed: boolean);
|
|
var
|
|
WordCount,SpcCount,SpcSize:Integer;
|
|
Arr: TArrUTF8Item;
|
|
PxSpc,RxSpc,Extra: Integer;
|
|
i: Integer;
|
|
Cini,Cend: Integer;
|
|
SpaceWidth, AvailWidth: Integer;
|
|
s:string;
|
|
begin
|
|
|
|
AvailWidth := (X2-X1);
|
|
// count words
|
|
Arr := UTF8CountWords(Text, WordCount, SpcCount, SpcSize);
|
|
|
|
// handle trimmed text
|
|
s := Text;
|
|
if (SpcCount>0) then
|
|
begin
|
|
Cini := 0;
|
|
CEnd := Length(Arr)-1;
|
|
if Trimmed then
|
|
begin
|
|
s := Trim(Text);
|
|
if Arr[Cini].Space then
|
|
begin
|
|
Inc(Cini);
|
|
Dec(SpcCount);
|
|
end;
|
|
if Arr[CEnd].Space then
|
|
begin
|
|
Dec(CEnd);
|
|
Dec(SpcCount);
|
|
end;
|
|
end;
|
|
AvailWidth := AvailWidth - Canvas.TextWidth(s);
|
|
end;
|
|
|
|
// check if long way is needed
|
|
if (SpcCount>0) and (AvailWidth>0) then
|
|
begin
|
|
|
|
SpaceWidth := Canvas.TextWidth(' ');
|
|
PxSpc := AvailWidth div SpcCount;
|
|
RxSpc := AvailWidth mod SpcCount;
|
|
if PxSPC=0 then
|
|
begin
|
|
PxSPC := 1;
|
|
RxSpc := 0;
|
|
end;
|
|
|
|
for i:=CIni to CEnd do
|
|
if Arr[i].Space then
|
|
begin
|
|
X1 := X1 + Arr[i].Count * SpaceWidth;
|
|
if AvailWidth>0 then
|
|
begin
|
|
Extra := PxSpc;
|
|
if RxSpc>0 then
|
|
begin
|
|
Inc(Extra);
|
|
Dec(RxSpc);
|
|
end;
|
|
X1 := X1 + Extra;
|
|
Dec(AvailWidth, Extra);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
s := Copy(Text, Arr[i].Index, Arr[i].Count);
|
|
Canvas.TextRect(ARect, X1, Y, s);
|
|
X1 := X1 + Canvas.TextWidth(s);
|
|
end;
|
|
|
|
end else
|
|
Canvas.TextRect(ARect, X1, Y, s);
|
|
|
|
SetLength(Arr, 0);
|
|
end;
|
|
|
|
{ TfrReportDesigner }
|
|
|
|
procedure TfrReportDesigner.SetModified(AValue: Boolean);
|
|
begin
|
|
if Assigned(CurReport) then
|
|
CurReport.FReportLastChange:=Now;
|
|
if FModified=AValue then Exit;
|
|
FModified:=AValue;
|
|
end;
|
|
|
|
{ TfrControl }
|
|
|
|
procedure TfrControl.UpdateControlPosition;
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TfrControl.AttachToParent;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TfrControl.OwnerForm: TWinControl;
|
|
begin
|
|
if Assigned(OwnerPage) and (OwnerPage is TfrPageDialog) then
|
|
Result:=TfrPageDialog(OwnerPage).Form
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
constructor TfrControl.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtAddIn;
|
|
end;
|
|
|
|
procedure TfrControl.Draw(ACanvas: TCanvas);
|
|
begin
|
|
BeginDraw(ACanvas);
|
|
CalcGaps;
|
|
PaintDesignControl;
|
|
RestoreCoord;
|
|
end;
|
|
|
|
procedure TfrControl.DefinePopupMenu(Popup: TPopupMenu);
|
|
begin
|
|
inherited DefinePopupMenu(Popup);
|
|
end;
|
|
|
|
{ TfrNonVisualControl }
|
|
|
|
procedure TfrNonVisualControl.PaintDesignControl;
|
|
begin
|
|
DrawFrameControl(Canvas.Handle, DRect, DFC_BUTTON, DFCS_BUTTONPUSH);
|
|
Canvas.Draw(DRect.Left + 2, DRect.Top + 2, ControlImage);
|
|
end;
|
|
|
|
constructor TfrNonVisualControl.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
ControlImage := CreateBitmapFromResourceName(HInstance, ClassName);
|
|
dx := 28;
|
|
dy := 28;
|
|
end;
|
|
|
|
destructor TfrNonVisualControl.Destroy;
|
|
begin
|
|
FreeAndNil(ControlImage);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrNonVisualControl.Draw(ACanvas: TCanvas);
|
|
begin
|
|
dx := 28;
|
|
dy := 28;
|
|
BeginDraw(ACanvas);
|
|
CalcGaps;
|
|
ShowBackground;
|
|
PaintDesignControl;
|
|
RestoreCoord;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Parent := nil;
|
|
Memo1 := TStringList.Create;
|
|
fFrameWidth := 1;
|
|
fFrameColor := clBlack;
|
|
fFillColor := clNone;
|
|
fFormat := 2*256 + Ord(DecimalSeparator);
|
|
BaseName := 'View';
|
|
FVisible := True;
|
|
StreamMode := smDesigning;
|
|
ScaleX := 1;
|
|
ScaleY := 1;
|
|
OffsX := 0;
|
|
OffsY := 0;
|
|
Flags := flStretched;
|
|
|
|
fFrames:=[]; //No frame
|
|
end;
|
|
|
|
destructor TfrView.Destroy;
|
|
begin
|
|
Memo1.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrView.Assign(From: TfrView);
|
|
begin
|
|
inherited Assign(From);
|
|
|
|
fName := From.Name;
|
|
Typ := From.Typ;
|
|
Selected := From.Selected;
|
|
|
|
Flags := From.Flags;
|
|
fFrameWidth := From.FrameWidth;
|
|
fFrameColor := From.FrameColor;
|
|
fFrameStyle := From.FrameStyle;
|
|
fFillColor := From.FillColor;
|
|
fFormat := From.Format;
|
|
fFormatStr := From.FormatStr;
|
|
fVisible := From.Visible;
|
|
fFrames:=From.Frames;
|
|
FTag:=From.FTag;
|
|
FURLInfo:=From.FURLInfo;
|
|
end;
|
|
|
|
procedure TfrView.CalcGaps;
|
|
var
|
|
bx, by, bx1, by1, wx1, wx2, wy1, wy2: Integer;
|
|
begin
|
|
SaveX := x;
|
|
SaveY := y;
|
|
SaveDX := dx;
|
|
SaveDY := dy;
|
|
SaveFW := FrameWidth;
|
|
if DocMode = dmDesigning then
|
|
begin
|
|
ScaleX := 1;
|
|
ScaleY := 1;
|
|
OffsX := 0;
|
|
OffsY := 0;
|
|
end;
|
|
|
|
x := Round(x*ScaleX)+OffsX;
|
|
y := Round(y* ScaleY)+OffsY;
|
|
dx:= Round(dx*ScaleX);
|
|
dy:= Round(dy*ScaleY);
|
|
|
|
wx1 := Round((FrameWidth * ScaleX - 1) / 2);
|
|
wx2 := Round(FrameWidth * ScaleX / 2);
|
|
wy1 := Round((FrameWidth * ScaleY - 1) / 2);
|
|
wy2 := Round(FrameWidth * ScaleY / 2);
|
|
fFrameWidth := FrameWidth * ScaleX;
|
|
gapx := wx2 + 2;
|
|
gapy := wy2 div 2 + 1;
|
|
bx := x;
|
|
by := y;
|
|
bx1 := Round((SaveX + SaveDX) * ScaleX + OffsX);
|
|
by1 := Round((SaveY + SaveDY) * ScaleY + OffsY);
|
|
|
|
if frbTop in Frames then Dec(bx1, wx2);
|
|
if frbLeft in Frames then Dec(by1, wy2);
|
|
if frbBottom in Frames then Inc(bx, wx1);
|
|
if frbRight in Frames then Inc(by, wy1);
|
|
DRect := Rect(bx, by, bx1 + 1, by1 + 1);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('CalcGaps: ScaleXY:%f %f OLD:%d %d %d %d NEW: %d %d %d %d GAPS: %d %d DRECT: %s',
|
|
[ScaleX,ScaleY,SaveX,SaveY,SaveDx,SaveDy,x,y,dx,dy,gapx,gapy,dbgs(drect)]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrView.RestoreCoord;
|
|
begin
|
|
x := SaveX;
|
|
y := SaveY;
|
|
dx := SaveDX;
|
|
dy := SaveDY;
|
|
fFrameWidth := SaveFW;
|
|
end;
|
|
|
|
procedure TfrView.ShowBackGround;
|
|
var
|
|
fp: TColor;
|
|
begin
|
|
if DisableDrawing then Exit;
|
|
if (DocMode = dmPrinting) and (FillColor = clNone) then Exit;
|
|
fp := FillColor;
|
|
if (DocMode = dmDesigning) and (fp = clNone) then
|
|
fp := clWhite;
|
|
Canvas.Brush.Bitmap := nil;
|
|
Canvas.Brush.Style := bsSolid;
|
|
Canvas.Brush.Color := fp;
|
|
if DocMode = dmDesigning then
|
|
Canvas.FillRect(DRect)
|
|
else
|
|
Canvas.FillRect(Rect(x, y,
|
|
//use calculating coords instead of dx, dy - for best view
|
|
Round((SaveX + SaveDX) * ScaleX + OffsX), Round((SaveY + SaveDY) * ScaleY + OffsY)));
|
|
end;
|
|
|
|
procedure TfrView.ShowFrame;
|
|
var
|
|
x1, y1: Integer;
|
|
|
|
procedure IntLine(X11, Y11, DX11, DY11: Integer);
|
|
begin
|
|
Canvas.MoveTo(X11, Y11);
|
|
Canvas.LineTo(X11+DX11, Y11+Dy11);
|
|
end;
|
|
|
|
procedure Line1(x, y, x1, y1: Integer);
|
|
var
|
|
i, w: Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Line1(',InttoStr(x),',',IntToStr(y),',',IntToStr(x1),',',IntToStr(y1),')');
|
|
{$ENDIF}
|
|
|
|
if Canvas.Pen.Style = psSolid then
|
|
begin
|
|
if FrameStyle<>frsDouble then
|
|
begin
|
|
Canvas.MoveTo(x, y);
|
|
Canvas.LineTo(x1, y1);
|
|
end
|
|
else
|
|
begin
|
|
if x = x1 then
|
|
begin
|
|
Canvas.MoveTo(x - Round(FrameWidth), y);
|
|
Canvas.LineTo(x1 - Round(FrameWidth), y1);
|
|
Canvas.Pen.Color := FillColor;
|
|
Canvas.MoveTo(x, y);
|
|
Canvas.LineTo(x1, y1);
|
|
Canvas.Pen.Color := FrameColor;
|
|
Canvas.MoveTo(x + Round(FrameWidth), y);
|
|
Canvas.LineTo(x1 + Round(FrameWidth), y1);
|
|
end
|
|
else
|
|
begin
|
|
Canvas.MoveTo(x, y - Round(FrameWidth));
|
|
Canvas.LineTo(x1, y1 - Round(FrameWidth));
|
|
Canvas.Pen.Color := FillColor;
|
|
Canvas.MoveTo(x, y);
|
|
Canvas.LineTo(x1, y1);
|
|
Canvas.Pen.Color := FrameColor;
|
|
Canvas.MoveTo(x, y + Round(FrameWidth));
|
|
Canvas.LineTo(x1, y1 + Round(FrameWidth));
|
|
end;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
Canvas.Brush.Color:=FillColor;
|
|
w := Canvas.Pen.Width;
|
|
Canvas.Pen.Width := 1;
|
|
if x = x1 then
|
|
begin
|
|
for i := 0 to w - 1 do
|
|
begin
|
|
Canvas.MoveTo(x - w div 2 + i, y);
|
|
Canvas.LineTo(x - w div 2 + i, y1);
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
for i := 0 to w - 1 do
|
|
begin
|
|
Canvas.MoveTo(x, y - w div 2 + i);
|
|
Canvas.LineTo(x1, y - w div 2 + i);
|
|
end;
|
|
end;
|
|
Canvas.Pen.Width := w;
|
|
end;
|
|
end;
|
|
begin
|
|
if DisableDrawing then Exit;
|
|
if (DocMode = dmPrinting) and (Frames=[]) then Exit;
|
|
|
|
with Canvas do
|
|
begin
|
|
Brush.Style:= bsClear;
|
|
Pen.Style:=psSolid;
|
|
if (dx>0) and (dy>0) and (DocMode = dmDesigning) then
|
|
begin
|
|
Pen.Color := clBlack;
|
|
Pen.Width := 1;
|
|
IntLine(x,y+3,0,-3);
|
|
IntLine(x,y, 4, 0);
|
|
IntLine(x,y+dy-3, 0, 3);
|
|
IntLine(x,y+dy, 4, 0);
|
|
IntLine(x+dx-3,y,3,0);
|
|
IntLine(x+dx,y,0,4);
|
|
IntLine(x+dx-3,y+dy,3,0);
|
|
IntLine(x+dx,y+dy,0,-4);
|
|
end;
|
|
|
|
Pen.Color := FrameColor;
|
|
Pen.Width := Round(FrameWidth);
|
|
if FrameStyle<>frsDouble then
|
|
Pen.Style := TPenStyle(FrameStyle);
|
|
|
|
// use calculating coords instead of dx, dy - for best view
|
|
x1 := Round((SaveX + SaveDX) * ScaleX + OffsX);
|
|
y1 := Round((SaveY + SaveDY) * ScaleY + OffsY);
|
|
|
|
{ // todo: Frame is not implemented in Win32
|
|
if ((frbTop in Frames) and (frbLeft in Frames) and
|
|
(frbBottom in Frames) and (frbRight in Frames)) and (FrameStyle=frsSolid) then
|
|
Frame(x,y, x1 + 1, y1 + 1)
|
|
else
|
|
}
|
|
begin
|
|
if (frbRight in Frames) then Line1(x1, y, x1, y1);
|
|
if (frbLeft in Frames) then Line1(x, y, x, y1);
|
|
if (frbBottom in Frames) then Line1(x, y1, x1, y1);
|
|
if (frbTop in Frames) then Line1(x, y, x1, y);
|
|
end;
|
|
|
|
Brush.Style := bsSolid;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.BeginDraw(ACanvas: TCanvas);
|
|
begin
|
|
fCanvas := ACanvas;
|
|
CurView := Self;
|
|
end;
|
|
|
|
procedure TfrView.Print(Stream: TStream);
|
|
var
|
|
FTmpTag:string;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('%s.TfrView.Print()',[name]);
|
|
{$ENDIF}
|
|
BeginDraw(Canvas);
|
|
Memo1.Assign(Memo);
|
|
CurReport.InternalOnEnterRect(Memo1, Self);
|
|
frInterpretator.DoScript(Script);
|
|
if not Visible then Exit;
|
|
|
|
Stream.Write(Typ, 1);
|
|
if Typ = gtAddIn then
|
|
frWriteString(Stream, ClassName);
|
|
|
|
|
|
FTmpTag:=FTag;
|
|
if (FTag<>'') and (Pos('[', FTag) > 0) then
|
|
FTag:=lrExpandVariables(FTmpTag);
|
|
|
|
SaveToStream(Stream);
|
|
FTag:=FTmpTag;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('%s.TfrView.Print() end',[name]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrView.ExportData;
|
|
begin
|
|
CurReport.InternalOnExportData(Self);
|
|
CurReport.InternalOnExported(Self);
|
|
end;
|
|
|
|
procedure TfrView.LoadFromStream(Stream: TStream);
|
|
var
|
|
wb : Word;
|
|
li : Longint;
|
|
S : Single;
|
|
i : Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('%s.TfrView.LoadFromStream begin StreamMode=%d ClassName=%s',
|
|
[name,Ord(StreamMode),ClassName]);
|
|
{$ENDIF}
|
|
with Stream do
|
|
begin
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
if frVersion >= 23 then
|
|
Name := ReadString(Stream)
|
|
else
|
|
CreateUniqueName;
|
|
end;
|
|
|
|
//Read(x, 18); // this is equal to, but much faster:
|
|
Read(x, 4);
|
|
Read(y, 4);
|
|
Read(dx, 4);
|
|
Read(dy, 4);
|
|
Read(Flags, 2);
|
|
|
|
if frVersion>23 then
|
|
begin
|
|
S := 0;
|
|
Read(S, SizeOf(S)); fFrameWidth := S;
|
|
Read(fFrameColor, SizeOf(fFrameColor));
|
|
Read(fFrames, SizeOf(fFrames));
|
|
Read(fFrameStyle, SizeOf(fFrameStyle));
|
|
end else
|
|
begin
|
|
wb := 0;
|
|
Read(wb, 2); // frametyp
|
|
fFrameTyp := wb;
|
|
fFrames := [];
|
|
if (wb and $1) <> 0 then include(fFrames, frbRight);
|
|
if (wb and $2) <> 0 then include(fFrames, frbBottom);
|
|
if (wb and $4) <> 0 then include(fFrames, frbLeft);
|
|
if (wb and $8) <> 0 then include(fFrames, frbTop);
|
|
li := 0;
|
|
Read(li, 4); // framewidth (single)
|
|
if li <= 10 then
|
|
li := li * 1000;
|
|
fFrameWidth := li / 1000;
|
|
Read(li, 4); // framecolor
|
|
fFrameColor := li;
|
|
read(wb, 2); // framestyle
|
|
fFrameStyle := TfrFrameStyle(wb);
|
|
end;
|
|
|
|
Read(fFillColor, 4);
|
|
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
Read(fFormat, 4);
|
|
fFormatStr := ReadString(Stream);
|
|
end;
|
|
ReadMemo(Stream, Memo);
|
|
|
|
if (frVersion >= 23) and (StreamMode = smDesigning) then
|
|
begin
|
|
ReadMemo(Stream, Script);
|
|
wb := 0;
|
|
Read(wb,2);
|
|
Visible:=(Wb<>0);
|
|
end;
|
|
|
|
if (frVersion >= 25) then begin
|
|
I := 0;
|
|
Read(I, 4);
|
|
ParentBandType := TfrBandType(I);
|
|
end;
|
|
|
|
if frVersion>25 then
|
|
begin
|
|
FTag := frReadString(Stream);
|
|
FURLInfo := frReadString(Stream);
|
|
end;
|
|
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('%s.TfrView.LoadFromStream end',[name]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
S:string;
|
|
begin
|
|
inherited LoadFromXML(XML,Path);
|
|
StreamMode := TfrStreamMode(XML.GetValue(Path+'StreamMode/Value'{%H-}, 0)); // TODO Check default
|
|
{
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
if frVersion >= 23 then
|
|
Name := XML.GetValue(Path+'Name/Value', 'checkthis!') // TODO Check default
|
|
else
|
|
CreateUniqueName;
|
|
end;
|
|
}
|
|
x := XML.GetValue(Path + 'Size/Left/Value'{%H-}, 0);
|
|
y := XML.GetValue(Path + 'Size/Top/Value'{%H-}, 0);
|
|
dx := XML.GetValue(Path + 'Size/Width/Value'{%H-}, 100);
|
|
dy := XML.GetValue(Path + 'Size/Height/Value'{%H-}, 100);
|
|
Flags := Word(XML.GetValue(Path + 'Flags/Value'{%H-}, 0)); // TODO Check default
|
|
|
|
FFrameWidth := StringToFloatDef(XML.GetValue(Path+'Frames/FrameWidth/Value', ''), 1.0);
|
|
FFramecolor := StringToColor(XML.GetValue(Path+'Frames/FrameColor/Value', 'clBlack')); // TODO Check default
|
|
|
|
S:=XML.GetValue(Path+'Frames/FrameBorders/Value','');
|
|
if S<>'' then
|
|
RestoreProperty('Frames',S);
|
|
|
|
S:=XML.GetValue(Path+'Frames/FrameStyle/Value','');
|
|
if S<>'' then
|
|
RestoreProperty('FrameStyle',S);
|
|
|
|
FFillColor := StringToColor(XML.GetValue(Path+'FillColor/Value', 'clWindow')); // TODO Check default
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
fFormat := XML.GetValue(Path+'Data/Format/Value'{%H-}, Format); // TODO Check default
|
|
fFormatStr := XML.GetValue(Path+'Data/FormatStr/Value', FormatStr);
|
|
Memo.Text := XML.GetValue(Path+'Data/Memo/Value', ''); // TODO Check default
|
|
Script.Text:= XML.GetValue(Path+'Data/Script/Value', ''); // TODO Check default
|
|
end
|
|
else
|
|
memo1.text := XML.GetValue(Path+'Data/Memo1/Value', ''); // TODO Check default
|
|
|
|
FTag:=XML.GetValue(Path+'Tag/Value', '');
|
|
FURLInfo:=XML.GetValue(Path+'FURLInfo/Value', '');
|
|
end;
|
|
|
|
procedure TfrView.SaveToStream(Stream: TStream);
|
|
var
|
|
S: Single;
|
|
B: Integer;
|
|
FTmpS:string;
|
|
{$IFDEF DebugLR}
|
|
st: string;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
WriteStr(st, StreamMode);
|
|
DebugLn('%s.SaveToStream begin StreamMode=%s',[name, st]);
|
|
{$ENDIF}
|
|
|
|
with Stream do
|
|
begin
|
|
if StreamMode = smDesigning then
|
|
frWriteString(Stream, Name);
|
|
// Write(x, 18); // this is equal to, but much faster:
|
|
Write(x, 4);
|
|
Write(y, 4);
|
|
Write(dx, 4);
|
|
Write(dy, 4);
|
|
Write(Flags, 2);
|
|
|
|
S := fFrameWidth; Write(s,SizeOf(s));
|
|
Write(fFrameColor, SizeOf(fFrameColor));
|
|
Write(fFrames,SizeOf(fFrames));
|
|
Write(fFrameStyle, SizeOf(fFrameStyle));
|
|
|
|
Write(fFillColor, 4);
|
|
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
Write(fFormat, 4);
|
|
frWriteString(Stream, fFormatStr);
|
|
frWriteMemo(Stream, Memo);
|
|
frWriteMemo(Stream, Script);
|
|
Write(Visible, 2);
|
|
end
|
|
else
|
|
frWriteMemo(Stream, Memo1);
|
|
|
|
// parent band type new in stream format 25
|
|
B := 0;
|
|
if Parent<>nil then
|
|
B := ord(Parent.Typ);
|
|
Write(B, 4);
|
|
|
|
//Tag property stream format 26
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
frWriteString(Stream, FTag);
|
|
frWriteString(Stream, FURLInfo);
|
|
end
|
|
else
|
|
begin
|
|
FTmpS:=lrExpandVariables(FTag);
|
|
frWriteString(Stream, FTmpS);
|
|
FTmpS:=lrExpandVariables(FURLInfo);
|
|
frWriteString(Stream, FTmpS);
|
|
end;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
Debugln('%s.SaveToStream end',[name]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrView.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited SaveToXML(XML,Path);
|
|
XML.SetValue(Path+'Typ/Value', frTypeObjectToStr(Typ));
|
|
XML.SetValue(Path+'StreamMode/Value'{%H-}, Ord(StreamMode)); //todo: use symbolic valuess
|
|
XML.SetValue(Path+'Size/Left/Value'{%H-}, x);
|
|
XML.SetValue(Path+'Size/Top/Value'{%H-}, y);
|
|
XML.SetValue(Path+'Size/Width/Value'{%H-}, dx);
|
|
XML.SetValue(Path+'Size/Height/Value'{%H-}, dy);
|
|
XML.SetValue(Path+'Flags/Value'{%H-}, flags);
|
|
|
|
if IsPublishedProp(self,'FillColor') then
|
|
XML.SetValue(Path+'FillColor/Value', GetSaveProperty('FillColor'));
|
|
|
|
if IsPublishedProp(self,'FrameColor') then
|
|
XML.SetValue(Path+'Frames/FrameColor/Value', GetSaveProperty('FrameColor'));
|
|
|
|
if IsPublishedProp(self,'FrameStyle') then
|
|
XML.SetValue(Path+'Frames/FrameStyle/Value', GetSaveProperty('FrameStyle'));
|
|
|
|
if IsPublishedProp(self,'FrameWidth') then
|
|
XML.SetValue(Path+'Frames/FrameWidth/Value', GetSaveProperty('FrameWidth'));
|
|
|
|
if IsPublishedProp(self,'Frames') then
|
|
XML.SetValue(Path+'Frames/FrameBorders/Value', GetSaveProperty('Frames'));
|
|
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
if IsPublishedProp(self,'Format') then
|
|
XML.SetValue(Path+'Data/Format/Value'{%H-}, Format);
|
|
if IsPublishedProp(self,'FormatStr') then
|
|
XML.SetValue(Path+'Data/FormatStr/Value', FormatStr);
|
|
if IsPublishedProp(self,'Memo') then
|
|
XML.SetValue(Path+'Data/Memo/Value', TStrings(Memo).Text);
|
|
if IsPublishedProp(self,'Script') then
|
|
XML.SetValue(Path+'Data/Script/Value', TStrings(Script).Text);
|
|
|
|
end
|
|
else
|
|
XML.SetValue(Path+'Data/Memo1/Value', Memo1.Text);
|
|
XML.SetValue(Path+'Tag/Value', FTag);
|
|
XML.SetValue(Path+'FURLInfo/Value', FURLInfo);
|
|
end;
|
|
|
|
procedure TfrView.Resized;
|
|
begin
|
|
end;
|
|
|
|
procedure TfrView.GetBlob(b: TfrTField);
|
|
begin
|
|
if b=nil then;
|
|
end;
|
|
|
|
procedure TfrView.OnHook(View: TfrView);
|
|
begin
|
|
if view=nil then;
|
|
end;
|
|
|
|
procedure TfrView.BeforeChange;
|
|
begin
|
|
if (frDesigner<>nil) and (fUpdate=0) and (DocMode=dmDesigning) then
|
|
frDesigner.BeforeChange;
|
|
end;
|
|
|
|
procedure TfrView.AfterChange;
|
|
begin
|
|
if (frDesigner<>nil) and (fUpdate=0) and (DocMode=dmDesigning) then
|
|
frDesigner.AfterChange;
|
|
end;
|
|
|
|
procedure TfrView.AfterCreate;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TfrView.ResetLastValue;
|
|
begin
|
|
// to be overriden in TfrMemoView
|
|
end;
|
|
|
|
function TfrView.GetClipRgn(rt: TfrRgnType): HRGN;
|
|
var
|
|
bx, by, bx1, by1, w1, w2: Integer;
|
|
begin
|
|
if FrameStyle=frsDouble then
|
|
begin
|
|
w1 := Round(FrameWidth * 1.5);
|
|
w2 := Round((FrameWidth - 1) / 2 + FrameWidth);
|
|
end
|
|
else
|
|
begin
|
|
w1 := Round(FrameWidth / 2);
|
|
w2 := Round((FrameWidth - 1) / 2);
|
|
end;
|
|
bx:=x;
|
|
by:=y;
|
|
bx1:=x+dx+1;
|
|
by1:=y+dy+1;
|
|
|
|
if (frbTop in Frames) then Inc(bx1, w2);
|
|
if (frbLeft in Frames) then Inc(by1, w2);
|
|
if (frbBottom in Frames) then Dec(bx, w1);
|
|
if (frbRight in Frames) then Dec(by, w1);
|
|
if rt = rtNormal then
|
|
Result := CreateRectRgn(bx, by, bx1, by1)
|
|
else
|
|
Result := CreateRectRgn(bx - 10, by - 10, bx1 + 10, by1 + 10);
|
|
end;
|
|
|
|
procedure TfrView.SetBounds(aLeft, aTop, aWidth, aHeight: Integer);
|
|
begin
|
|
Self.x := aLeft;
|
|
Self.y := aTop;
|
|
Self.dx := aWidth;
|
|
Self.dy:= aHeight;
|
|
end;
|
|
|
|
function TfrView.PointInView(aX,aY: Integer): Boolean;
|
|
Var Rc : TRect;
|
|
bx, by, bx1, by1, w1, w2: Integer;
|
|
begin
|
|
if FrameStyle=frsDouble then
|
|
begin
|
|
w1 := Round(FrameWidth * 1.5);
|
|
w2 := Round((FrameWidth - 1) / 2 + FrameWidth);
|
|
end
|
|
else
|
|
begin
|
|
w1 := Round(FrameWidth / 2);
|
|
w2 := Round((FrameWidth - 1) / 2);
|
|
end;
|
|
bx:=x;
|
|
by:=y;
|
|
bx1:=dx+1;
|
|
by1:=dy+1;
|
|
|
|
if (frbTop in Frames) then Inc(bx1, w2);
|
|
if (frbLeft in Frames) then Inc(by1, w2);
|
|
if (frbBottom in Frames) then Dec(bx, w1);
|
|
if (frbRight in Frames) then Dec(by, w1);
|
|
Rc:=Bounds(bx, by, bx1, by1);
|
|
|
|
Result:=((aX>Rc.Left) and (aX<Rc.Right) and (aY>Rc.Top) and (aY<Rc.Bottom));
|
|
end;
|
|
|
|
procedure TfrView.Invalidate;
|
|
begin
|
|
if Assigned(Canvas) and (fUpdate=0) then
|
|
Draw(Canvas);
|
|
end;
|
|
|
|
procedure TfrView.DefinePopupMenu(Popup: TPopupMenu);
|
|
var
|
|
m: TMenuItem;
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := '-';
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sStretched;
|
|
m.OnClick := @P1Click;
|
|
m.Checked := Stretched;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
procedure TfrView.P1Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flStretched);
|
|
end;
|
|
|
|
function TfrView.GetLeft: Double;
|
|
begin
|
|
if frDesigner<>nil then
|
|
result := frDesigner.PointsToUnits(x)
|
|
else
|
|
result := x;
|
|
end;
|
|
|
|
function TfrView.GetStretched: Boolean;
|
|
begin
|
|
Result:=((Flags and flStretched)<>0);
|
|
end;
|
|
|
|
function TfrView.GetHeight: Double;
|
|
begin
|
|
if frDesigner<>nil then
|
|
result := frDesigner.PointsToUnits(dy)
|
|
else
|
|
result := dy;
|
|
end;
|
|
|
|
function TfrView.GetFrames: TfrFrameBorders;
|
|
begin
|
|
result := fFrames;
|
|
end;
|
|
|
|
procedure TfrView.ModifyFlag(aFlag: Word; aValue: Boolean);
|
|
begin
|
|
BeforeChange;
|
|
SetBit(Flags, AValue, AFlag);
|
|
AfterChange;
|
|
end;
|
|
|
|
procedure TfrView.MenuItemCheckFlag(Sender:TObject; aFlag: Word);
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t := TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
SetBit(t.Flags, Checked, aFlag);
|
|
end;
|
|
end;
|
|
frDesigner.AfterChange;
|
|
end;
|
|
|
|
function TfrView.GetTop: Double;
|
|
begin
|
|
if frDesigner<>nil then
|
|
result := frDesigner.PointsToUnits(y)
|
|
else
|
|
result := y;
|
|
end;
|
|
|
|
function TfrView.GetWidth: Double;
|
|
begin
|
|
if frDesigner<>nil then
|
|
result := frDesigner.PointsToUnits(dx)
|
|
else
|
|
result := dx;
|
|
end;
|
|
|
|
procedure TfrView.SetFillColor(const AValue: TColor);
|
|
begin
|
|
if aValue<>fFillColor then
|
|
begin
|
|
BeforeChange;
|
|
fFillColor:=aValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFormat(const AValue: Integer);
|
|
begin
|
|
if fFormat<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
fFormat := AValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFormatStr(const AValue: String);
|
|
begin
|
|
if fFormatStr<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
fFormatStr := AValue;
|
|
AFterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFrameColor(const AValue: TColor);
|
|
begin
|
|
if fFramecolor<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
fFrameColor := AValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFrames(const AValue: TfrFrameBorders);
|
|
begin
|
|
if (aValue<>fFrames) then
|
|
begin
|
|
BeforeChange;
|
|
fFrames:=AValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFrameStyle(const AValue: TfrFrameStyle);
|
|
begin
|
|
if fFrameStyle<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
fFrameStyle := AValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetFrameWidth(const AValue: Double);
|
|
begin
|
|
if fFrameWidth<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
fFrameWidth := AValue;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrView.SetHeight(const AValue: Double);
|
|
begin
|
|
if frDesigner<>nil then begin
|
|
BeforeChange;
|
|
dy := frDesigner.UnitsToPoints(AValue);
|
|
AfterChange;
|
|
end else
|
|
dy := round(Avalue);
|
|
end;
|
|
|
|
procedure TfrView.SetLeft(const AValue: Double);
|
|
begin
|
|
if frDesigner<>nil then begin
|
|
BeforeChange;
|
|
x := frDesigner.UnitsToPoints(AValue);
|
|
AfterChange;
|
|
end else
|
|
x := round(AValue);
|
|
end;
|
|
|
|
procedure TfrView.SetStretched(const AValue: Boolean);
|
|
begin
|
|
if Stretched<>AValue then
|
|
ModifyFlag(flStretched, AValue);
|
|
end;
|
|
|
|
procedure TfrView.SetTop(const AValue: Double);
|
|
begin
|
|
if frDesigner<>nil then begin
|
|
BeforeChange;
|
|
y := frDesigner.UnitsToPoints(AValue);
|
|
AfterChange;
|
|
end else
|
|
y := round(AValue);
|
|
end;
|
|
|
|
procedure TfrView.SetWidth(const AValue: Double);
|
|
begin
|
|
if frDesigner<>nil then begin
|
|
BeforeChange;
|
|
dx := frDesigner.UnitsToPoints(AValue);
|
|
AfterChange;
|
|
end else
|
|
dx := round(AValue);
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrMemoView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtMemo;
|
|
FFont := TFont.Create;
|
|
FFont.Name := 'Arial';
|
|
FFont.Size := 10;
|
|
FFont.Color := clBlack;
|
|
FFont.Charset := frCharset;
|
|
Highlight.FontColor := clBlack;
|
|
Highlight.FillColor := clWhite;
|
|
Highlight.FontStyle := 2; // fsBold
|
|
BaseName := 'Memo';
|
|
Flags := flStretched + flWordWrap;
|
|
LineSpacing := 2;
|
|
CharacterSpacing := 0;
|
|
Adjust := 0;
|
|
end;
|
|
|
|
destructor TfrMemoView.Destroy;
|
|
begin
|
|
FFont.Free;
|
|
if FLastValue<>nil then
|
|
FLastValue.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetFont(Value: TFont);
|
|
begin
|
|
BeforeChange;
|
|
fFont.Assign(Value);
|
|
AfterChange;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetHideDuplicates(const AValue: Boolean);
|
|
begin
|
|
if HideDuplicates<>AValue then
|
|
ModifyFlag(flHideDuplicates, AValue);
|
|
end;
|
|
|
|
procedure TfrMemoView.SetHideZeroValues(AValue: Boolean);
|
|
begin
|
|
if WordBreak<>AValue then
|
|
ModifyFlag(flHideZeros, AValue);
|
|
end;
|
|
|
|
procedure TfrMemoView.SetIsLastValueSet(const AValue: boolean);
|
|
begin
|
|
if AValue then begin
|
|
if FLastValue=nil then
|
|
FLastValue := TStringList.Create;
|
|
FLastValue.Assign(Memo1);
|
|
end else
|
|
if FLastValue<>nil then begin
|
|
FLastValue.Free;
|
|
FLastValue:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetJustify(AValue: boolean);
|
|
begin
|
|
// only if AValue=true change Adjust to reflect justify
|
|
// otherwise let it alone, so previous value of alignment is respected
|
|
if Avalue then
|
|
Adjust := Adjust or %11;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetLayout(const AValue: TTextLayout);
|
|
begin
|
|
if Layout<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
Adjust := (Adjust and %11100111) or (ord(AValue) shl 3);
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetWordBreak(AValue: Boolean);
|
|
begin
|
|
if WordBreak<>AValue then
|
|
ModifyFlag(flWordBreak, AValue);
|
|
end;
|
|
|
|
procedure TfrMemoView.SetWordWrap(const AValue: Boolean);
|
|
begin
|
|
if WordWrap<>AValue then
|
|
ModifyFlag(flWordWrap, AValue);
|
|
end;
|
|
|
|
procedure TfrMemoView.Assign(From: TfrView);
|
|
begin
|
|
inherited Assign(From);
|
|
FFont.Assign(TfrMemoView(From).Font);
|
|
Adjust := TfrMemoView(From).Adjust;
|
|
Highlight := TfrMemoView(From).Highlight;
|
|
HighlightStr := TfrMemoView(From).HighlightStr;
|
|
LineSpacing := TfrMemoView(From).LineSpacing;
|
|
end;
|
|
|
|
procedure TfrMemoView.ExpandVariables;
|
|
var
|
|
i: Integer;
|
|
procedure GetData(var s: String);
|
|
var
|
|
i, j: Integer;
|
|
s1, s2: String;
|
|
begin
|
|
i := 1;
|
|
repeat
|
|
while (i < Length(s)) and (s[i] <> '[') do Inc(i);
|
|
s1 := GetBrackedVariable(s, i, j);
|
|
if i <> j then
|
|
begin
|
|
Delete(s, i, j - i + 1);
|
|
s2 := '';
|
|
CurReport.InternalOnGetValue(s1, s2);
|
|
Insert(s2, s, i);
|
|
Inc(i, Length(s2));
|
|
j := 0;
|
|
end;
|
|
until i = j;
|
|
end;
|
|
|
|
var
|
|
s: string;
|
|
begin
|
|
Memo1.Clear;
|
|
for i := 0 to Memo.Count - 1 do
|
|
begin
|
|
s := Memo[i];
|
|
if Length(s) > 0 then
|
|
begin
|
|
GetData(s);
|
|
Memo1.Add(s)
|
|
end
|
|
else
|
|
Memo1.Add('');
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.AssignFont(aCanvas: TCanvas);
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('AssignFont (%s) INIT: Self.Font.Size=%d aCanvas.Font.Size=%d',
|
|
[self.Font.Name,Self.Font.Size,ACanvas.Font.Size]);
|
|
{$ENDIF}
|
|
//** Brush.Style := bsClear;
|
|
aCanvas.Font.Assign(Self.Font);
|
|
if Self.Font.Name='' then
|
|
aCanvas.Font.Name := 'default';
|
|
//Font := Self.Font;
|
|
if not IsPrinting and (ScaleY<>0) then
|
|
ACanvas.Font.Height := -Round(Self.Font.Size * 96 / 72 * ScaleY);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('AssignFont (%s) DONE: Self.Font.Size=%d aCanvas.Font.Size=%d',
|
|
[self.Font.Name,Self.Font.Size,ACanvas.Font.Size]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
type
|
|
TWordBreaks = string;
|
|
|
|
const
|
|
gl:string='ÀŨÈÎÓÛÝÞßàåèîóûýþ';
|
|
r_sogl:string='ÚÜúü';
|
|
|
|
function BreakWord(s: string): TWordBreaks;
|
|
|
|
function IsCharIn(i:integer; target:string):boolean;
|
|
begin
|
|
result := Pos(UTF8Copy(s, i, 1), target)>0;
|
|
end;
|
|
|
|
var
|
|
i,len: Integer;
|
|
IsCh1,IsCh2,CanBreak: Boolean;
|
|
begin
|
|
Result := '';
|
|
Len := UTF8Length(s);
|
|
if Len > 4 then
|
|
begin
|
|
i := 2;
|
|
repeat
|
|
CanBreak := False;
|
|
IsCh1 := IsCharIn(i + 1,gl);
|
|
IsCh2 := IsCharIn(i + 2,gl);
|
|
if IsCharIn(i,gl) then
|
|
begin
|
|
if IsCh1 or IsCh2 then
|
|
CanBreak := True;
|
|
end
|
|
else
|
|
begin
|
|
if not IsCh1 and not IsCharIn(i + 1,r_sogl) and IsCh2 then
|
|
CanBreak := True;
|
|
end;
|
|
if CanBreak then
|
|
Result := Result + Chr(i);
|
|
Inc(i);
|
|
until i > Len - 2;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('');
|
|
debugLn('breakword: s=%s result=%s',[dbgstr(s),dbgstr(result)]);
|
|
DebugLnExit('');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrMemoView.WrapMemo;
|
|
var
|
|
size, size1, maxwidth: Integer;
|
|
b: TWordBreaks;
|
|
WCanvas: TCanvas;
|
|
desc, aword: string;
|
|
|
|
procedure OutLine(const str: String);
|
|
var
|
|
n, w: Word;
|
|
begin
|
|
n := Length(str);
|
|
if (n > 0) and (str[n] = #1) then
|
|
w := WCanvas.TextWidth(Copy(str, 1, n - 1)) else
|
|
w := WCanvas.TextWidth(str);
|
|
{$IFDEF DebugLR_detail}
|
|
debugLn('Outline: str="%s" w/=%d w%%=%d',[copy(str,1,12),w div 256, w mod 256]);
|
|
{$ENDIF}
|
|
SMemo.Add(str + Chr(w div 256) + Chr(w mod 256));
|
|
Inc(size, size1);
|
|
end;
|
|
|
|
procedure WrapLine(const s: String);
|
|
var
|
|
i, cur, beg, last, len: Integer;
|
|
WasBreak, CRLF, IsCR: Boolean;
|
|
ch: TUTF8char;
|
|
begin
|
|
|
|
CRLF := False;
|
|
for i := 1 to Length(s) do
|
|
begin
|
|
if s[i] in [#10, #13] then
|
|
begin
|
|
CRLF := True;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
last := 1; beg := 1;
|
|
if not CRLF and ((Length(s) <= 1) or (WCanvas.TextWidth(s) <= maxwidth)) then
|
|
begin
|
|
OutLine(s + #1)
|
|
end else
|
|
begin
|
|
|
|
cur := 1;
|
|
Len := UTF8Desc(S, Desc);
|
|
|
|
while cur <= Len do
|
|
begin
|
|
Ch := UTF8Char(s, cur, Desc);
|
|
|
|
// check for items with soft-breaks
|
|
IsCR := Ch=#13;
|
|
if IsCR then
|
|
begin
|
|
//handle composite newline
|
|
ch := UTF8Char(s, cur+1, desc);
|
|
//dont increase char index if next char is LF (#10)
|
|
if ch<>#10 then
|
|
Inc(Cur);
|
|
end;
|
|
if Ch=#10 then
|
|
begin
|
|
OutLine(UTF8Range(s, beg, cur - beg, Desc) + #1);
|
|
//increase the char index since it's pointing to CR (#13)
|
|
if IsCR then
|
|
Inc(cur);
|
|
Inc(cur);
|
|
beg := cur;
|
|
last := beg;
|
|
Continue;
|
|
end;
|
|
|
|
if ch <> ' ' then
|
|
if WCanvas.TextWidth(UTF8Range(s, beg, cur - beg + 1, Desc)) > maxwidth then
|
|
begin
|
|
|
|
WasBreak := False;
|
|
if (Flags and flWordBreak) <> 0 then
|
|
begin
|
|
|
|
// in case of breaking in the middle, get the full word
|
|
i := cur;
|
|
while (i <= Len) and not UTF8CharIn(ch, [' ', '.', ',', '-']) do
|
|
begin
|
|
Inc(i);
|
|
if i<=len then
|
|
ch := UTF8Char(s, i, Desc);
|
|
end;
|
|
|
|
// find word's break points using some simple hyphenator algorithm
|
|
// TODO: implement interface so users can use their own hyphenator
|
|
// algorithm
|
|
aWord := UTF8Range(s, last, i - last, Desc);
|
|
if (FHyp<>nil) and (FHyp.Loaded) then
|
|
begin
|
|
try
|
|
b := FHyp.BreakWord(UTF8Lowercase(aWord));
|
|
except
|
|
b := '';
|
|
end;
|
|
end else
|
|
b := BreakWord(aWord);
|
|
|
|
// if word can be broken in many segments, find the last segment that
|
|
// fits within maxwidth
|
|
if Length(b) > 0 then
|
|
begin
|
|
i := 1;
|
|
while (i <= Length(b)) and
|
|
(WCanvas.TextWidth(UTF8Range(s, beg, last - beg + Ord(b[i]), Desc) + '-') <= maxwidth) do
|
|
begin
|
|
WasBreak := True;
|
|
cur := last + Ord(b[i]); // cur now points to next char after breaking word
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
if (not WasBreak) and (FHyp<>nil) and FHyp.Loaded then
|
|
// if hyphenator was specified and is valid don't break
|
|
// words which hyphenator didn't break
|
|
else
|
|
// last now points to nex char to be processed
|
|
last := cur;
|
|
end
|
|
else
|
|
begin
|
|
if last = beg then
|
|
last := cur;
|
|
end;
|
|
|
|
if WasBreak then
|
|
begin
|
|
// if word has been broken, output the partial word plus an hyphen
|
|
OutLine(UTF8Range(s, beg, last - beg, Desc) + '-');
|
|
end else
|
|
begin
|
|
// output the portion of word that fits maxwidth
|
|
OutLine(UTF8Range(s, beg, last - beg, Desc));
|
|
// if space was found, advance to next no space char
|
|
while (UTF8Char(s, last, Desc) = ' ') and (last < Length(s)) do
|
|
Inc(last);
|
|
end;
|
|
|
|
beg := last;
|
|
end;
|
|
|
|
if UTF8CharIn(Ch, [' ', '.', ',', '-']) then
|
|
last := cur;
|
|
Inc(cur);
|
|
end;
|
|
|
|
if beg <> cur then
|
|
OutLine(UTF8Range(s, beg, cur - beg + 1, Desc) + #1);
|
|
end;
|
|
end;
|
|
|
|
procedure OutMemo;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
size := y + gapy;
|
|
size1 := -WCanvas.Font.Height + LineSpacing;
|
|
maxWidth := dx - gapx - gapx;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('OutMemo I: Size=%d Size1=%d MaxWidth=%d DIM:%d %d %d %d gapxy:%d %d',
|
|
[Size,Size1,MaxWidth,x,y,dx,dy,gapx,gapy]);
|
|
{$ENDIF}
|
|
for i := 0 to Memo1.Count - 1 do
|
|
begin
|
|
if (Flags and flWordWrap) <> 0 then
|
|
WrapLine(Memo1[i])
|
|
else
|
|
OutLine(Memo1[i] + #1);
|
|
end;
|
|
VHeight := size - y + gapy;
|
|
TextHeight := size1;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('OutMemo E: Size=%d Size1=%d MaxWidth=%d DIM:%d %d %d %d gapxy:%d %d',
|
|
[Size,Size1,MaxWidth,x,y,dx,dy,gapx,gapy]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure OutMemo90;
|
|
var
|
|
i: Integer;
|
|
h, oldh: HFont;
|
|
begin
|
|
h := Create90Font(WCanvas.Font);
|
|
oldh := SelectObject(WCanvas.Handle, h);
|
|
size := x + gapx;
|
|
size1 := -WCanvas.Font.Height + LineSpacing;
|
|
maxwidth := dy - gapy - gapy;
|
|
for i := 0 to Memo1.Count - 1 do
|
|
begin
|
|
if (Flags and flWordWrap) <> 0 then
|
|
WrapLine(Memo1[i])
|
|
else
|
|
OutLine(Memo1[i]);
|
|
end;
|
|
|
|
SelectObject(WCanvas.Handle, oldh);
|
|
DeleteObject(h);
|
|
VHeight := size - x + gapx;
|
|
TextHeight := size1;
|
|
end;
|
|
|
|
begin
|
|
WCanvas := TempBmp.Canvas;
|
|
WCanvas.Font.Assign(Font);
|
|
WCanvas.Font.Height := -Round(Font.Size * 96 / 72);
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrMemoView.WrapMemo INI Font.PPI=%d Font.Size=%d Canvas.Font.PPI=%d WCanvas.Font.Size=%d',
|
|
[Font.PixelsPerInch, Font.Size,Canvas.Font.PixelsPerInch,WCanvas.Font.Size]);
|
|
{$ENDIF}
|
|
|
|
SetTextCharacterExtra(WCanvas.Handle, CharacterSpacing);
|
|
SMemo.Clear;
|
|
if Angle<>0 then
|
|
OutMemo90
|
|
else
|
|
OutMemo;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrMemoView.WrapMemo DONE',[]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrMemoView.ShowMemo;
|
|
var
|
|
DR : TRect;
|
|
SavX,SavY : Integer;
|
|
|
|
procedure OutMemo;
|
|
var
|
|
i: Integer;
|
|
curyf, thf, linespc: double;
|
|
|
|
function OutLine(st: String): Boolean;
|
|
var
|
|
{$IFDEF DebugLR}
|
|
aw: Integer;
|
|
{$ENDIF}
|
|
cond: boolean;
|
|
n, {nw, w, }curx, lasty: Integer;
|
|
lastyf: Double;
|
|
Ts: TTextStyle;
|
|
ParaEnd: boolean;
|
|
begin
|
|
lastyf := curyf + thf - LineSpc - 1;
|
|
lastY := Round(lastyf);
|
|
cond := not streaming and (lasty<=DR.Bottom);
|
|
{$IFDEF DebugLR_detail}
|
|
DebugLn('OutLine curyf=%f + thf=%f - gapy=%d = %f (%d) <= dr.bottom=%d == %s',
|
|
[curyf,thf,gapy,lastyf,lasty,dr.bottom,dbgs(Cond)]);
|
|
{$ENDIF}
|
|
if not Streaming and cond then
|
|
begin
|
|
n := Length(St);
|
|
//w := Ord(St[n - 1]) * 256 + Ord(St[n]);
|
|
ParaEnd := true;
|
|
SetLength(St, n - 2);
|
|
if Length(St) > 0 then
|
|
begin
|
|
if St[Length(St)] = #1 then
|
|
SetLength(St, Length(St) - 1)
|
|
else
|
|
ParaEnd := false;
|
|
end;
|
|
|
|
// handle any alignment with same code
|
|
Ts := Canvas.TextStyle;
|
|
Ts.Layout :=tlTop;
|
|
Ts.Alignment := taLeftJustify;
|
|
Ts.Wordbreak :=false;
|
|
Ts.SingleLine:=True;
|
|
Ts.Clipping :=True;
|
|
Canvas.TextStyle := Ts;
|
|
|
|
(*
|
|
// the disabled code allows for text-autofitting adjusting font size
|
|
// TODO: waiting for users mising this and make it an option or remove it
|
|
nw := Round(w * ScaleX); // needed width
|
|
{$IFDEF DebugLR_detail}
|
|
DebugLn('TextWidth=%d st=%s',[Canvas.TextWidth(St),copy(st, 1, 20)]);
|
|
{$ENDIF}
|
|
while (Canvas.TextWidth(St) > nw) and (Canvas.Font.Size>1) do
|
|
begin
|
|
Canvas.Font.Size := Canvas.Font.Size-1;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Rescal font %d',[Canvas.Font.Size]);
|
|
{$ENDIF}
|
|
end;
|
|
{$IFDEF DebugLR_detail}
|
|
Debugln('Canvas.Font.Size=%d TextWidth=%d',[Canvas.Font.Size,Canvas.TextWidth(St)]);
|
|
aw := Canvas.TextWidth(St); // actual width
|
|
DebugLn('nw=%d aw=%d',[nw,aw]);
|
|
{$ENDIF}
|
|
*)
|
|
case Alignment of
|
|
Classes.taLeftJustify : CurX :=x+gapx;
|
|
Classes.taRightJustify: CurX :=x+dx-1-gapx-Canvas.TextWidth(St);
|
|
Classes.taCenter : CurX :=x+gapx+(dx-gapx-gapx-Canvas.TextWidth(St)) div 2;
|
|
end;
|
|
|
|
if not Exporting then
|
|
begin
|
|
if Justify and not ParaEnd then
|
|
CanvasTextRectJustify(Canvas, DR, x+gapx, x+dx-1-gapx, round(CurYf), St, true)
|
|
else
|
|
Canvas.TextRect(DR, CurX, round(curYf), St);
|
|
end
|
|
else
|
|
CurReport.InternalOnExportText(X, round(curYf), St, Self);
|
|
|
|
Inc(CurStrNo);
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := True;
|
|
|
|
curyf := curyf + thf;
|
|
end;
|
|
|
|
begin {OutMemo}
|
|
if Alignment in [Classes.taLeftJustify..Classes.taCenter] then
|
|
begin
|
|
if Layout=tlCenter then
|
|
y:=y+(dy-VHeight) div 2
|
|
else if Layout=tlBottom then
|
|
y:=y+dy-VHeight;
|
|
end;
|
|
curyf := y + gapy;
|
|
|
|
LineSpc := LineSpacing * ScaleY;
|
|
// calc our reference at 100% and then scale it
|
|
// NOTE: this should not be r((Self.Font.Size*96/72 + LineSpacing)*ScaleY)
|
|
// as our base at 100% is rounded.
|
|
thf := Round(Self.Font.Size*96/72 + LineSpacing)* ScaleY;
|
|
// Corrects font height, that's the total line height minus the scaled linespacing
|
|
Canvas.Font.Height := -Round(thf - LineSpc);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('curyf=%f thf=%f Font.height=%d TextHeight(H)=%d DR=%s Memo1.Count=%d',
|
|
[curyf, thf, Canvas.Font.Height, Canvas.Textheight('H'), dbgs(DR), Memo1.Count]);
|
|
{$ENDIF}
|
|
CurStrNo := 0;
|
|
for i := 0 to Memo1.Count - 1 do
|
|
if OutLine(Memo1[i]) then
|
|
break;
|
|
|
|
{$IFDEF DebugLR}
|
|
DebugLn('CurStrNo=%d CurYf=%f Last"i"=%d',[CurStrNo, CurYf, i]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure OutMemo90;
|
|
var
|
|
i, th, curx: Integer;
|
|
oldFont: TFont;
|
|
rotatedFont: TFont;
|
|
|
|
procedure OutLine(str: String);
|
|
var
|
|
cury: Integer;
|
|
Ts: TTextStyle;
|
|
begin
|
|
SetLength(str, Length(str) - 2);
|
|
if str[Length(str)] = #1 then
|
|
SetLength(str, Length(str) - 1);
|
|
cury := 0;
|
|
|
|
Ts := Canvas.TextStyle;
|
|
Ts.Layout :=tlTop;
|
|
Ts.Alignment :=self.Alignment;
|
|
Ts.Wordbreak :=false;
|
|
Ts.SingleLine:=True;
|
|
Ts.Clipping :=True;
|
|
Canvas.TextStyle := Ts;
|
|
|
|
case Alignment of
|
|
Classes.taLeftJustify : CurY :=y + dy-gapy;
|
|
Classes.taRightJustify: CurY :=y + gapy + 1 + Canvas.TextWidth(str);
|
|
Classes.taCenter : CurY :=y + gapy + (dy + Canvas.TextWidth(str)) div 2;
|
|
end;
|
|
if not Exporting then
|
|
canvas.TextOut(curx,cury,str)
|
|
else
|
|
if Angle <> 0 then
|
|
CurReport.InternalOnExportText(CurX, CurY, str, Self)
|
|
else
|
|
CurReport.InternalOnExportText(CurX, Y, str, Self);
|
|
Inc(CurStrNo);
|
|
curx := curx + th;
|
|
end;
|
|
|
|
begin {OutMemo90}
|
|
rotatedFont := TFont.Create;
|
|
try
|
|
rotatedFont.assign(Canvas.Font);
|
|
rotatedFont.Orientation := 900;
|
|
oldFont := Canvas.Font;
|
|
Canvas.Font := rotatedFont;
|
|
if Alignment in [Classes.taLeftJustify..Classes.taCenter] then
|
|
begin
|
|
if Layout=tlCenter then
|
|
x := x +(dx-VHeight) div 2
|
|
else if Layout=tlBottom then
|
|
x:=x+dx-VHeight;
|
|
end;
|
|
curx := x + gapx;
|
|
th := -Canvas.Font.Height + Round(LineSpacing * ScaleY);
|
|
CurStrNo := 0;
|
|
for i := 0 to Memo1.Count - 1 do
|
|
OutLine(Memo1[i]);
|
|
finally
|
|
Canvas.Font := OldFont;
|
|
rotatedFont.Free
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrMemoView.ShowMemo INIT Font.Size=%d Canvas.Font.Size=%d',
|
|
[Font.Size, Canvas.Font.Size]);
|
|
{$ENDIF}
|
|
AssignFont(Canvas);
|
|
SavX:=X;
|
|
SavY:=Y;
|
|
Try
|
|
SetTextCharacterExtra(Canvas.Handle, Round(CharacterSpacing * ScaleX));
|
|
DR:=Rect(DRect.Left + 1, DRect.Top, DRect.Right - 2, DRect.Bottom - 1);
|
|
VHeight:=Round(VHeight*ScaleY);
|
|
|
|
if Angle <> 0 then
|
|
OutMemo90
|
|
else
|
|
OutMemo;
|
|
|
|
finally
|
|
X:=SavX;
|
|
Y:=SavY;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrMemoView.ShowMemo DONE Font.Size=%d Canvas.Font.Size=%d',[Font.Size, Canvas.Font.Size]);
|
|
{$ENDIF}
|
|
end;
|
|
(*
|
|
if (Adjust and $18) <> 0 then
|
|
begin
|
|
ad := Adjust;
|
|
ox := x;
|
|
oy := y;
|
|
Adjust := Adjust and $7;
|
|
if (ad and $4) <> 0 then
|
|
begin
|
|
if (ad and $18) = $8 then
|
|
x := x + (dx - VHeight) div 2
|
|
else if (ad and $18) = $10 then
|
|
x := x + dx - VHeight;
|
|
OutMemo90;
|
|
end
|
|
else
|
|
begin
|
|
if (ad and $18) = $8 then
|
|
y := y + (dy - VHeight) div 2
|
|
else if (ad and $18) = $10 then
|
|
y := y + dy - VHeight;
|
|
OutMemo;
|
|
end;
|
|
Adjust := ad;
|
|
x := ox; y := oy;
|
|
end
|
|
else if (Adjust and $4) <> 0 then
|
|
OutMemo90
|
|
else
|
|
OutMemo;
|
|
*)
|
|
end;
|
|
|
|
function TfrMemoView.CalcWidth(aMemo: TStringList): Integer;
|
|
var
|
|
CalcRect: TRect;
|
|
s: String;
|
|
n: Integer;
|
|
DTFlags: Cardinal;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrMemoView.CalcWidth INIT text=%s Font.PPI=%d Font.Size=%d dx=%d dy=%d',
|
|
[aMemo.Text,Font.PixelsPerInch,Font.Size,Dx,dy]);
|
|
{$ENDIF}
|
|
CalcRect := Rect(0, 0, dx, dy);
|
|
Canvas.Font.Assign(Font);
|
|
Canvas.Font.Height := -Round(Font.Size * 96 / 72);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Canvas.Font.PPI=%d Canvas.Font.Size=%d',[Canvas.Font.PixelsPerInch,Canvas.Font.Size]);
|
|
{$ENDIF}
|
|
DTFlags := DT_CALCRECT;
|
|
if Flags and flWordBreak <> 0 then
|
|
DTFlags := DT_CALCRECT or DT_WORDBREAK;
|
|
|
|
s := aMemo.Text;
|
|
n := Length(s);
|
|
if n > 2 then
|
|
if (s[n - 1] = #13) and (s[n] = #10) then
|
|
SetLength(s, n - 2);
|
|
SetTextCharacterExtra(Canvas.Handle, Round(CharacterSpacing * ScaleX));
|
|
DrawText(Canvas.Handle, PChar(s), Length(s), CalcRect, DTFlags);
|
|
Result := CalcRect.Right + Round(2 * FrameWidth) + 2;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrMemoView.CalcWidth DONE Width=%d Rect=%s',[Result,dbgs(CalcRect)]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrMemoView.Draw(aCanvas: TCanvas);
|
|
var
|
|
NeedWrap: Boolean;
|
|
newdx: Integer;
|
|
OldScaleX, OldScaleY: Double;
|
|
IsVisible: boolean;
|
|
begin
|
|
BeginDraw(aCanvas);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('');
|
|
DebuglnEnter('TfrMemoView.Draw: Name=%s Printing=%s Canvas.Font.PPI=%d',
|
|
[Name,dbgs(IsPrinting),Canvas.Font.PixelsPerInch]);
|
|
NewDx := 0;
|
|
{$ENDIF}
|
|
if ((Flags and flAutoSize) <> 0) and (Memo.Count > 0) and (DocMode <> dmDesigning) then
|
|
begin
|
|
newdx := CalcWidth(Memo);
|
|
|
|
if Alignment=Classes.taRightJustify then
|
|
begin
|
|
x := x + dx - newdx;
|
|
dx := newdx;
|
|
end
|
|
else
|
|
dx := newdx;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('NewDx=%d Dx=%d',[NewDx,dx]);
|
|
{$ENDIF}
|
|
Streaming := False;
|
|
Memo1.Assign(Memo);
|
|
|
|
OldScaleX := ScaleX;
|
|
OldScaleY := ScaleY;
|
|
ScaleX := 1;
|
|
ScaleY := 1;
|
|
CalcGaps;
|
|
ScaleX := OldScaleX;
|
|
ScaleY := OldScaleY;
|
|
RestoreCoord;
|
|
if Memo1.Count > 0 then
|
|
begin
|
|
NeedWrap := Pos(#1, Memo1.Text) = 0;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Memo1: Count=%d Text=%s NeedWrap=%s', [Memo1.Count,dbgstr(Memo1.text),dbgs(needwrap)]);
|
|
{$ENDIF}
|
|
if Memo1[Memo1.Count - 1] = #1 then
|
|
Memo1.Delete(Memo1.Count - 1);
|
|
|
|
if NeedWrap then
|
|
begin
|
|
WrapMemo;
|
|
Memo1.Assign(SMemo);
|
|
end;
|
|
end;
|
|
|
|
CalcGaps;
|
|
|
|
if Flags and flHideDuplicates <> 0 then
|
|
IsVisible := (flIsDuplicate and Flags = 0)
|
|
else
|
|
IsVisible := true;
|
|
|
|
if IsVisible then
|
|
begin
|
|
if not Exporting then ShowBackground;
|
|
if not Exporting then ShowFrame;
|
|
if Memo1.Count > 0 then
|
|
ShowMemo;
|
|
end;
|
|
|
|
RestoreCoord;
|
|
{$IFDEF DebugLR}
|
|
DebuglnExit('TfrMemoView.Draw: DONE',[]);
|
|
{$Endif}
|
|
end;
|
|
|
|
procedure TfrMemoView.Print(Stream: TStream);
|
|
var
|
|
St: String;
|
|
CanExpandVar: Boolean;
|
|
OldFont: TFont;
|
|
OldFill: Integer;
|
|
i: Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
WriteStr(St, DrawMode);
|
|
DebugLnEnter('TfrMemoView.Print INIT %s DrawMode=%s Visible=%s',[ViewInfoDIM(Self), st, dbgs(Visible)]);
|
|
{$ENDIF}
|
|
BeginDraw(TempBmp.Canvas);
|
|
Streaming := True;
|
|
if DrawMode = drAll then
|
|
frInterpretator.DoScript(Script);
|
|
|
|
CanExpandVar := True;
|
|
if (DrawMode = drAll) and (Assigned(CurReport.OnEnterRect) or
|
|
((FDataSet <> nil) and frIsBlob(TfrTField(FDataSet.FindField(FField))))) then
|
|
begin
|
|
Memo1.Assign(Memo);
|
|
St:=Memo1.Text;
|
|
CurReport.InternalOnEnterRect(Memo1, Self);
|
|
if St<>Memo1.Text then
|
|
CanExpandVar:= False;
|
|
end
|
|
else if DrawMode = drAfterCalcHeight then
|
|
CanExpandVar := False;
|
|
if DrawMode <> drPart then
|
|
if CanExpandVar then ExpandVariables;
|
|
|
|
if HideDuplicates then begin
|
|
if IsLastValueSet then
|
|
SetBit(Flags, FLastValue.Equals(Memo1), flIsDuplicate)
|
|
else
|
|
SetBit(Flags, false, flIsDuplicate);
|
|
IsLastValueSet := True;
|
|
end;
|
|
|
|
if not Visible then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrMemoView.Print EXIT Not Visible!');
|
|
{$ENDIF}
|
|
DrawMode := drAll;
|
|
Exit;
|
|
end;
|
|
|
|
OldFont := TFont.Create;
|
|
OldFont.Assign(Font);
|
|
OldFill := FillColor;
|
|
if Length(HighlightStr) <> 0 then
|
|
begin
|
|
if frParser.Calc(HighlightStr) <> 0 then
|
|
begin
|
|
Font.Style:= frSetFontStyle(Highlight.FontStyle);
|
|
Font.Color:= Highlight.FontColor;
|
|
fFillColor := Highlight.FillColor;
|
|
end;
|
|
end;
|
|
|
|
if (DrawMode = drPart) then
|
|
begin
|
|
CalcGaps;
|
|
Streaming:=False;
|
|
ShowMemo;
|
|
SMemo.Assign(Memo1);
|
|
while Memo1.Count > CurStrNo do
|
|
Memo1.Delete(CurStrNo);
|
|
if (Memo1.Count>0) and (Pos(#1, Memo1.Text) = 0) then
|
|
Memo1.Add(#1);
|
|
end;
|
|
|
|
Stream.Write(Typ, 1);
|
|
if Typ = gtAddIn then
|
|
frWriteString(Stream, ClassName);
|
|
|
|
SaveToStream(Stream);
|
|
|
|
if DrawMode = drPart then
|
|
begin
|
|
Memo1.Assign(SMemo);
|
|
for i := 0 to CurStrNo - 1 do
|
|
Memo1.Delete(0);
|
|
end;
|
|
|
|
Font.Assign(OldFont);
|
|
OldFont.Free;
|
|
fFillColor := OldFill;
|
|
DrawMode := drAll;
|
|
{$IFDEF DebugLR}
|
|
WriteStr(St, DrawMode);
|
|
DebugLnExit('TfrMemoView.Print DONE %s DrawMode=%s',[ViewInfo(Self), st]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrMemoView.ExportData;
|
|
begin
|
|
CurReport.InternalOnExportData(Self);
|
|
Exporting := True;
|
|
Draw(TempBmp.Canvas);
|
|
Exporting := False;
|
|
CurReport.InternalOnExported(Self);
|
|
end;
|
|
|
|
function TfrMemoView.CalcHeight: Integer;
|
|
var
|
|
s: String;
|
|
CanExpandVar: Boolean;
|
|
OldFont: TFont;
|
|
OldFill: Integer;
|
|
begin
|
|
Result := 0;
|
|
DrawMode := drAfterCalcHeight;
|
|
BeginDraw(TempBmp.Canvas);
|
|
frInterpretator.DoScript(Script);
|
|
if not Visible then Exit;
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrMemoView.CalcHeight %s INIT',[ViewInfo(Self)]);
|
|
{$ENDIF}
|
|
CanExpandVar := True;
|
|
Memo1.Assign(Memo);
|
|
s := Memo1.Text;
|
|
CurReport.InternalOnEnterRect(Memo1, Self);
|
|
if s <> Memo1.Text then CanExpandVar := False;
|
|
if CanExpandVar then ExpandVariables;
|
|
|
|
OldFont := TFont.Create;
|
|
OldFont.Assign(Font);
|
|
OldFill := FillColor;
|
|
if Length(HighlightStr) <> 0 then
|
|
if frParser.Calc(HighlightStr) <> 0 then
|
|
begin
|
|
Font.Style := frSetFontStyle(Highlight.FontStyle);
|
|
Font.Color := Highlight.FontColor;
|
|
fFillColor := Highlight.FillColor;
|
|
end;
|
|
if ((Flags and flAutoSize) <> 0) and (Memo1.Count > 0) and
|
|
(DocMode <> dmDesigning) then
|
|
dx := CalcWidth(Memo1);
|
|
|
|
CalcGaps;
|
|
if Memo1.Count <> 0 then
|
|
begin
|
|
WrapMemo;
|
|
Result := VHeight;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Memo1.Count<>0: VHeight=%d',[VHeight]);
|
|
{$ENDIF}
|
|
end;
|
|
Font.Assign(OldFont);
|
|
OldFont.Free;
|
|
fFillColor := OldFill;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrMemoView.CalcHeight DONE result=%d',[Result]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrMemoView.MinHeight: Integer;
|
|
begin
|
|
Result := TextHeight;
|
|
end;
|
|
|
|
function TfrMemoView.RemainHeight: Integer;
|
|
begin
|
|
Result := Memo1.Count * TextHeight;
|
|
end;
|
|
|
|
procedure TfrMemoView.LoadFromStream(Stream: TStream);
|
|
var
|
|
w: Word;
|
|
i: Integer;
|
|
tmpLayout: TTextLayout;
|
|
tmpAngle: Byte;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Stream.Position=%d Stream.Size=%d',[Stream.Position,Stream.Size]);
|
|
{$ENDIF}
|
|
|
|
inherited LoadFromStream(Stream);
|
|
Font.Name := ReadString(Stream);
|
|
with Stream do
|
|
begin
|
|
Read(i{%H-}, 4);
|
|
Font.Size := i;
|
|
Read(w{%H-}, 2);
|
|
Font.Style := frSetFontStyle(w);
|
|
Read(i, 4);
|
|
Font.Color := i;
|
|
if frVersion=23 then
|
|
Read(Adjust, 4);
|
|
Read(w, 2);
|
|
if frVersion < 23 then
|
|
w := frCharset;
|
|
Font.Charset := w;
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
Read(Highlight, 10);
|
|
HighlightStr := ReadString(Stream);
|
|
end;
|
|
if frVersion>23 then
|
|
begin
|
|
if LRE_OLDV25_FRF_READ then
|
|
begin
|
|
Read(i, 4);
|
|
tmpAngle := byte(i);
|
|
end else
|
|
Read(tmpAngle, SizeOf(tmpAngle));
|
|
Adjust := (Adjust and not 3) or (tmpAngle and %11);
|
|
Read(TmpLayout{%H-},SizeOf(TmpLayout));
|
|
tmpAngle := 0;
|
|
Read(tmpAngle,SizeOf(tmpAngle));
|
|
|
|
BeginUpdate;
|
|
Layout := tmpLayout;
|
|
Angle := tmpAngle;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
if frVersion = 21 then
|
|
Flags := Flags or flWordWrap;
|
|
end;
|
|
|
|
procedure TfrMemoView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
|
|
Font.Name := XML.GetValue(Path+'Font/Name/Value', 'Arial'); // todo chk
|
|
Font.Size := XML.GetValue(Path+'Font/Size/Value'{%H-}, 10); // todo chk
|
|
RestoreProperty('CharSet',XML.GetValue(Path+'Font/Charset/Value',''),Font);
|
|
RestoreProperty('Style',XML.GetValue(Path+'Font/Style/Value',''),Font);
|
|
Font.Color := StringToColor(XML.GetValue(Path+'Font/Color/Value','clBlack')); // todo chk
|
|
|
|
if StreamMode = smDesigning then begin
|
|
Highlight.FontStyle := XML.GetValue(Path+'Highlight/FontStyle/Value'{%H-}, 0); // todo chk
|
|
Highlight.FontColor := StringToColor(XML.GetValue(Path+'Highlight/FontColor/Value', 'clBlack'));
|
|
Highlight.FillColor := StringToColor(XML.GetValue(Path+'Highlight/FillColor/Value', 'clWhite'));
|
|
HighlightStr := XML.GetValue(Path+'Highlight/HighlightStr/Value', HighlightStr);
|
|
end;
|
|
|
|
RestoreProperty('Alignment',XML.GetValue(Path+'Alignment/Value',''));
|
|
RestoreProperty('Layout',XML.GetValue(Path+'Layout/Value',''));
|
|
Angle := XML.GetValue(Path+'Angle/Value'{%H-}, 0);
|
|
Justify := XML.GetValue(Path+'Justify/Value', false);
|
|
end;
|
|
|
|
procedure TfrMemoView.SaveToStream(Stream: TStream);
|
|
var
|
|
i: Integer;
|
|
w: Word;
|
|
tmpLayout: TTextLayout;
|
|
tmpAngle: Byte;
|
|
tmpByteAlign: Byte;
|
|
begin
|
|
inherited SaveToStream(Stream);
|
|
frWriteString(Stream, Font.Name);
|
|
with Stream do
|
|
begin
|
|
i := Font.Size;
|
|
Write(i, 4);
|
|
w := frGetFontStyle(Font.Style);
|
|
Write(w, 2);
|
|
i := Font.Color;
|
|
Write(i, 4);
|
|
w := Font.Charset;
|
|
Write(w, 2);
|
|
if StreamMode = smDesigning then
|
|
begin
|
|
Write(Highlight, 10);
|
|
frWriteString(Stream, HighlightStr);
|
|
end;
|
|
|
|
tmpByteAlign := Adjust and %11;
|
|
tmpLayout := Layout;
|
|
tmpAngle := Angle;
|
|
Write(tmpByteAlign, SizeOf(tmpByteAlign));
|
|
Write(tmpLayout,SizeOf(tmpLayout));
|
|
Write(tmpAngle,SizeOf(tmpAngle));
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited SaveToXML(XML, Path);
|
|
XML.SetValue(Path+'Font/Name/Value', Font.name);
|
|
XML.SetValue(Path+'Font/Size/Value'{%H-}, Font.Size);
|
|
XML.SetValue(Path+'Font/Color/Value', ColorToString(Font.Color));
|
|
XML.SetValue(Path+'Font/Charset/Value', GetSaveProperty('CharSet',Font));
|
|
XML.SetValue(Path+'Font/Style/Value', GetSaveProperty('Style',Font));
|
|
|
|
if StreamMode=smDesigning then
|
|
begin
|
|
XML.SetValue(Path+'Highlight/FontStyle/Value'{%H-}, HighLight.FontStyle);
|
|
XML.SetValue(Path+'Highlight/FontColor/Value', ColorToString(Highlight.FontColor));
|
|
XML.SetValue(Path+'Highlight/FillColor/Value', ColorToString(Highlight.FillColor));
|
|
XML.SetValue(Path+'Highlight/HighlightStr/Value', HighlightStr);
|
|
end;
|
|
XML.SetValue(Path+'Alignment/Value',GetSaveProperty('Alignment'));
|
|
XML.SetValue(Path+'Layout/Value', GetSaveProperty('Layout'));
|
|
XML.SetValue(Path+'Angle/Value'{%H-}, Angle);
|
|
XML.SetValue(Path+'Justify/Value', Justify);
|
|
end;
|
|
|
|
procedure TfrMemoView.GetBlob(b: TfrTField);
|
|
var
|
|
M: TMemoryStream;
|
|
begin
|
|
// todo: TBLobField.AssignTo is not implemented yet
|
|
// even if I supply a patch for 2.0.4 it will
|
|
// not be integrated because it's in RC1 now
|
|
// (I guess)
|
|
//
|
|
//Memo1.Assign(b);
|
|
M := TMemoryStream.Create;
|
|
try
|
|
TBlobField(B).SaveToStream(M);
|
|
M.Position := 0;
|
|
Memo1.LoadFromStream(M);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.FontChange(sender: TObject);
|
|
begin
|
|
AfterChange;
|
|
end;
|
|
|
|
procedure TfrMemoView.ResetLastValue;
|
|
begin
|
|
IsLastValueSet := False;
|
|
end;
|
|
|
|
procedure TfrMemoView.DefinePopupMenu(Popup: TPopupMenu);
|
|
var
|
|
m: TMenuItem;
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sVarFormat;
|
|
m.OnClick := @P1Click;
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sFont;
|
|
m.OnClick := @P4Click;
|
|
Popup.Items.Add(m);
|
|
inherited DefinePopupMenu(Popup);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sWordWrap;
|
|
m.OnClick := @P2Click;
|
|
m.Checked := WordWrap;
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sWordBreak;
|
|
m.OnClick := @P3Click;
|
|
m.Enabled := WordWrap;
|
|
if m.Enabled then
|
|
m.Checked := WordBreak;
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sAutoSize;
|
|
m.OnClick := @P5Click;
|
|
m.Checked := AutoSize;
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sHideZeroValues;
|
|
m.OnClick := @P6Click;
|
|
m.Checked := HideZeroValues;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
procedure TfrMemoView.MonitorFontChanges;
|
|
begin
|
|
FFont.OnChange:= @FontChange;
|
|
end;
|
|
|
|
procedure TfrMemoView.P1Click(Sender: TObject);
|
|
var
|
|
t: TfrView;
|
|
i: Integer;
|
|
begin
|
|
BeforeChange;
|
|
frFmtForm := TfrFmtForm.Create(nil);
|
|
try
|
|
with frFmtForm do
|
|
begin
|
|
EdFormat := Self.Format;
|
|
EdFormatStr := Self.FormatStr;
|
|
if ShowModal = mrOk then
|
|
begin
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t := TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
begin
|
|
(t as TfrMemoView).Format := EdFormat;
|
|
(t as TfrMemoView).FormatStr := EdFormatStr;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
frFmtForm.Free;
|
|
AfterChange
|
|
end;
|
|
end;
|
|
|
|
function TfrMemoView.GetAutoSize: Boolean;
|
|
begin
|
|
Result:=((Flags and flAutoSize)<>0);
|
|
end;
|
|
|
|
function TfrMemoView.GetHideDuplicates: Boolean;
|
|
begin
|
|
result:=((Flags and flHideDuplicates)<>0);
|
|
end;
|
|
|
|
function TfrMemoView.GetHideZeroValues: Boolean;
|
|
begin
|
|
Result:=((Flags and flHideZeros)<>0);
|
|
end;
|
|
|
|
function TfrMemoView.GetIsLastValueSet: boolean;
|
|
begin
|
|
result := FLastValue<>nil;
|
|
end;
|
|
|
|
function TfrMemoView.GetJustify: boolean;
|
|
begin
|
|
result := (Adjust and %11) = %11;
|
|
end;
|
|
|
|
function TfrMemoView.GetLayout: TTextLayout;
|
|
begin
|
|
result := TTextLayout((adjust shr 3) and %11);
|
|
end;
|
|
|
|
function TfrMemoView.GetWordBreak: Boolean;
|
|
begin
|
|
Result := ((Flags and flWordBreak)<>0);
|
|
end;
|
|
|
|
function TfrMemoView.GetAlignment: TAlignment;
|
|
begin
|
|
if (Adjust and %11) = %11 then
|
|
result := taLeftJustify
|
|
else
|
|
Result:=Classes.TAlignment(Adjust and %11);
|
|
end;
|
|
|
|
function TfrMemoView.GetAngle: Byte;
|
|
begin
|
|
if Adjust and 4 <> 0 then
|
|
Result := 90
|
|
else
|
|
Result := 0
|
|
end;
|
|
|
|
function TfrMemoView.GetWordWrap: Boolean;
|
|
begin
|
|
Result:=((Flags and flWordWrap)<>0);
|
|
end;
|
|
|
|
procedure TfrMemoView.P2Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flWordWrap);
|
|
end;
|
|
|
|
procedure TfrMemoView.P3Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flWordBreak);
|
|
end;
|
|
|
|
procedure TfrMemoView.P4Click(Sender: TObject);
|
|
var
|
|
t: TfrView;
|
|
i: Integer;
|
|
fd: TFontDialog;
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
fd := TFontDialog.Create(nil);
|
|
with fd do
|
|
begin
|
|
Font.Assign(Self.Font);
|
|
if Execute then
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
begin
|
|
if Font.Name <> Self.Font.Name then
|
|
TfrMemoView(t).Font.Name := Font.Name;
|
|
if Font.Size <> Self.Font.Size then
|
|
TfrMemoView(t).Font.Size := Font.Size;
|
|
if Font.Color <> Self.Font.Color then
|
|
TfrMemoView(t).Font.Color := Font.Color;
|
|
if Font.Style <> Self.Font.Style then
|
|
TfrMemoView(t).Font.Style := Font.Style;
|
|
if Font.Charset <> Self.Font.Charset then
|
|
TfrMemoView(t).Font.Charset := Font.Charset;
|
|
end;
|
|
end;
|
|
end;
|
|
fd.Free;
|
|
frDesigner.AfterChange;
|
|
end;
|
|
|
|
procedure TfrMemoView.P5Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flAutoSize);
|
|
end;
|
|
|
|
procedure TfrMemoView.P6Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flHideZeros);
|
|
end;
|
|
|
|
procedure TfrMemoView.SetAlignment(const AValue: TAlignment);
|
|
var
|
|
b: byte;
|
|
begin
|
|
if Alignment<>AValue then
|
|
begin
|
|
BeforeChange;
|
|
// just in case, check for crazy value stored by alignment=justify
|
|
// in previous versions.
|
|
b := byte(AValue) and %11;
|
|
Adjust := (Adjust and not 3) or b;
|
|
AfterChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetAngle(const AValue: Byte);
|
|
begin
|
|
if AValue <> Angle then
|
|
begin
|
|
BeforeChange;
|
|
if AValue <> 0 then
|
|
Adjust := Adjust or $04
|
|
else
|
|
Adjust := Adjust and $FB;
|
|
AfterChange
|
|
end;
|
|
end;
|
|
|
|
procedure TfrMemoView.SetAutoSize(const AValue: Boolean);
|
|
begin
|
|
if AutoSize<>AValue then
|
|
ModifyFlag(flAutoSize, AValue);
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrBandView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtBand;
|
|
fFormat := 0;
|
|
BaseName := 'Band';
|
|
Flags := flBandOnFirstPage + flBandOnLastPage;
|
|
end;
|
|
|
|
procedure TfrBandView.Assign(From: TfrView);
|
|
begin
|
|
inherited Assign(From);
|
|
if From is TfrBandView then
|
|
begin
|
|
BandType := TFrBandView(From).BandType;
|
|
DataSet := TFrBandView(From).DataSet;
|
|
GroupCondition:=TFrBandView(From).GroupCondition;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.LoadFromStream(Stream: TStream);
|
|
begin
|
|
inherited LoadFromStream(Stream);
|
|
|
|
With Stream do
|
|
if frVersion>23 then begin
|
|
Read(fBandType,SizeOf(BandType));
|
|
fCondition :=ReadString(Stream);
|
|
fDataSetStr:=ReadString(Stream);
|
|
end else
|
|
begin
|
|
if StreamMode=smDesigning then begin
|
|
fBandType := TfrBandType(fFrameTyp);
|
|
fCondition := FormatStr;
|
|
fDatasetStr := FormatStr;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
RestoreProperty('BandType',XML.GetValue(Path+'BandType/Value','')); // todo chk
|
|
FCondition := XML.GetValue(Path+'Condition/Value', ''); // todo chk
|
|
FDatasetStr := XML.GetValue(Path+'DatasetStr/Value', ''); // todo chk
|
|
end;
|
|
|
|
procedure TfrBandView.SaveToStream(Stream: TStream);
|
|
begin
|
|
inherited SaveToStream(Stream);
|
|
|
|
with Stream do
|
|
begin
|
|
Write(fBandType,SizeOf(fBandType));
|
|
frWriteString(Stream, fCondition);
|
|
frWriteString(Stream, fDataSetStr);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited SaveToXML(XML, Path);
|
|
XML.SetValue(Path+'BandType/Value', GetSaveProperty('BandType')); //Ord(FBandType)); // todo: use symbolic values
|
|
XML.SetValue(Path+'Condition/Value', FCondition);
|
|
XML.SetValue(Path+'DatasetStr/Value', FDatasetStr);
|
|
end;
|
|
|
|
procedure TfrBandView.Draw(aCanvas: TCanvas);
|
|
var
|
|
St : String;
|
|
R : TRect;
|
|
begin
|
|
fFrameWidth := 1;
|
|
if BandType in [btCrossHeader..btCrossFooter] then
|
|
begin
|
|
y := 0;
|
|
dy := frDesigner.Page.PrnInfo.Pgh;
|
|
end
|
|
else
|
|
begin
|
|
x := 0;
|
|
dx := frDesigner.Page.PrnInfo.Pgw;
|
|
end;
|
|
BeginDraw(aCanvas);
|
|
CalcGaps;
|
|
with Canvas do
|
|
begin
|
|
//Brush.Bitmap := SBmp;
|
|
Brush.Bitmap := nil;
|
|
Brush.Style := bsSolid;
|
|
Brush.Color:=clBtnFace;
|
|
FillRect(DRect);
|
|
Brush.Color:=clLtGray;
|
|
Brush.Style:=bsDiagCross;
|
|
FillRect(DRect);
|
|
frInitFont(Font,clBlack,8,[]);
|
|
Pen.Width := 1;
|
|
Pen.Color := clBtnFace;
|
|
Pen.Style := psSolid;
|
|
Brush.Style := bsClear;
|
|
Rectangle(x, y, x + dx + 1, y + dy + 1);
|
|
Brush.Color := clBtnFace;
|
|
Brush.Style := bsSolid;
|
|
CalcTitleSize;
|
|
R := GetTitleRect;
|
|
if ShowBandTitles then
|
|
begin
|
|
FillRect(R);
|
|
if BandType in [btCrossHeader..btCrossFooter] then
|
|
begin
|
|
Pen.Color := clBtnShadow;
|
|
MoveTo(r.left, r.Bottom-2); LineTo(r.right, r.Bottom-2);
|
|
Pen.Color := clBlack;
|
|
MoveTo(r.left, r.Bottom-1); LineTo(r.right, r.Bottom-1);
|
|
Pen.Color := clBtnHighlight;
|
|
MoveTo(r.left, r.bottom-1); lineto(r.left, r.top);
|
|
Font.Orientation := 900;
|
|
Brush.Color:=clBtnFace;
|
|
TextOut(r.Left + 3, r.bottom-6, frBandNames[BandType]);
|
|
end
|
|
else
|
|
begin
|
|
Pen.Color := clBtnShadow;
|
|
MoveTo(r.Right-2, r.Top);
|
|
LineTo(r.Right-2, r.Bottom);
|
|
Pen.Color := clBlack;
|
|
MoveTo(r.Right-1, r.Top);
|
|
LineTo(r.Right-1, r.Bottom);
|
|
st:=frBandNames[BandType];
|
|
Font.Orientation := 0;
|
|
Brush.Color:=clBtnFace;
|
|
TextOut(r.left+5, r.top+1, st);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Brush.Style := bsClear;
|
|
if BandType in [btCrossHeader..btCrossFooter] then
|
|
begin
|
|
Font.Orientation := 900;
|
|
Brush.Color:=clBtnFace;
|
|
TextOut(x + 2, r.bottom-6, frBandNames[BandType]);
|
|
end
|
|
else
|
|
begin
|
|
Font.Orientation := 0;
|
|
Brush.Color:=clBtnFace;
|
|
TextOut(x + 4, y + 2, frBandNames[BandType]);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrBandView.GetClipRgn(rt: TfrRgnType): HRGN;
|
|
var
|
|
R,R1,R2: HRGN;
|
|
begin
|
|
if not ShowBandTitles then
|
|
begin
|
|
Result := inherited GetClipRgn(rt);
|
|
Exit;
|
|
end;
|
|
|
|
if rt = rtNormal then
|
|
R1 := CreateRectRgn(x, y, x + dx + 1, y + dy + 1)
|
|
else
|
|
R1 := CreateRectRgn(x - 10, y - 10, x + dx + 10, y + dy + 10);
|
|
|
|
with GetTitleRect do
|
|
R := CreateRectRgn(Left,Top,Right,Bottom);
|
|
|
|
R2:=CreateRectRgn(0,0,0,0);
|
|
|
|
CombineRgn(R2, R, R1, RGN_OR);
|
|
Result:=R2;
|
|
|
|
|
|
DeleteObject(R);
|
|
DeleteObject(R1);
|
|
end;
|
|
|
|
function TfrBandView.PointInView(aX,aY: Integer): Boolean;
|
|
var
|
|
Rc : TRect;
|
|
begin
|
|
Rc:=Bounds(x, y,dx+1,dy + 1);
|
|
Result:=((aX>Rc.Left) and (aX<Rc.Right) and (aY>Rc.Top) and (aY<Rc.Bottom));
|
|
{$IFDEF DebugLR}
|
|
DebugLn('PointInView, Bounds=%s Point=%d,%d Res=%s',[dbgs(rc),ax,ay,BoolToStr(result)]);
|
|
{$ENDIF}
|
|
|
|
if not Result and ShowBandTitles then
|
|
begin
|
|
Rc := GetTitleRect;
|
|
Result := PtInRect(Rc, Point(Ax,Ay));
|
|
{$IFDEF DebugLR}
|
|
DebugLn('PointInView, TitleRect=%s Point=%d,%d Res=%s',[dbgs(rc),ax,ay,BoolToStr(result)]);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.DefinePopupMenu(Popup: TPopupMenu);
|
|
var
|
|
m: TMenuItem;
|
|
begin
|
|
if BandType in [btReportTitle, btReportSummary, btPageHeader, btCrossHeader,
|
|
btMasterHeader..btSubDetailFooter, btGroupHeader, btGroupFooter] then
|
|
inherited DefinePopupMenu(Popup);
|
|
|
|
if BandType in [btReportTitle, btReportSummary, btMasterData, btDetailData,
|
|
btSubDetailData, btMasterFooter, btDetailFooter,
|
|
btSubDetailFooter, btGroupHeader] then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sFormNewPage;
|
|
m.OnClick := @P1Click;
|
|
m.Checked := (Flags and flBandNewPageAfter) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
if BandType in [btMasterData, btDetailData] then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sPrintIfSubsetEmpty;
|
|
m.OnClick := @P2Click;
|
|
m.Checked := (Flags and flBandPrintIfSubsetEmpty) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
if BandType in [btReportTitle, btReportSummary, btMasterHeader..btSubDetailFooter,
|
|
btGroupHeader, btGroupFooter] then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sBreaked;
|
|
m.OnClick := @P3Click;
|
|
m.Checked := (Flags and flBandPageBreak) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
if BandType in [btPageHeader, btPageFooter] then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sOnFirstPage;
|
|
m.OnClick := @P4Click;
|
|
m.Checked := (Flags and flBandOnFirstPage) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
if BandType = btPageFooter then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sOnLastPage;
|
|
m.OnClick := @P5Click;
|
|
m.Checked := (Flags and flBandOnLastPage) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
if BandType in [btMasterHeader, btDetailHeader, btSubDetailHeader,
|
|
btCrossHeader, btGroupHeader] then
|
|
begin
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sRepeatHeader;
|
|
m.OnClick := @P6Click;
|
|
m.Checked := (Flags and flBandRepeatHeader) <> 0;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P1Click(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
t.Flags := (t.Flags and not flBandNewPageAfter) +
|
|
Word(Checked) * flBandNewPageAfter;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P2Click(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
t.Flags := (t.Flags and not flBandPrintifSubsetEmpty) +
|
|
Word(Checked) * flBandPrintifSubsetEmpty;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P3Click(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
for i := 0 to frDesigner.Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(frDesigner.Page.Objects[i]);
|
|
if t.Selected then
|
|
t.Flags := (t.Flags and not flBandPageBreak) + Word(Checked) * flBandPageBreak;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P4Click(Sender: TObject);
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
Flags := (Flags and not flBandOnFirstPage) + Word(Checked) * flBandOnFirstPage;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P5Click(Sender: TObject);
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
Flags := (Flags and not flBandOnLastPage) + Word(Checked) * flBandOnLastPage;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBandView.P6Click(Sender: TObject);
|
|
begin
|
|
frDesigner.BeforeChange;
|
|
with Sender as TMenuItem do
|
|
begin
|
|
Checked := not Checked;
|
|
Flags := (Flags and not flBandRepeatHeader) + Word(Checked) * flBandRepeatHeader;
|
|
end;
|
|
end;
|
|
|
|
function TfrBandView.GetTitleRect: TRect;
|
|
begin
|
|
if BandType in [btCrossHeader..btCrossFooter] then
|
|
result := rect(x - 18, y, x, y + TitleSize + 10)
|
|
else
|
|
result := rect(x, y-18, x + TitleSize + 10, y);
|
|
end;
|
|
|
|
function TfrBandView.TitleSize: Integer;
|
|
begin
|
|
if MaxTitleSize<100 then
|
|
result := 100
|
|
else
|
|
result := MaxTitleSize;
|
|
end;
|
|
|
|
procedure TfrBandView.CalcTitleSize;
|
|
var
|
|
Bt: TfrBandType;
|
|
W: Integer;
|
|
begin
|
|
if MaxTitleSize=0 then begin
|
|
MaxTitleSize := Canvas.TextWidth('-'); // work around gtk2 first calc is not right
|
|
for bt := btReportTitle to btNone do begin
|
|
W := Canvas.TextWidth(frBandNames[bt]);
|
|
if W>MaxTitleSize then
|
|
MaxTitleSize := W;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrSubReportView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtSubReport;
|
|
BaseName := 'SubReport';
|
|
end;
|
|
|
|
procedure TfrSubReportView.Assign(From: TfrView);
|
|
begin
|
|
inherited Assign(From);
|
|
SubPage := (From as TfrSubReportView).SubPage;
|
|
end;
|
|
|
|
procedure TfrSubReportView.Draw(aCanvas: TCanvas);
|
|
begin
|
|
BeginDraw(aCanvas);
|
|
fFrameWidth := 1;
|
|
CalcGaps;
|
|
with aCanvas do
|
|
begin
|
|
Font.Name := 'Arial';
|
|
Font.Style := [];
|
|
Font.Size := 8;
|
|
Font.Color := clBlack;
|
|
Font.Charset := frCharset;
|
|
Pen.Width := 1;
|
|
Pen.Color := clBlack;
|
|
Pen.Style := psSolid;
|
|
Brush.Color := clWhite;
|
|
Rectangle(x, y, x + dx + 1, y + dy + 1);
|
|
Brush.Style := bsClear;
|
|
TextRect(DRect, x + 2, y + 2, sSubReportOnPage + ' ' +
|
|
IntToStr(SubPage + 1));
|
|
end;
|
|
RestoreCoord;
|
|
end;
|
|
|
|
procedure TfrSubReportView.DefinePopupMenu(Popup: TPopupMenu);
|
|
begin
|
|
// no specific items in popup menu
|
|
end;
|
|
|
|
procedure TfrSubReportView.LoadFromStream(Stream: TStream);
|
|
begin
|
|
inherited LoadFromStream(Stream);
|
|
Stream.Read(SubPage, 4);
|
|
end;
|
|
|
|
procedure TfrSubReportView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
SubPage := XML.GetValue(Path+'SubPage/Value'{%H-}, 0); // todo chk
|
|
end;
|
|
|
|
procedure TfrSubReportView.SaveToStream(Stream: TStream);
|
|
begin
|
|
inherited SaveToStream(Stream);
|
|
Stream.Write(SubPage, 4);
|
|
end;
|
|
|
|
procedure TfrSubReportView.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited SaveToXML(XML, Path);
|
|
XML.SetValue(Path+'SubPage/Value'{%H-}, SubPage);
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrPictureView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtPicture;
|
|
fPicture := TPicture.Create;
|
|
Flags := flStretched + flPictRatio;
|
|
BaseName := 'Picture';
|
|
end;
|
|
|
|
destructor TfrPictureView.Destroy;
|
|
begin
|
|
Picture.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrPictureView.Assign(From: TfrView);
|
|
begin
|
|
inherited Assign(From);
|
|
Picture.Assign(TfrPictureView(From).Picture);
|
|
FSharedName := TFrPictureView(From).SharedName;
|
|
end;
|
|
|
|
procedure TfrPictureView.Draw(aCanvas: TCanvas);
|
|
var
|
|
r: TRect;
|
|
kx, ky: Double;
|
|
w, h, w1, h1, PictureHeight, PictureWidth: Integer;
|
|
ClipRgn, PreviousClipRgn: HRGN;
|
|
ClipNeeded: Boolean;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrPictureView.Draw INI');
|
|
{$ENDIF}
|
|
BeginDraw(aCanvas);
|
|
CalcGaps;
|
|
w := DRect.Right - DRect.Left - 1;
|
|
h := DRect.Bottom - DRect.Top - 1;
|
|
with aCanvas do
|
|
begin
|
|
ShowBackground;
|
|
if ((Picture.Graphic = nil) or Picture.Graphic.Empty) and (DocMode = dmDesigning) then
|
|
begin
|
|
Font.Name := 'Arial';
|
|
Font.Size := 8;
|
|
Font.Style := [];
|
|
Font.Color := clBlack;
|
|
Font.Charset := frCharset;
|
|
TextOut(x + 2, y + 2, sPicture);
|
|
end
|
|
else if not ((Picture.Graphic = nil) or Picture.Graphic.Empty) then
|
|
begin
|
|
r := DRect;
|
|
Dec(r.Bottom);
|
|
Dec(r.Right);
|
|
if (Flags and flStretched) <> 0 then
|
|
begin
|
|
if (Flags and flPictRatio) <> 0 then
|
|
begin
|
|
kx := dx / Picture.Width;
|
|
ky := dy / Picture.Height;
|
|
if kx < ky then
|
|
r.Bottom := r.Top + Round(Picture.Height * kx)
|
|
else
|
|
r.Right := r.Left + Round(Picture.Width * ky);
|
|
w1 := r.Right - r.Left;
|
|
h1 := r.Bottom - r.Top;
|
|
if (Flags and flPictCenter) <> 0 then
|
|
OffsetRect(r, (w - w1) div 2, (h - h1) div 2);
|
|
end;
|
|
StretchDraw(r, Picture.Graphic);
|
|
end
|
|
else
|
|
begin
|
|
PictureWidth := Round(Picture.Width * ScaleX);
|
|
PictureHeight := Round(Picture.Height * ScaleY);
|
|
if (Flags and flPictCenter) <> 0 then
|
|
OffsetRect(r, (w - PictureWidth) div 2, (h - PictureHeight) div 2);
|
|
ClipNeeded := (PictureHeight > h) or (PictureWidth > w);
|
|
if ClipNeeded then
|
|
begin
|
|
ClipRgn := CreateRectRgn(r.Left, r.Top, r.Right, r.Bottom);
|
|
PreviousClipRgn := CreateRectRgn(0, 0, 0, 0);
|
|
LCLIntf.GetClipRgn(Handle, PreviousClipRgn);
|
|
SelectClipRgn(Handle, ClipRgn);
|
|
end;
|
|
r.Right := r.Left + PictureWidth;
|
|
r.Bottom := r.Top + PictureHeight;
|
|
StretchDraw(r, Picture.Graphic);
|
|
if ClipNeeded then
|
|
begin
|
|
SelectClipRGN(Handle, PreviousClipRgn);
|
|
DeleteObject(PreviousClipRgn);
|
|
DeleteObject(ClipRgn);
|
|
end;
|
|
end;
|
|
end;
|
|
ShowFrame;
|
|
end;
|
|
RestoreCoord;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrPictureView.Draw DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
const
|
|
pkNone = 0;
|
|
pkBitmap = 1;
|
|
pkMetafile = 2;
|
|
pkIcon = 3;
|
|
pkJPEG = 4;
|
|
pkPNG = 5;
|
|
pkAny = 255;
|
|
|
|
procedure StreamToXML(XML: TLrXMLConfig; Path: String; Stream: TStream);
|
|
var
|
|
Buf: array[0..1023] of byte;
|
|
S: string;
|
|
i,c: integer;
|
|
procedure WriteBuf(Count: Integer);
|
|
var
|
|
j: Integer;
|
|
St: string[3];
|
|
begin
|
|
for j:=0 to Count-1 do begin
|
|
St := IntToHex(Buf[j], 2);
|
|
Move(St[1], S[C], 2);
|
|
inc(c,2);
|
|
end;
|
|
end;
|
|
begin
|
|
XML.SetValue(Path+'Size/Value'{%H-}, Stream.Size);
|
|
SetLength(S, Stream.Size*2);
|
|
c := 1;
|
|
for i:=1 to Stream.Size div SizeOf(Buf) do begin
|
|
Stream.Read(Buf{%H-}, SizeOf(buf));
|
|
WriteBuf(SizeOf(Buf));
|
|
end;
|
|
i := Stream.Size mod SizeOf(Buf);
|
|
if i>0 then begin
|
|
Stream.Read(Buf, i);
|
|
Writebuf(i);
|
|
end;
|
|
XML.SetValue(Path+'Data/Value', S);
|
|
end;
|
|
|
|
procedure XMLToStream(XML: TLrXMLConfig; Path: String; Stream: TStream);
|
|
var
|
|
S: String;
|
|
i,Size,{%H-}cd: integer;
|
|
B: Byte;
|
|
begin
|
|
Size := XML.GetValue(Path+'Size/Value'{%H-}, 0);
|
|
if Size>0 then begin
|
|
S := XML.GetValue(Path+'Data/Value', '');
|
|
if S<>'' then
|
|
for i:=1 to Size do begin
|
|
Val('$'+S[i*2-1]+S[i*2], B, cd);
|
|
Stream.Write(B, 1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPictureView.LoadFromStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
n: Integer;
|
|
Graphic: TGraphic;
|
|
begin
|
|
inherited LoadFromStream(Stream);
|
|
b := 0;
|
|
Stream.Read(b, 1);
|
|
|
|
if frVersion<=23 then
|
|
begin
|
|
n := 0;
|
|
Stream.Read(n, 4);
|
|
Graphic := PictureTypeToGraphic(b);
|
|
if b=pkMetafile then
|
|
raise exception.Create('LazReport does not support TMetafile');
|
|
end else
|
|
begin
|
|
if b=pkAny then
|
|
Graphic := ExtensionToGraphic(Stream.ReadAnsiString)
|
|
else
|
|
Graphic := PictureTypeToGraphic(b);
|
|
FSharedName := Stream.ReadAnsiString;
|
|
n := 0;
|
|
Stream.Read(n, 4);
|
|
end;
|
|
|
|
Picture.Graphic := Graphic;
|
|
if Graphic <> nil then
|
|
begin
|
|
Graphic.Free;
|
|
Picture.Graphic.LoadFromStream(Stream);
|
|
end;
|
|
Stream.Seek(n, soFromBeginning);
|
|
end;
|
|
|
|
procedure TfrPictureView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
b: Byte;
|
|
m: TMemoryStream;
|
|
Graphic: TGraphic;
|
|
Ext: string;
|
|
|
|
procedure GetPictureStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
XMLToStream(XML, Path+'Picture/', M);
|
|
except
|
|
M.Free;
|
|
M := nil;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
|
|
SharedName := XML.GetValue(Path+'Picture/SharedName/Value','');
|
|
b := XML.GetValue(Path+'Picture/Type/Value'{%H-}, pkNone);
|
|
Ext := XML.GetValue(Path+'Picture/Type/Ext', '');
|
|
|
|
M := nil;
|
|
if (b=pkAny) and (Ext<>'') then
|
|
Graphic := ExtensionToGraphic(Ext)
|
|
else
|
|
if (b>pkBitmap) and (b<pkAny) then
|
|
Graphic := PictureTypeToGraphic(b)
|
|
else begin
|
|
GetPictureStream;
|
|
Graphic := StreamToGraphic(M);
|
|
end;
|
|
|
|
Picture.Graphic := Graphic;
|
|
try
|
|
if Graphic <> nil then
|
|
begin
|
|
Graphic.Free;
|
|
if M=nil then
|
|
GetPictureStream;
|
|
try
|
|
M.Position := 0;
|
|
Picture.Graphic.LoadFromStream(M);
|
|
except
|
|
ShowMessage('Unknown Image Format!');
|
|
end;
|
|
end;
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPictureView.SaveToStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
n, o: Integer;
|
|
ext: string;
|
|
begin
|
|
inherited SaveToStream(Stream);
|
|
|
|
b := GetPictureType;
|
|
Stream.Write(b, 1);
|
|
if b<>pkNone then
|
|
begin
|
|
ext := GraphicExtension(TGraphicClass(Picture.Graphic.ClassType));
|
|
Stream.WriteAnsiString(ext);
|
|
end;
|
|
Stream.WriteAnsiString(FSharedName);
|
|
n := Stream.Position;
|
|
Stream.Write(n, 4);
|
|
if b <> pkNone then
|
|
Picture.Graphic.SaveToStream(Stream);
|
|
o := Stream.Position;
|
|
Stream.Seek(n, soFromBeginning);
|
|
Stream.Write(o, 4);
|
|
Stream.Seek(0, soFromEnd);
|
|
end;
|
|
|
|
procedure TfrPictureView.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
b: Byte;
|
|
m: TMemoryStream;
|
|
begin
|
|
inherited SaveToXML(XML, Path);
|
|
b := GetPictureType;
|
|
|
|
XML.SetValue(Path+'Picture/SharedName/Value', SharedName);
|
|
XML.SetValue(Path+'Picture/Type/Value'{%H-}, b);
|
|
if b <> pkNone then
|
|
begin
|
|
XML.SetValue(Path+'Picture/Type/Ext',
|
|
GraphicExtension(TGraphicClass(Picture.Graphic.ClassType)));
|
|
M := TMemoryStream.Create;
|
|
try
|
|
Picture.Graphic.SaveToStream(M);
|
|
M.Position:=0;
|
|
StreamToXML(XML, Path+'Picture/', M);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPictureView.GetBlob(b: TfrTField);
|
|
var
|
|
s: TStream;
|
|
GraphExt: string;
|
|
gc: TGraphicClass;
|
|
AGraphic: TGraphic;
|
|
CurPos: Int64;
|
|
|
|
function LoadImageFromStream: boolean;
|
|
begin
|
|
result := (s<>nil);
|
|
if result then
|
|
try
|
|
curPos := s.Position;
|
|
Picture.LoadFromStream(s);
|
|
except
|
|
s.Position := Curpos;
|
|
result := false;
|
|
end;
|
|
end;
|
|
|
|
procedure GraphExtToClass;
|
|
begin
|
|
gc := GetGraphicClassForFileExtension(GraphExt);
|
|
end;
|
|
|
|
procedure ReadImageHeader;
|
|
begin
|
|
CurPos := s.Position;
|
|
try
|
|
GraphExt := s.ReadAnsiString;
|
|
except
|
|
s.Position := CurPos;
|
|
GraphExt := '';
|
|
end;
|
|
GraphExtToClass;
|
|
if gc=nil then
|
|
s.Position := CurPos;
|
|
end;
|
|
|
|
begin
|
|
|
|
Picture.Clear;
|
|
|
|
if b.IsNull then
|
|
exit;
|
|
|
|
// todo: TBlobField.AssignTo is not implemented yet
|
|
s := TDataset(FDataSet).CreateBlobStream(TField(b),bmRead);
|
|
if (s=nil) or (s.Size = 0) then
|
|
begin
|
|
s.Free;
|
|
exit;
|
|
end;
|
|
|
|
try
|
|
GraphExt := '';
|
|
AGraphic := nil;
|
|
|
|
if assigned(CurReport.OnDBImageRead) then
|
|
begin
|
|
// External method to identify graphic type
|
|
// returns file extension for graphic type (e.g. jpg)
|
|
// If user implements CurReport.OnDBImageRead, the control assumes that
|
|
// the programmer either:
|
|
//
|
|
// -- Returns a valid identifier that matches a graphic class and
|
|
// the remainder of stream contains the image data. An instance of
|
|
// of graphic class will be used to load the image data.
|
|
// or
|
|
// -- Returns an invalid identifier that doesn't match a graphic class
|
|
// and the remainder of stream contains the image data. The control
|
|
// will try to load the image trying to identify the format
|
|
// by it's content
|
|
//
|
|
// In particular, returning an invalid identifier while the stream has
|
|
// a image header will not work.
|
|
CurReport.OnDBImageRead(self,s,GraphExt);
|
|
GraphExtToClass;
|
|
end
|
|
else
|
|
ReadImageHeader;
|
|
|
|
if gc<>nil then
|
|
begin
|
|
AGraphic := gc.Create;
|
|
AGraphic.LoadFromStream(s);
|
|
Picture.Assign(AGraphic);
|
|
end
|
|
else
|
|
begin
|
|
if not LoadImageFromStream then
|
|
Picture.Clear;
|
|
end;
|
|
|
|
finally
|
|
s.Free;
|
|
AGraphic.Free;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrPictureView.DefinePopupMenu(Popup: TPopupMenu);
|
|
var
|
|
m: TMenuItem;
|
|
begin
|
|
inherited DefinePopupMenu(Popup);
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sPictureCenter;
|
|
m.OnClick := @P1Click;
|
|
m.Checked := Centered;
|
|
Popup.Items.Add(m);
|
|
|
|
m := TMenuItem.Create(Popup);
|
|
m.Caption := sKeepAspectRatio;
|
|
m.OnClick := @P2Click;
|
|
m.Enabled := Stretched;
|
|
if m.Enabled then
|
|
m.Checked := KeepAspect;
|
|
Popup.Items.Add(m);
|
|
end;
|
|
|
|
procedure TfrPictureView.P1Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flPictCenter);
|
|
end;
|
|
|
|
function TfrPictureView.GetKeepAspect: boolean;
|
|
begin
|
|
Result:=((Flags and flPictRatio)<>0);
|
|
end;
|
|
|
|
function TfrPictureView.GetCentered: boolean;
|
|
begin
|
|
Result:=((Flags and flPictCenter)<>0);
|
|
end;
|
|
|
|
procedure TfrPictureView.P2Click(Sender: TObject);
|
|
begin
|
|
MenuItemCheckFlag(Sender, flPictRatio);
|
|
end;
|
|
|
|
function TfrPictureView.GetPictureType: byte;
|
|
begin
|
|
result := pkNone;
|
|
if Picture.Graphic <> nil then
|
|
result := pkAny;
|
|
end;
|
|
|
|
function TfrPictureView.PictureTypeToGraphic(b: Byte): TGraphic;
|
|
begin
|
|
result := nil;
|
|
case b of
|
|
pkBitmap: result := TBitmap.Create;
|
|
pkIcon: result := TIcon.Create;
|
|
pkJPEG: result := TJPEGImage.Create;
|
|
pkPNG: result := TPortableNetworkGraphic.Create;
|
|
end;
|
|
end;
|
|
|
|
function TfrPictureView.ExtensionToGraphic(const Ext: string): TGraphic;
|
|
var
|
|
AGraphicClass: TGraphicClass;
|
|
begin
|
|
AGraphicClass := GetGraphicClassForFileExtension(Ext);
|
|
if AGraphicClass<>nil then
|
|
result := AGraphicClass.Create
|
|
else
|
|
result := nil;
|
|
end;
|
|
|
|
procedure TfrPictureView.SetCentered(AValue: boolean);
|
|
begin
|
|
if Centered<>AValue then
|
|
ModifyFlag(flPictCenter, AValue);
|
|
end;
|
|
|
|
procedure TfrPictureView.SetKeepAspect(AValue: boolean);
|
|
begin
|
|
if KeepAspect<>AValue then
|
|
ModifyFlag(flPictRatio, AValue);
|
|
end;
|
|
|
|
function TfrPictureView.StreamToGraphic(M: TMemoryStream): TGraphic;
|
|
|
|
function ReadString(Len: Integer): string;
|
|
begin
|
|
SetLength(result, Len);
|
|
M.Read(result[1], Len);
|
|
end;
|
|
|
|
function TestStreamIsPNG: boolean;
|
|
begin
|
|
result := ReadString(8) = #137'PNG'#13#10#26#10;
|
|
M.Position := 0;
|
|
end;
|
|
|
|
function TestStreamIsJPEG: boolean;
|
|
begin
|
|
Result := ReadString(4) = #$FF#$D8#$FF#$E0;
|
|
if result then begin
|
|
M.Position := 6;
|
|
result := ReadString(5) = 'JFIF'#0
|
|
end;
|
|
M.Position := 0;
|
|
end;
|
|
|
|
begin
|
|
|
|
if M=nil then begin
|
|
result := nil;
|
|
exit;
|
|
end;
|
|
|
|
M.Position := 0;
|
|
|
|
if TestStreamIsBMP(M) then
|
|
begin
|
|
result := PictureTypeToGraphic(pkBitmap);
|
|
exit;
|
|
end;
|
|
|
|
if TestStreamIsIcon(M) then begin
|
|
result := PictureTypeToGraphic(pkIcon);
|
|
exit;
|
|
end;
|
|
|
|
if TestStreamIsXPM(M) then
|
|
begin
|
|
result := TPixmap.Create;
|
|
exit;
|
|
end;
|
|
|
|
if TestStreamIsPNG then
|
|
begin
|
|
result := PictureTypeToGraphic(pkPNG);
|
|
exit;
|
|
end;
|
|
|
|
if TestStreamIsJPEG then
|
|
begin
|
|
result := PictureTypeToGraphic(pkJPEG);
|
|
exit;
|
|
end;
|
|
|
|
result := nil;
|
|
end;
|
|
|
|
procedure TfrPictureView.SetPicture(const AValue: TPicture);
|
|
begin
|
|
BeforeChange;
|
|
fPicture := AValue;
|
|
AfterChange;
|
|
end;
|
|
|
|
function TfrLineView.GetFrames: TfrFrameBorders;
|
|
begin
|
|
if dx > dy then
|
|
begin
|
|
dy := 0;
|
|
fFrames:=[frbTop];
|
|
end
|
|
else
|
|
begin
|
|
dx := 0;
|
|
fFrames:=[frbLeft];
|
|
end;
|
|
Result:=fFrames;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrLineView.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
Typ := gtLine;
|
|
fFrames:=[frbLeft];
|
|
BaseName := 'Line';
|
|
SetBit(Flags, false, flStretched);
|
|
end;
|
|
|
|
procedure TfrLineView.Draw(aCanvas: TCanvas);
|
|
begin
|
|
BeginDraw(aCanvas);
|
|
GetFrames;
|
|
CalcGaps;
|
|
ShowFrame;
|
|
RestoreCoord;
|
|
end;
|
|
|
|
function TfrLineView.GetClipRgn(rt: TfrRgnType): HRGN;
|
|
var
|
|
bx, by, bx1, by1, dd: Integer;
|
|
begin
|
|
bx := x; by := y; bx1 := x + dx + 1; by1 := y + dy + 1;
|
|
if FrameStyle<>frsDouble then
|
|
dd := Round(FrameWidth / 2)
|
|
else
|
|
dd := Round(FrameWidth * 1.5);
|
|
if Frames=[frbLeft] then
|
|
begin
|
|
Dec(bx, dd);
|
|
Inc(bx1, dd);
|
|
end
|
|
else
|
|
begin
|
|
Dec(by, dd);
|
|
Inc(by1, dd);
|
|
end;
|
|
if rt = rtNormal then
|
|
Result := CreateRectRgn(bx, by, bx1, by1)
|
|
else
|
|
Result := CreateRectRgn(bx - 10, by - 10, bx1 + 10, by1 + 10);
|
|
end;
|
|
|
|
function TfrLineView.PointInView(aX, aY: Integer): Boolean;
|
|
var
|
|
bx, by, bx1, by1, w1: Integer;
|
|
tmp: Double;
|
|
begin
|
|
|
|
if FrameWidth<1.0 then
|
|
tmp := 1.0
|
|
else
|
|
tmp := FrameWidth;
|
|
|
|
if FrameStyle=frsDouble then
|
|
w1 := Round(tmp * 1.5)
|
|
else
|
|
w1 := Round(tmp);
|
|
|
|
bx:=x-w1;
|
|
by:=y-w1;
|
|
bx1:=x+dx+w1;
|
|
by1:=y+dy+w1;
|
|
|
|
Result:=(ax>=bx) and (ax<=bx1) and (ay>=by) and (ay<=by1);
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrBand.Create(ATyp: TfrBandType; AParent: TfrPage);
|
|
begin
|
|
inherited Create(nil);
|
|
Typ := ATyp;
|
|
Parent := AParent;
|
|
Objects := TFpList.Create;
|
|
Values := TStringList.Create;
|
|
Next := nil;
|
|
Positions[psLocal] := 1;
|
|
Positions[psGlobal] := 1;
|
|
Visible:=True;
|
|
end;
|
|
|
|
destructor TfrBand.Destroy;
|
|
begin
|
|
if Next <> nil then
|
|
Next.Free;
|
|
Objects.Free;
|
|
Values.Free;
|
|
if DataSet <> nil then
|
|
DataSet.Exit;
|
|
if IsVirtualDS then
|
|
DataSet.Free;
|
|
if VCDataSet <> nil then
|
|
VCDataSet.Exit;
|
|
if IsVirtualVCDS then
|
|
VCDataSet.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TfrBand.IsDataBand: boolean;
|
|
begin
|
|
result := (typ in [btMasterData, btDetailData, btSubDetailData]);
|
|
end;
|
|
|
|
function TfrBand.getName: string;
|
|
begin
|
|
if Assigned(View) then
|
|
Result:= View.Name
|
|
else Result:= '';
|
|
end;
|
|
|
|
procedure TfrBand.InitDataSet(const Desc: String);
|
|
begin
|
|
if Typ = btGroupHeader then
|
|
GroupCondition := Desc
|
|
else
|
|
if Pos(';', Desc) = 0 then
|
|
CreateDS(Desc, DataSet, IsVirtualDS);
|
|
if (Typ = btMasterData) and (Dataset = nil) and
|
|
(CurReport.ReportType = rtSimple) then
|
|
DataSet := CurReport.Dataset;
|
|
end;
|
|
|
|
procedure TfrBand.DoError(const AErrorMsg: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
ErrorFlag := True;
|
|
ErrorStr := sErrorOccured;
|
|
for i := 0 to CurView.Memo.Count - 1 do
|
|
ErrorStr := ErrorStr + LineEnding + CurView.Memo[i];
|
|
ErrorStr := ErrorStr + LineEnding +
|
|
sDoc + ' ' + CurReport.Name + LineEnding +
|
|
sCurMemo + ' ' + CurView.Name;
|
|
if Assigned(CurView.Parent) then
|
|
ErrorStr := ErrorStr + LineEnding +
|
|
sBand + ' ' + CurView.Parent.Name; //frBandNames[Integer(CurView.Parent.Typ)];
|
|
|
|
if AErrorMsg<>'' then
|
|
ErrorStr := ErrorStr + LineEnding + AErrorMsg;
|
|
|
|
MasterReport.Terminated := True;
|
|
end;
|
|
|
|
function TfrBand.CalcHeight: Integer;
|
|
var
|
|
Bnd: TfrBand;
|
|
DS : TfrDataSet;
|
|
ddx: Integer;
|
|
BM : Pointer;
|
|
|
|
function SubDoCalcHeight(CheckAll: Boolean): Integer;
|
|
var
|
|
i, h, vh: Integer;
|
|
t: TfrView;
|
|
begin
|
|
CurBand := Self;
|
|
AggrBand := Self;
|
|
Result := dy;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
t.olddy := t.dy;
|
|
if t is TfrStretcheable then
|
|
if (t.Parent = Self) or CheckAll then
|
|
begin
|
|
vh := TfrStretcheable(t).CalcHeight;
|
|
h := vh + t.y;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('View=%s t.y=%d t.dy=%d vh=%d h=%d result=%d',[ViewInfo(t),t.y,t.dy,vh,h,result]);
|
|
{$ENDIF}
|
|
if h > Result then
|
|
Result := h;
|
|
if CheckAll then
|
|
TfrStretcheable(t).DrawMode := drAll;
|
|
end
|
|
end;
|
|
end;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrBand.CalcHeight INIT CurDy=%d',[dy]);
|
|
{$ENDIF}
|
|
Result := dy;
|
|
if HasCross and (Typ <> btPageFooter) then
|
|
begin
|
|
Parent.ColPos := 1;
|
|
CurReport.DoBeginColumn(Self);
|
|
if Parent.BandExists(Parent.Bands[btCrossData]) then
|
|
begin
|
|
Bnd := Parent.Bands[btCrossData];
|
|
if Bnd.DataSet <> nil then
|
|
DS := Bnd.DataSet
|
|
else
|
|
DS := VCDataSet;
|
|
if DS <> nil then
|
|
begin
|
|
BM:=DS.GetBookMark;
|
|
DS.DisableControls;
|
|
try
|
|
DS.First;
|
|
while not DS.Eof do
|
|
begin
|
|
ddx := 0;
|
|
CurReport.DoPrintColumn(Parent.ColPos, ddx);
|
|
CalculatedHeight := SubDoCalcHeight(True);
|
|
if CalculatedHeight > Result then
|
|
Result := CalculatedHeight;
|
|
Inc(Parent.ColPos);
|
|
DS.Next;
|
|
if MasterReport.Terminated then break;
|
|
end;
|
|
finally
|
|
DS.GotoBookMark(BM);
|
|
DS.FreeBookMark(BM);
|
|
DS.EnableControls;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
Result := SubDoCalcHeight(False);
|
|
CalculatedHeight := Result;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrBand.CalcHeight DONE CalculatedHeight=%d',[CalculatedHeight]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrBand.StretchObjects(MaxHeight: Integer);
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrBand.StretchObjects INIT MaxHeight=%d Self.dy=%d',[MaxHeight,Self.dy]);
|
|
{$ENDIF}
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if (t is TfrStretcheable) or (t is TfrLineView) then
|
|
if (t.Flags and flStretched) <> 0 then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('i=%d View=%s Antes: y=%d dy=%d',[i,ViewInfo(t), t.y,t.dy]);
|
|
{$ENDIF}
|
|
t.oldy := t.y;
|
|
if t.dy=0 then
|
|
t.y := t.y + (MaxHeight - self.dy)
|
|
else
|
|
t.dy := MaxHeight - t.y;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('i=%d View=%s After: y=%d dy=%d',[i,ViewInfo(t), t.y,t.dy]);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrBand.StretchObjects DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrBand.UnStretchObjects;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
t.dy := t.olddy;
|
|
t.y := t.oldy;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBand.DrawObject(t: TfrView);
|
|
var
|
|
ox,oy: Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrBand.DrawObject INI y=%d t=%s Xadj=%d Margin=%d DiableDrawing=%s',
|
|
[y,ViewInfoDIM(t),Parent.XAdjust,Parent.LeftMargin,BoolToStr(DisableDrawing,true)]);
|
|
{$ENDIF}
|
|
CurPage := Parent;
|
|
CurBand := Self;
|
|
AggrBand := Self;
|
|
try
|
|
if (t.Parent = Self) and not DisableDrawing then
|
|
begin
|
|
ox := t.x; Inc(t.x, Parent.XAdjust - Parent.LeftMargin);
|
|
oy := t.y; Inc(t.y, y);
|
|
t.Print(MasterReport.EMFPages[PageNo]^.Stream);
|
|
t.x := ox; t.y := oy;
|
|
if (t is TfrMemoView) and
|
|
(TfrMemoView(t).DrawMode in [drAll, drAfterCalcHeight]) then
|
|
Parent.AfterPrint;
|
|
end;
|
|
except
|
|
on E:Exception do
|
|
DoError(E.Message);
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrBand.DrawObject DONE t=%s:%s',[dbgsname(t),t.name]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrBand.PrepareSubReports;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
Page: TfrPage;
|
|
begin
|
|
for i := SubIndex to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
|
|
Page.Mode := pmBuildList;
|
|
Page.FormPage;
|
|
Page.CurY := y + t.y;
|
|
Page.CurBottomY := Parent.CurBottomY;
|
|
Page.XAdjust := Parent.XAdjust + t.x;
|
|
Page.ColCount := 1;
|
|
Page.PlayFrom := 0;
|
|
EOFArr[i - SubIndex] := False;
|
|
end;
|
|
Parent.LastBand := nil;
|
|
end;
|
|
|
|
procedure TfrBand.DoSubReports;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
Page: TfrPage;
|
|
begin
|
|
repeat
|
|
if not EOFReached then
|
|
for i := SubIndex to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
|
|
Page.CurY := Parent.CurY;
|
|
Page.CurBottomY := Parent.CurBottomY;
|
|
end;
|
|
EOFReached := True;
|
|
MaxY := Parent.CurY;
|
|
for i := SubIndex to Objects.Count - 1 do
|
|
begin
|
|
if not EOFArr[i - SubIndex] then
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
|
|
if Page.PlayRecList then
|
|
EOFReached := False
|
|
else
|
|
begin
|
|
EOFArr[i - SubIndex] := True;
|
|
if Page.CurY > MaxY then MaxY := Page.CurY;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not EOFReached then
|
|
begin
|
|
if Parent.Skip then
|
|
begin
|
|
Parent.LastBand := Self;
|
|
Exit;
|
|
end
|
|
else
|
|
Parent.NewPage;
|
|
end;
|
|
|
|
until EOFReached or MasterReport.Terminated;
|
|
|
|
for i := SubIndex to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
|
|
Page.ClearRecList;
|
|
end;
|
|
Parent.CurY := MaxY;
|
|
Parent.LastBand := nil;
|
|
end;
|
|
|
|
function TfrBand.DrawObjects: Boolean;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
{$ifdef DebugLR}
|
|
DebugLnEnter('DrawObjects INIT');
|
|
{$endif}
|
|
Result := False;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if t.Typ = gtSubReport then
|
|
begin
|
|
SubIndex := i;
|
|
Result := True;
|
|
PrepareSubReports;
|
|
DoSubReports;
|
|
break;
|
|
end;
|
|
|
|
t.Flags:=t.Flags and not (flStartRecord or flEndRecord);
|
|
if i=0 then t.Flags := t.Flags or flStartRecord;
|
|
if i=Objects.Count-1 then t.Flags := t.Flags or flEndRecord;
|
|
|
|
DrawObject(t);
|
|
if MasterReport.Terminated then break;
|
|
end;
|
|
{$ifdef DebugLR}
|
|
DebugLnExit('DrawObjects DONE result=%s',[BoolToStr(result,true)]);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrBand.DrawCrossCell(Parnt: TfrBand; CurX: Integer);
|
|
var
|
|
i, sfx, sfy: Integer;
|
|
t: TfrView;
|
|
begin
|
|
CurBand := Self;
|
|
CurBand.Positions[psGlobal] := Parnt.Positions[psGlobal];
|
|
CurBand.Positions[psLocal] := Parnt.Positions[psLocal];
|
|
if Typ = btCrossData then
|
|
AggrBand := Parnt;
|
|
try
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t := TfrView(Objects[i]);
|
|
if Parnt.Objects.IndexOf(t) <> -1 then
|
|
if not DisableDrawing then
|
|
begin
|
|
sfx := t.x; Inc(t.x, CurX);
|
|
sfy := t.y; Inc(t.y, Parnt.y);
|
|
t.Print(MasterReport.EMFPages[PageNo]^.Stream);
|
|
if (t is TfrMemoView) and
|
|
(TfrMemoView(t).DrawMode in [drAll, drAfterCalcHeight]) then
|
|
Parent.AfterPrint;
|
|
t.Parent := Self;
|
|
t.x := sfx;
|
|
t.y := sfy;
|
|
end
|
|
else
|
|
begin
|
|
CurView := t;
|
|
frInterpretator.DoScript(t.Script);
|
|
end;
|
|
end;
|
|
except
|
|
on E:Exception do
|
|
DoError(E.Message); //(E);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBand.DrawCross;
|
|
var
|
|
Bnd : TfrBand;
|
|
sfpage : Integer;
|
|
CurX, ddx : Integer;
|
|
DS : TfrDataSet;
|
|
BM : Pointer;
|
|
|
|
procedure CheckColumnPageBreak(ddx: Integer);
|
|
var
|
|
sfy: Integer;
|
|
b: TfrBand;
|
|
begin
|
|
if CurX + ddx > Parent.RightMargin then
|
|
begin
|
|
Inc(ColumnXAdjust, CurX - Parent.LeftMargin);
|
|
CurX := Parent.LeftMargin;
|
|
Inc(PageNo);
|
|
if PageNo >= MasterReport.EMFPages.Count then
|
|
begin
|
|
MasterReport.EMFPages.Add(Parent);
|
|
sfy := Parent.CurY;
|
|
Parent.ShowBand(Parent.Bands[btOverlay]);
|
|
Parent.CurY := Parent.TopMargin;
|
|
if (sfPage <> 0) or
|
|
((Parent.Bands[btPageHeader].Flags and flBandOnFirstPage) <> 0) then
|
|
Parent.ShowBand(Parent.Bands[btPageHeader]);
|
|
Parent.CurY := sfy;
|
|
CurReport.InternalOnProgress(PageNo);
|
|
end;
|
|
if Parent.BandExists(Parent.Bands[btCrossHeader]) then
|
|
if (Parent.Bands[btCrossHeader].Flags and flBandRepeatHeader) <> 0 then
|
|
begin
|
|
b := Parent.Bands[btCrossHeader];
|
|
b.DrawCrossCell(Self, Parent.LeftMargin);
|
|
CurX := Parent.LeftMargin + b.dx;
|
|
end;
|
|
end;
|
|
end;
|
|
begin
|
|
ColumnXAdjust := 0;
|
|
Parent.ColPos := 1;
|
|
CurX := 0;
|
|
sfpage := PageNo;
|
|
if Typ = btPageFooter then Exit;
|
|
IsColumns := True;
|
|
CurReport.DoBeginColumn(Self);
|
|
|
|
if Parent.BandExists(Parent.Bands[btCrossHeader]) then
|
|
begin
|
|
Bnd := Parent.Bands[btCrossHeader];
|
|
Bnd.DrawCrossCell(Self, Bnd.x);
|
|
CurX := Bnd.x + Bnd.dx;
|
|
end;
|
|
|
|
if Parent.BandExists(Parent.Bands[btCrossData]) then
|
|
begin
|
|
Bnd := Parent.Bands[btCrossData];
|
|
if CurX = 0 then CurX := Bnd.x;
|
|
if Bnd.DataSet <> nil then
|
|
DS := Bnd.DataSet
|
|
else
|
|
DS := VCDataSet;
|
|
|
|
if DS <> nil then
|
|
begin
|
|
BM:=DS.GetBookMark;
|
|
DS.DisableControls;
|
|
try
|
|
DS.First;
|
|
while not DS.Eof do
|
|
begin
|
|
ddx := Bnd.dx;
|
|
CurReport.DoPrintColumn(Parent.ColPos, ddx);
|
|
CheckColumnPageBreak(ddx);
|
|
Bnd.DrawCrossCell(Self, CurX);
|
|
|
|
if Typ in [btMasterData, btDetailData, btSubdetailData] then
|
|
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
|
|
btSubDetailFooter, btGroupFooter, btCrossFooter, btReportSummary]);
|
|
|
|
Inc(CurX, ddx);
|
|
Inc(Parent.ColPos);
|
|
DS.Next;
|
|
if MasterReport.Terminated then break;
|
|
end;
|
|
finally
|
|
DS.GotoBookMark(BM);
|
|
DS.FreeBookMark(BM);
|
|
DS.EnableControls;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Parent.BandExists(Parent.Bands[btCrossFooter]) then
|
|
begin
|
|
Bnd := Parent.Bands[btCrossFooter];
|
|
if CurX = 0 then CurX := Bnd.x;
|
|
CheckColumnPageBreak(Bnd.dx);
|
|
AggrBand := Bnd;
|
|
Bnd.DrawCrossCell(Self, CurX);
|
|
Bnd.InitValues;
|
|
end;
|
|
PageNo := sfpage;
|
|
ColumnXAdjust := 0;
|
|
IsColumns := False;
|
|
end;
|
|
|
|
function TfrBand.CheckPageBreak(ay, ady: Integer; PBreak: Boolean): Boolean;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrBand.CheckPageBreak INI ay=%d ady=%d Pbreak=%d',[ay,ady,ord(pbreak)]);
|
|
{$ENDIF}
|
|
Result := False;
|
|
with Parent do begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('ay+ColFoot.dy+ady=%d CurBottomY=%d',[ay+Bands[btColumnFooter].dy+ady,CurBottomY]);
|
|
{$ENDIF}
|
|
if not RowsLayout then begin
|
|
if ay + Bands[btColumnFooter].dy + ady > CurBottomY then
|
|
begin
|
|
if not PBreak then
|
|
NewColumn(Self);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrBand.CheckPageBreak END ay=%d ady=%d Result=%d',[ay,ady,ord(Result)]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrBand.CheckNextColumn: boolean;
|
|
var
|
|
BandHeight: Integer;
|
|
begin
|
|
with Parent do begin
|
|
if (CurColumn=0) and (typ=btMasterData) then begin
|
|
BandHeight := DoCalcHeight;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrBand.CheckNextColumn INI CurY=%d BHeight=%d CurY+BH=%d CurBottomY=%d',
|
|
[CurY,BandHeight,CurY+BandHeight,CurBottomY]);
|
|
{$ENDIF}
|
|
// check left height space when on last column
|
|
if CurY + BandHeight>CurBottomY then
|
|
NewPage;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrBand.CheckNextColumn END CurY=%d BHeight=%d CurY+BH=%d CurBottomY=%d',
|
|
[CurY,BandHeight,CurY+BandHeight,CurBottomY]);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
Result := true;
|
|
end;
|
|
|
|
procedure TfrBand.DrawPageBreak;
|
|
var
|
|
i, j, k, ty: Integer;
|
|
newDy, oldy, olddy, aMaxy: Integer;
|
|
t: TfrView;
|
|
Flag: Boolean;
|
|
PgArr: array of integer;
|
|
|
|
procedure CorrY(t: TfrView; dy: Integer);
|
|
var
|
|
i: Integer;
|
|
t1: TfrView;
|
|
begin
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t1 :=TfrView(Objects[i]);
|
|
if t1 <> t then
|
|
if (t1.y > t.y + t.dy) and (t1.x >= t.x) and (t1.x <= t.x + t.dx) then
|
|
Inc(t1.y, dy);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('DrawPageBreak INI y=%d Maxdy=%d',[y,maxdy]);
|
|
{$ENDIF}
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
t.Selected := True;
|
|
t.OriginalRect := Rect(t.x, t.y, t.dx, t.dy);
|
|
end;
|
|
|
|
if not CheckPageBreak(y, maxdy, True) then
|
|
DrawObjects
|
|
else
|
|
begin
|
|
|
|
// space left of each column after headers and footers
|
|
newDy := Parent.CurBottomY - Parent.Bands[btColumnFooter].dy - y - 2;
|
|
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if t is TfrStretcheable then
|
|
TfrStretcheable(t).ActualHeight := 0;
|
|
if t is TfrMemoView then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('CalcHeight Memo INI');
|
|
{$ENDIF}
|
|
TfrMemoView(t).CalcHeight; // wraps a memo onto separate lines
|
|
t.Memo1.Assign(SMemo);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('CalcHeight Memo DONE');
|
|
{$ENDIF}
|
|
// all stretcheable objects "end" at the same pixel
|
|
// here t.y coordinate is relative to current band, so is 0 based
|
|
|
|
// roughly, how many columns we will need?
|
|
k := ((t.y+t.dy) div newDy) + 2; // +2 = 1 for probable remainder + 1 extra
|
|
if k > Length(pgArr) then
|
|
SetLength(pgArr, k);
|
|
end;
|
|
end;
|
|
|
|
// some objects do not fully use "newdy" pixels on each page, because of
|
|
// the granularity of "min height", some use as much space as "lines" fit
|
|
for j:=0 to Length(pgArr)-1 do
|
|
begin
|
|
|
|
pgArr[j] := newDy;
|
|
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
// calc the number of pixels really used by stretchable objects
|
|
// on each page.
|
|
t :=TfrView(Objects[i]);
|
|
if not (t is TfrStretcheable) then
|
|
continue;
|
|
|
|
ty := t.y;
|
|
if j>0 then
|
|
ty := 0; // on each additional page, each object starts at 0, not t.y
|
|
|
|
// additionally, when objects are drawn, they are offseted t.gapy pixels
|
|
// but this is object dependant, for TfrMemoView they are.
|
|
if (t is TfrMemoView) then
|
|
ty := ty + t.gapy;
|
|
|
|
k := Max(TfrStretcheable(t).MinHeight, 1);
|
|
pgArr[j] := Min(pgArr[j], ty + (newDy-ty) div k * k);
|
|
end;
|
|
end;
|
|
|
|
k := 0;
|
|
repeat
|
|
if k>(Length(pgArr)-1) then
|
|
break; // TODO: raise exception?
|
|
newDy := pgArr[k];
|
|
|
|
aMaxy := 0;
|
|
{$IFDEF DebugLR}
|
|
WriteLn('Parent.CurBottomy=',Parent.CurBottomY,' NewDY=',newDY);
|
|
{$ENDIF}
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if not t.Selected then
|
|
continue;
|
|
|
|
if (t.y >= 0) and (t.y < newdy) then
|
|
begin
|
|
if (t.y + t.dy < newdy) then
|
|
begin
|
|
// draw objects that fit on page and remove from
|
|
// pending objects
|
|
if aMaxy < t.y + t.dy then
|
|
aMaxy := t.y + t.dy;
|
|
DrawObject(t);
|
|
t.Selected := False;
|
|
end
|
|
else
|
|
begin
|
|
// objects that doesn't fit on page
|
|
if t is TfrStretcheable then
|
|
begin
|
|
olddy := t.dy;
|
|
t.dy := newdy - t.y + 1;
|
|
Inc(TfrStretcheable(t).ActualHeight, t.dy);
|
|
if t.dy > TfrStretcheable(t).MinHeight then
|
|
begin
|
|
TfrStretcheable(t).DrawMode := drPart;
|
|
DrawObject(t);
|
|
end;
|
|
t.dy := olddy;
|
|
end
|
|
else
|
|
t.y := newdy
|
|
end
|
|
end
|
|
else if t is TfrStretcheable then
|
|
begin
|
|
if (t.y < 0) and (t.y + t.dy >= 0) then
|
|
begin
|
|
// drawing the remaining part of some object
|
|
if t.y + t.dy > newdy then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('BIGGER THAN PAGE: t=%s Acumdy=%d y+dy=%d newdy=%d',
|
|
[ViewInfoDIM(t), TfrStretcheable(t).ActualHeight, t.y + t.dy,newdy]);
|
|
{$ENDIF}
|
|
// the rest of "t" is too large to fit in the rest of the page
|
|
oldy := t.y; olddy := t.dy;
|
|
t.y := 0; t.dy := newdy;
|
|
Inc(TfrStretcheable(t).ActualHeight, t.dy);
|
|
TfrStretcheable(t).DrawMode := drPart;
|
|
DrawObject(t);
|
|
t.y := oldy; t.dy := olddy;
|
|
t.Selected := true;
|
|
end else
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('REMAINING OF PAGE: t=%s Acumdy=%d y+dy=%d newdy=%d',
|
|
[ViewInfoDIM(t),TfrStretcheable(t).ActualHeight, t.y + t.dy,newdy]);
|
|
{$ENDIF}
|
|
// the rest of "t" fits within the remaining space on page
|
|
oldy := t.y; olddy := t.dy;
|
|
t.dy := t.y + t.dy;
|
|
t.y := 0;
|
|
Inc(TfrStretcheable(t).ActualHeight, t.dy);
|
|
TfrStretcheable(t).DrawMode := drPart;
|
|
DrawObject(t);
|
|
if aMaxy < t.y + t.dy then
|
|
aMaxy := t.y + t.dy;
|
|
t.y := oldy; t.dy := olddy;
|
|
CorrY(t, TfrStretcheable(t).ActualHeight - t.dy);
|
|
t.Selected := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
Flag := False;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if t.Selected then Flag := True;
|
|
Dec(t.y, newdy);
|
|
end;
|
|
|
|
if Flag then
|
|
CheckPageBreak(y, 10000, False);
|
|
y := Parent.CurY;
|
|
|
|
inc(k);
|
|
|
|
if MasterReport.Terminated then
|
|
break;
|
|
until not Flag;
|
|
maxdy := aMaxy;
|
|
end;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
t.y := t.OriginalRect.Top;
|
|
t.dy := t.OriginalRect.Bottom;
|
|
end;
|
|
Inc(Parent.CurY, maxdy);
|
|
SetLength(pgArr, 0);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('DrawPageBreak END Parent.CurY=%d',[Parent.CurY]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrBand.HasCross: Boolean;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
Result := False;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
if t.Parent <> Self then
|
|
begin
|
|
Result := True;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrBand.DoDraw;
|
|
var
|
|
sfy, sh: Integer;
|
|
UseY, WasSub: Boolean;
|
|
|
|
begin
|
|
if Objects.Count = 0 then Exit;
|
|
sfy := y;
|
|
UseY := not (Typ in [btPageFooter, btOverlay, btNone]);
|
|
if UseY then
|
|
y := Parent.CurY;
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrBand.DoDraw INI Band=%s sfy=%d y=%d dy=%d XAdjust=%d CurY=%d Stretch=%d PageBreak=%d',
|
|
[bandInfo(self), sfy, y, dy, Parent.XAdjust, parent.cury, Ord(Stretched), Ord(PageBreak)]);
|
|
{$ENDIF}
|
|
|
|
Parent.RowStarted := True;
|
|
|
|
if Stretched then
|
|
begin
|
|
sh := CalculatedHeight;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Height=%d CalculatedHeight=%d',[dy,sh]);
|
|
{$ENDIF}
|
|
StretchObjects(sh);
|
|
maxdy := sh;
|
|
if not PageBreak then
|
|
CheckPageBreak(y, sh, False);
|
|
y := Parent.CurY;
|
|
WasSub := False;
|
|
if PageBreak then
|
|
begin
|
|
DrawPageBreak;
|
|
sh := 0;
|
|
end
|
|
else
|
|
begin
|
|
WasSub := DrawObjects;
|
|
if HasCross then
|
|
DrawCross;
|
|
end;
|
|
UnStretchObjects;
|
|
|
|
Parent.LastRowHeight := sh;
|
|
|
|
if not WasSub then
|
|
Inc(Parent.CurY, sh);
|
|
end
|
|
else
|
|
begin
|
|
|
|
if UseY then
|
|
begin
|
|
if not PageBreak then
|
|
CheckPageBreak(y, dy, False);
|
|
y := Parent.CurY;
|
|
end;
|
|
|
|
if PageBreak then
|
|
begin
|
|
maxdy := CalculatedHeight;
|
|
DrawPageBreak;
|
|
Parent.LastRowHeight := maxdy;
|
|
end
|
|
else
|
|
begin
|
|
WasSub := DrawObjects;
|
|
if HasCross then
|
|
DrawCross;
|
|
if UseY and not WasSub then begin
|
|
|
|
Parent.LastRowHeight := dy;
|
|
|
|
if Parent.AdvanceRow(Self) then
|
|
Inc(Parent.CurY, dy);
|
|
end;
|
|
end;
|
|
end;
|
|
y := sfy;
|
|
if Typ in [btMasterData, btDetailData, btSubDetailData] then
|
|
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
|
|
btSubDetailFooter, btGroupFooter, btReportSummary]);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrBand.DoDraw END sfy=%d y=%d dy=%d xadjust=%d CurY=%d',
|
|
[sfy, y, dy, parent.xadjust, parent.cury]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrBand.DoCalcHeight: Integer;
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
if (Typ in [btMasterData, btDetailData, btSubDetailData]) and
|
|
(Next <> nil) and (Next.Dataset = nil) then
|
|
begin
|
|
b := Self;
|
|
Result := 0;
|
|
repeat
|
|
Result := Result + b.CalcHeight;
|
|
b := b.Next;
|
|
until b = nil;
|
|
end
|
|
else
|
|
begin
|
|
Result := dy;
|
|
CalculatedHeight := dy;
|
|
if Stretched then Result := CalcHeight;
|
|
end;
|
|
end;
|
|
|
|
function TfrBand.Draw: Boolean;
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
{$IFDEF debugLr}
|
|
DebugLnEnter('TFrBand.Draw INI Band=%s y=%d dy=%d vis=%s',[BandInfo(self),y,dy,BoolToStr(Visible,true)]);
|
|
{$endif}
|
|
Result := False;
|
|
CurView := View;
|
|
CurBand := Self;
|
|
AggrBand := Self;
|
|
CalculatedHeight := -1;
|
|
ForceNewPage := False;
|
|
ForceNewColumn := False;
|
|
CurReport.DoBeginBand(Self);
|
|
frInterpretator.DoScript(Script);
|
|
|
|
if Parent.RowsLayout and IsDataBand then begin
|
|
|
|
if Visible then
|
|
begin
|
|
if Objects.Count > 0 then
|
|
begin
|
|
if not (Typ in [btPageFooter, btOverlay, btNone]) then begin
|
|
if Parent.Skip then
|
|
exit
|
|
else
|
|
CheckNextColumn;
|
|
end;
|
|
EOFReached := True;
|
|
// only masterdata band supported in RowsLayout columns report
|
|
if typ=btMasterData then begin
|
|
DoDraw;
|
|
Parent.NextColumn(Self);
|
|
end;
|
|
if not EOFReached then
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
end else begin
|
|
|
|
if Parent.RowsLayout and (typ<>btColumnHeader) then
|
|
|
|
Parent.StartRowsLayoutNonDataBand(Self)
|
|
|
|
else
|
|
// new page was requested in script
|
|
if ForceNewPage then
|
|
begin
|
|
Parent.CurColumn := Parent.ColCount - 1;
|
|
Parent.NewColumn(Self);
|
|
end;
|
|
if ForceNewColumn then
|
|
Parent.NewColumn(Self);
|
|
|
|
if Visible then
|
|
begin
|
|
if Typ = btColumnHeader then
|
|
Parent.LastStaticColumnY := Parent.CurY;
|
|
if Typ = btPageFooter then
|
|
y := Parent.CurBottomY;
|
|
if Objects.Count > 0 then
|
|
begin
|
|
if not (Typ in [btPageFooter, btOverlay, btNone]) then
|
|
if (Parent.CurY + DoCalcHeight > Parent.CurBottomY) and not PageBreak then
|
|
begin
|
|
Result := True;
|
|
if Parent.Skip then
|
|
Exit
|
|
else
|
|
CheckPageBreak(0, 10000, False);
|
|
end;
|
|
EOFReached := True;
|
|
|
|
// dealing with multiple bands
|
|
if (Typ in [btMasterData, btDetailData, btSubDetailData]) and
|
|
(Next <> nil) and (Next.Dataset = nil) and (DataSet <> nil) then
|
|
begin
|
|
b := Self;
|
|
repeat
|
|
b.DoDraw;
|
|
b := b.Next;
|
|
until b = nil;
|
|
end
|
|
else
|
|
begin
|
|
DoDraw;
|
|
if not (Typ in [btMasterData, btDetailData, btSubDetailData, btGroupHeader]) and
|
|
NewPageAfter then
|
|
Parent.NewPage;
|
|
end;
|
|
if not EOFReached then Result := True;
|
|
end;
|
|
end
|
|
// if band is not visible, just performing aggregate calculations
|
|
// relative to it
|
|
else
|
|
if Typ in [btMasterData, btDetailData, btSubDetailData] then
|
|
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
|
|
btSubDetailFooter, btGroupFooter, btReportSummary]);
|
|
|
|
// check if multiple pagefooters (in cross-tab report) - resets last of them
|
|
if not DisableInit then
|
|
if (Typ <> btPageFooter) or (PageNo = MasterReport.EMFPages.Count - 1) then
|
|
InitValues;
|
|
|
|
// if in rows layout, reset starting column after non-data band
|
|
if Parent.RowsLayout and (typ<>btColumnHeader) then
|
|
Parent.StartColumn;
|
|
|
|
end;
|
|
|
|
CurReport.DoEndBand(Self);
|
|
|
|
Parent.LastBandType := typ;
|
|
|
|
{$IFDEF debugLr}
|
|
DebugLnExit('TFrBand.Draw END %s y=%d PageNo=%d EOFReached=',[dbgsname(self),y, PageNo]);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrBand.InitValues;
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
if Typ = btGroupHeader then
|
|
begin
|
|
b := Self;
|
|
while b <> nil do
|
|
begin
|
|
if b.FooterBand <> nil then
|
|
begin
|
|
b.FooterBand.Values.Clear;
|
|
b.FooterBand.Count := 0;
|
|
end;
|
|
b.LastGroupValue := frParser.Calc(b.GroupCondition);
|
|
b := b.Next;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Values.Clear;
|
|
Count := 0;
|
|
end
|
|
end;
|
|
|
|
{$ifdef DebugLR}
|
|
function DecodeValue(s:string):string;
|
|
var
|
|
p: Integer;
|
|
begin
|
|
result := s;
|
|
p := pos('=',result) + 2;
|
|
if result<>'' then
|
|
insert('|',result,p);
|
|
end;
|
|
{$endif}
|
|
procedure TfrBand.DoAggregate;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
s: String;
|
|
v: Boolean;
|
|
begin
|
|
{$ifdef DebugLR}
|
|
DebugLnEnter('TfrBand.DoAggregate INIT Band=%s',[BandInfo(self)]);
|
|
{$endif}
|
|
for i := 0 to Values.Count - 1 do
|
|
begin
|
|
s := Values[i];
|
|
{$ifdef DebugLR}
|
|
DbgOut('Mangling Values[',dbgs(i),']=',QuotedStr(DecodeValue(s)),' ==> ');
|
|
{$endif}
|
|
Values[i] := Copy(s, 1, Pos('=', s) - 1) + '=0' + Copy(s, Pos('=', s) + 2, 255);
|
|
{$ifdef DebugLR}
|
|
DebugLn(QuotedStr(DecodeValue(Values[i])));
|
|
{$endif}
|
|
end;
|
|
|
|
v := Visible;
|
|
Visible := False;
|
|
AggrBand := Self;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
CurView := t;
|
|
if t is TfrMemoView then
|
|
TfrMemoView(t).ExpandVariables;
|
|
end;
|
|
Visible := v;
|
|
Inc(Count);
|
|
{$ifdef DebugLR}
|
|
DebugLnExit('TfrBand.DoAggregate DONE Band=%s',[BandInfo(self)]);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrBand.ResetLastValues;
|
|
var
|
|
i: Integer;
|
|
t: TfrView;
|
|
begin
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Objects[i]);
|
|
t.ResetLastValue;
|
|
end;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
type
|
|
TfrBandParts = (bpHeader, bpData, bpFooter);
|
|
const
|
|
MAXBNDS = 3;
|
|
Bnds: Array[1..MAXBNDS, TfrBandParts] of TfrBandType =
|
|
((btMasterHeader, btMasterData, btMasterFooter),
|
|
(btDetailHeader, btDetailData, btDetailFooter),
|
|
(btSubDetailHeader, btSubDetailData, btSubDetailFooter));
|
|
|
|
|
|
constructor TfrPage.Create(ASize, AWidth, AHeight: Integer;
|
|
AOr: TPrinterOrientation);
|
|
begin
|
|
Self.Create(nil);
|
|
|
|
ChangePaper(ASize, AWidth, AHeight, AOr);
|
|
PrintToPrevPage := False;
|
|
UseMargins := True;
|
|
end;
|
|
|
|
constructor TfrPage.CreatePage;
|
|
begin
|
|
self.Create(nil);
|
|
end;
|
|
|
|
destructor TfrPage.Destroy;
|
|
begin
|
|
Clear;
|
|
Objects.Free;
|
|
RTObjects.Free;
|
|
List.Free;
|
|
fMargins.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrPage.ChangePaper(ASize, AWidth, AHeight: Integer;
|
|
AOr: TPrinterOrientation);
|
|
begin
|
|
try
|
|
Prn.SetPrinterInfo(ASize, AWidth, AHeight, AOr);
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
except
|
|
on E:exception do
|
|
begin
|
|
Prn.SetPrinterInfo($100, AWidth, AHeight, AOr);
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
end;
|
|
end;
|
|
pgSize := Prn.PaperSize;
|
|
Width := Prn.PaperWidth;
|
|
Height := Prn.PaperHeight;
|
|
Orientation:= Prn.Orientation;
|
|
end;
|
|
|
|
procedure TfrPage.Clear;
|
|
begin
|
|
while Objects.Count > 0 do
|
|
Delete(0);
|
|
end;
|
|
|
|
procedure TfrPage.Delete(Index: Integer);
|
|
begin
|
|
TfrView(Objects[Index]).Free;
|
|
Objects.Delete(Index);
|
|
end;
|
|
|
|
function TfrPage.FindObjectByID(ID: Integer): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
if TfrView(Objects[i]).ID = ID then
|
|
begin
|
|
Result := i;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrPage.FindObject(aName: String): TfrObject;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
aName:=UpperCase(aName);
|
|
if UpperCase(Name) = aName then
|
|
Result:=Self
|
|
else
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
if UpperCase(TfrObject(Objects[i]).Name) = aName then
|
|
begin
|
|
Result :=TfrObject(Objects[i]);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrPage.FindRTObject(const aName: String): TfrObject;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
if AnsiCompareText(Self.Name, aName) = 0 then
|
|
Result:=Self
|
|
else
|
|
for i := 0 to RTObjects.Count - 1 do
|
|
begin
|
|
if AnsiCompareText(TfrObject(RTObjects[i]).Name, aName) = 0 then
|
|
begin
|
|
Result :=TfrObject(RTObjects[i]);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPage.InitReport;
|
|
var
|
|
b: TfrBandType;
|
|
begin
|
|
for b := btReportTitle to btNone do
|
|
Bands[b] := TfrBand.Create(b, Self);
|
|
while RTObjects.Count > 0 do
|
|
begin
|
|
TfrView(RTObjects[0]).Free;
|
|
RTObjects.Delete(0);
|
|
end;
|
|
TossObjects;
|
|
InitFlag := True;
|
|
CurPos := 1; ColPos := 1;
|
|
end;
|
|
|
|
procedure TfrPage.DoneReport;
|
|
var
|
|
b: TfrBandType;
|
|
begin
|
|
if InitFlag then
|
|
begin
|
|
for b := btReportTitle to btNone do
|
|
Bands[b].Free;
|
|
while RTObjects.Count > 0 do
|
|
begin
|
|
TfrView(RTObjects[0]).Free;
|
|
RTObjects.Delete(0);
|
|
end;
|
|
end;
|
|
InitFlag := False;
|
|
end;
|
|
|
|
function TfrPage.TopMargin: Integer;
|
|
begin
|
|
if UseMargins then
|
|
begin
|
|
if Margins.Top = 0 then
|
|
Result := PrnInfo.Ofy
|
|
else
|
|
Result := Margins.Top;
|
|
end
|
|
else Result := 0;
|
|
end;
|
|
|
|
function TfrPage.BottomMargin: Integer;
|
|
begin
|
|
with PrnInfo do
|
|
if UseMargins then
|
|
if Margins.Bottom = 0 then
|
|
Result:=Ofy+Ph
|
|
else
|
|
Result:=Pgh-Margins.Bottom
|
|
else
|
|
Result:=Pgh;
|
|
if (DocMode <> dmDesigning) and BandExists(Bands[btPageFooter]) then
|
|
Result := Result - Bands[btPageFooter].dy;
|
|
end;
|
|
|
|
function TfrPage.LeftMargin: Integer;
|
|
begin
|
|
if UseMargins then
|
|
begin
|
|
if Margins.Left = 0 then
|
|
Result := PrnInfo.Ofx
|
|
else
|
|
Result := Margins.Left;
|
|
end
|
|
else Result := 0;
|
|
end;
|
|
|
|
function TfrPage.RightMargin: Integer;
|
|
begin
|
|
with PrnInfo do
|
|
begin
|
|
if UseMargins then
|
|
begin
|
|
if Margins.Right = 0 then
|
|
Result := Ofx + Pw
|
|
else
|
|
Result := Pgw - Margins.Right;
|
|
end
|
|
else Result := Pgw;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPage.TossObjects;
|
|
var
|
|
i, j, n, last, miny: Integer;
|
|
b: TfrBandType;
|
|
bt, t: TfrView;
|
|
Bnd, Bnd1: TfrBand;
|
|
FirstBand, Flag: Boolean;
|
|
BArr: Array[0..31] of TfrBand;
|
|
s: String;
|
|
begin
|
|
for i := 0 to Objects.Count - 1 do
|
|
begin
|
|
bt :=TfrView(Objects[i]);
|
|
t := frCreateObject(bt.Typ, bt.ClassName, Self);
|
|
t.Assign(bt);
|
|
t.StreamMode := smPrinting;
|
|
RTObjects.Add(t);
|
|
if (t.Flags and flWantHook) <> 0 then
|
|
HookList.Add(t);
|
|
end;
|
|
|
|
for i := 0 to RTObjects.Count - 1 do // select all objects exclude bands
|
|
begin
|
|
t :=TfrView(RTObjects[i]);
|
|
t.Selected := t.Typ <> gtBand;
|
|
t.Parent := nil;
|
|
frInterpretator.PrepareScript(t.Script, t.Script, SMemo);
|
|
if t.Typ = gtSubReport then
|
|
CurReport.Pages[(t as TfrSubReportView).SubPage].Skip := True;
|
|
end;
|
|
Flag := False;
|
|
for i := 0 to RTObjects.Count - 1 do // search for btCrossXXX bands
|
|
begin
|
|
bt :=TfrView(RTObjects[i]);
|
|
if (bt.Typ = gtBand) and
|
|
(TfrBandView(bt).BandType in [btCrossHeader..btCrossFooter]) then
|
|
with Bands[TfrBandView(bt).BandType] do
|
|
begin
|
|
Memo.Assign(bt.Memo);
|
|
Script.Assign(bt.Script);
|
|
x := bt.x; dx := bt.dx;
|
|
InitDataSet(TfrBandView(bt).DataSet);
|
|
View := bt;
|
|
Flags := bt.Flags;
|
|
Visible := bt.Visible;
|
|
bt.Parent := Bands[TfrBandView(bt).BandType];
|
|
Flag := True;
|
|
end;
|
|
end;
|
|
|
|
if Flag then // fill a ColumnXXX bands at first
|
|
for b := btCrossHeader to btCrossFooter do
|
|
begin
|
|
Bnd := Bands[b];
|
|
for i := 0 to RTObjects.Count - 1 do
|
|
begin
|
|
t :=TfrView(RTObjects[i]);
|
|
if t.Selected then
|
|
if (t.x >= Bnd.x) and (t.x + t.dx <= Bnd.x + Bnd.dx) then
|
|
begin
|
|
t.x := t.x - Bnd.x;
|
|
t.Parent := Bnd;
|
|
Bnd.Objects.Add(t);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
for b := btReportTitle to btGroupFooter do // fill other bands
|
|
begin
|
|
FirstBand := True;
|
|
Bnd := Bands[b];
|
|
BArr[0] := Bnd;
|
|
Last := 1;
|
|
for i := 0 to RTObjects.Count - 1 do // search for specified band
|
|
begin
|
|
bt :=TfrView(RTObjects[i]);
|
|
if (bt.Typ = gtBand) and (TfrBandView(bt).BandType=b) then
|
|
begin
|
|
if not FirstBand then
|
|
begin
|
|
Bnd.Next := TfrBand.Create(b,Self);
|
|
Bnd := Bnd.Next;
|
|
BArr[Last] := Bnd;
|
|
Inc(Last);
|
|
end;
|
|
FirstBand := False;
|
|
Bnd.Memo.Assign(bt.Memo);
|
|
Bnd.Script.Assign(bt.Script);
|
|
Bnd.y := bt.y;
|
|
Bnd.dy := bt.dy;
|
|
Bnd.View := bt;
|
|
Bnd.Flags := bt.Flags;
|
|
Bnd.Visible := bt.Visible;
|
|
bt.Parent := Bnd;
|
|
with bt as TfrBandView, Bnd do
|
|
begin
|
|
if Typ = btGroupHeader then
|
|
InitDataSet(TfrBandView(Bt).fCondition)
|
|
else
|
|
InitDataSet(TfrBandView(Bt).DataSet);
|
|
Stretched := (Flags and flStretched) <> 0;
|
|
PrintIfSubsetEmpty := (Flags and flBandPrintIfSubsetEmpty) <> 0;
|
|
if Skip then
|
|
begin
|
|
NewPageAfter := False;
|
|
PageBreak := False;
|
|
end
|
|
else
|
|
begin
|
|
NewPageAfter := (Flags and flBandNewPageAfter) <> 0;
|
|
PageBreak := (Flags and flBandPageBreak) <> 0;
|
|
end;
|
|
end;
|
|
for j := 0 to RTObjects.Count - 1 do // placing objects over band
|
|
begin
|
|
t :=TfrView(RTObjects[j]);
|
|
if (t.Parent = nil) and (t.Typ <> gtSubReport) then
|
|
if t.Selected then
|
|
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
|
|
begin
|
|
t.Parent := Bnd;
|
|
t.y := t.y - Bnd.y;
|
|
t.Selected := False;
|
|
Bnd.Objects.Add(t);
|
|
end;
|
|
end;
|
|
for j := 0 to RTObjects.Count - 1 do // placing ColumnXXX objects over band
|
|
begin
|
|
t :=TfrView(RTObjects[j]);
|
|
if t.Parent <> nil then
|
|
if t.Selected then
|
|
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
|
|
begin
|
|
t.y := t.y - Bnd.y;
|
|
t.Selected := False;
|
|
Bnd.Objects.Add(t);
|
|
end;
|
|
end;
|
|
for j := 0 to RTObjects.Count - 1 do // placing subreports over band
|
|
begin
|
|
t :=TfrView(RTObjects[j]);
|
|
if (t.Parent = nil) and (t.Typ = gtSubReport) then
|
|
if t.Selected then
|
|
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
|
|
begin
|
|
t.Parent := Bnd;
|
|
t.y := t.y - Bnd.y;
|
|
t.Selected := False;
|
|
Bnd.Objects.Add(t);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
for i := 0 to Last - 1 do // sorting bands
|
|
begin
|
|
miny := BArr[i].y; n := i;
|
|
for j := i + 1 to Last - 1 do
|
|
if BArr[j].y < miny then
|
|
begin
|
|
miny := BArr[j].y;
|
|
n := j;
|
|
end;
|
|
Bnd := BArr[i]; BArr[i] := BArr[n]; BArr[n] := Bnd;
|
|
end;
|
|
Bnd := BArr[0]; Bands[b] := Bnd;
|
|
Bnd.Prev := nil;
|
|
for i := 1 to Last - 1 do // finally ordering
|
|
begin
|
|
Bnd.Next := BArr[i];
|
|
Bnd := Bnd.Next;
|
|
Bnd.Prev := BArr[i - 1];
|
|
end;
|
|
Bnd.Next := nil;
|
|
Bands[b].LastBand := Bnd;
|
|
end;
|
|
|
|
for i := 0 to RTObjects.Count - 1 do // place other objects on btNone band
|
|
begin
|
|
t :=TfrView(RTObjects[i]);
|
|
if t.Selected then
|
|
begin
|
|
t.Parent := Bands[btNone];
|
|
Bands[btNone].y := 0;
|
|
Bands[btNone].Objects.Add(t);
|
|
end;
|
|
end;
|
|
|
|
for i := 1 to MAXBNDS do // connect header & footer to each data-band
|
|
begin
|
|
Bnd := Bands[Bnds[i, bpHeader]];
|
|
while Bnd <> nil do
|
|
begin
|
|
Bnd1 := Bands[Bnds[i, bpData]];
|
|
while Bnd1 <> nil do
|
|
begin
|
|
if Bnd1.y > Bnd.y + Bnd.dy then break;
|
|
Bnd1 := Bnd1.Next;
|
|
end;
|
|
if (Bnd1 <> nil) and (Bnd1.HeaderBand = nil) then
|
|
Bnd1.HeaderBand := Bnd;
|
|
|
|
Bnd := Bnd.Next;
|
|
end;
|
|
|
|
Bnd := Bands[Bnds[i, bpFooter]];
|
|
while Bnd <> nil do
|
|
begin
|
|
Bnd1 := Bands[Bnds[i, bpData]];
|
|
while Bnd1 <> nil do
|
|
begin
|
|
if Bnd1.y + Bnd1.dy > Bnd.y then
|
|
begin
|
|
Bnd1 := Bnd1.Prev;
|
|
break;
|
|
end;
|
|
if Bnd1.Next = nil then break;
|
|
Bnd1 := Bnd1.Next;
|
|
end;
|
|
if (Bnd1 <> nil) and (Bnd1.FooterBand = nil) then
|
|
Bnd1.FooterBand := Bnd;
|
|
|
|
Bnd := Bnd.Next;
|
|
end;
|
|
end;
|
|
|
|
Bnd := Bands[btGroupHeader].LastBand;
|
|
Bnd1 := Bands[btGroupFooter];
|
|
repeat
|
|
Bnd.FooterBand := Bnd1;
|
|
Bnd := Bnd.Prev;
|
|
Bnd1 := Bnd1.Next;
|
|
until (Bnd = nil) or (Bnd1 = nil);
|
|
|
|
if BandExists(Bands[btCrossData]) and (Pos(';', TfrBandView(Bands[btCrossData].View).DataSet) <> 0) then
|
|
begin
|
|
s := TfrBandView(Bands[btCrossData].View).DataSet;
|
|
|
|
i := 1;
|
|
while i < Length(s) do
|
|
begin
|
|
j := i;
|
|
while s[j] <> '=' do Inc(j);
|
|
n := j;
|
|
while s[n] <> ';' do Inc(n);
|
|
for b := btMasterHeader to btGroupFooter do
|
|
begin
|
|
Bnd := Bands[b];
|
|
while Bnd <> nil do
|
|
begin
|
|
if Bnd.View <> nil then
|
|
if AnsiCompareText(Bnd.View.Name, Copy(s, i, j - i)) = 0 then
|
|
CreateDS(Copy(s, j + 1, n - j - 1), Bnd.VCDataSet, Bnd.IsVirtualVCDS);
|
|
Bnd := Bnd.Next;
|
|
end;
|
|
end;
|
|
i := n + 1;
|
|
end;
|
|
end;
|
|
|
|
if ColCount = 0 then ColCount := 1;
|
|
ColWidth := (RightMargin - LeftMargin) div ColCount;
|
|
end;
|
|
|
|
procedure TfrPage.PrepareObjects;
|
|
var
|
|
i, j: Integer;
|
|
t: TfrView;
|
|
Value: TfrValue;
|
|
s: String;
|
|
DSet: TfrTDataSet;
|
|
Field: TfrTField;
|
|
begin
|
|
{$ifdef DebugLR}
|
|
DebugLnEnter('TfrPage.PrepareObjects INIT');
|
|
{$endif}
|
|
|
|
CurPage := Self;
|
|
for i := 0 to RTObjects.Count - 1 do
|
|
begin
|
|
t :=TfrView(RTObjects[i]);
|
|
t.FField := '';
|
|
if t.Memo.Count > 0 then
|
|
s := t.Memo[0];
|
|
j := Length(s);
|
|
if (j > 2) and (s[1] = '[') then
|
|
begin
|
|
while (j > 0) and (s[j] <> ']') do Dec(j);
|
|
s := Copy(s, 2, j - 2);
|
|
t.FDataSet := nil;
|
|
t.FField := '';
|
|
Value := CurReport.Values.FindVariable(s);
|
|
if Value = nil then
|
|
begin
|
|
CurBand := t.Parent;
|
|
DSet := GetDefaultDataset;
|
|
frGetDatasetAndField(s, DSet, Field);
|
|
if Field <> nil then
|
|
begin
|
|
{$ifdef DebugLR}
|
|
DebugLn('For View=%s found Field=%s',[ViewInfo(t),Field.FieldName]);
|
|
{$endif}
|
|
t.FDataSet := DSet;
|
|
t.FField := Field.FieldName;
|
|
end;
|
|
end
|
|
else if Value.Typ = vtDBField then
|
|
if Value.DSet <> nil then
|
|
begin
|
|
t.FDataSet := Value.DSet;
|
|
t.FField := Value.Field;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ifdef DebugLR}
|
|
DebugLnExit('TfrPage.PrepareObjects DONE');
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrPage.ShowBand(b: TfrBand);
|
|
begin
|
|
if b <> nil then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn;
|
|
DebugLnEnter('TfrPage.ShowBand INI Band=%s',[BandInfo(b)]);
|
|
{$ENDIF}
|
|
if Mode = pmBuildList then
|
|
AddRecord(b, rtShowBand) else
|
|
b.Draw;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrPage.ShowBand END Band=%s',[BandInfo(b)]);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
constructor TfrPage.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
FillChar(Bands, 0, SizeOf(Bands));
|
|
|
|
fMargins:=TfrRect.Create;
|
|
BaseName:='Page';
|
|
|
|
List := TFpList.Create;
|
|
Objects := TFpList.Create;
|
|
RTObjects := TFpList.Create;
|
|
PageType:=ptReport; //todo: - remove this
|
|
end;
|
|
|
|
procedure TfrPage.ShowBandByName(const s: String);
|
|
var
|
|
bt: TfrBandType;
|
|
b: TfrBand;
|
|
begin
|
|
for bt := btReportTitle to btNone do
|
|
begin
|
|
b := Bands[bt];
|
|
while b <> nil do
|
|
begin
|
|
if b.View <> nil then
|
|
if AnsiCompareText(b.View.Name, s) = 0 then
|
|
begin
|
|
b.Draw;
|
|
Exit;
|
|
end;
|
|
b := b.Next;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPage.ShowBandByType(bt: TfrBandType);
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
b := Bands[bt];
|
|
if b <> nil then
|
|
b.Draw;
|
|
end;
|
|
|
|
procedure TfrPage.AddRecord(b: TfrBand; rt: TfrBandRecType);
|
|
var
|
|
p: PfrBandRec;
|
|
begin
|
|
GetMem(p, SizeOf(TfrBandRec));
|
|
p^.Band := b;
|
|
p^.Action := rt;
|
|
List.Add(p);
|
|
end;
|
|
|
|
procedure TfrPage.ClearRecList;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to List.Count - 1 do
|
|
FreeMem(PfrBandRec(List[i]), SizeOf(TfrBandRec));
|
|
List.Clear;
|
|
end;
|
|
|
|
function TfrPage.PlayRecList: Boolean;
|
|
var
|
|
p: PfrBandRec;
|
|
b: TfrBand;
|
|
begin
|
|
Result := False;
|
|
while PlayFrom < List.Count do
|
|
begin
|
|
p := List[PlayFrom];
|
|
b := p^.Band;
|
|
case p^.Action of
|
|
rtShowBand:
|
|
begin
|
|
if LastBand <> nil then
|
|
begin
|
|
LastBand.DoSubReports;
|
|
if LastBand <> nil then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
if b.Draw then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
rtFirst:
|
|
begin
|
|
b.DataSet.First;
|
|
b.Positions[psLocal] := 1;
|
|
end;
|
|
rtNext:
|
|
begin
|
|
b.DataSet.Next;
|
|
Inc(CurPos);
|
|
Inc(b.Positions[psGlobal]);
|
|
Inc(b.Positions[psLocal]);
|
|
end;
|
|
end;
|
|
Inc(PlayFrom);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPage.DrawPageFooters;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TFrPage.DrawPageFootersPage INI PageNo=%d XAdjust=%d CurColumn=%d',
|
|
[PageNo, XAdjust, CurColumn]);
|
|
{$ENDIF}
|
|
CurColumn := 0;
|
|
XAdjust := LeftMargin;
|
|
if (PageNo <> 0) or ((Bands[btPageFooter].Flags and flBandOnFirstPage) <> 0) then
|
|
while PageNo < MasterReport.EMFPages.Count do
|
|
begin
|
|
if not (Append and WasPF) then
|
|
begin
|
|
if CurReport <> nil then
|
|
CurReport.DoEndPage(PageNo);
|
|
if (MasterReport <> CurReport) and (MasterReport <> nil) then
|
|
MasterReport.DoEndPage(PageNo);
|
|
if not RowsLayout then
|
|
ShowBand(Bands[btPageFooter]);
|
|
end;
|
|
Inc(PageNo);
|
|
end;
|
|
PageNo := MasterReport.EMFPages.Count;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TFrPage.DrawPageFootersPage FIN PageNo=%d XAdjust=%d CurColumn=%d',
|
|
[PageNo, XAdjust, CurColumn]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrPage.NewPage;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TFrPage.NewPage INI PageNo=%d CurBottomY=%d CurY=%d XAdjust=%d',
|
|
[PageNo, CurBottomY, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
|
|
CurReport.InternalOnProgress(PageNo + 1);
|
|
if not RowsLayout then
|
|
ShowBand(Bands[btColumnFooter]);
|
|
DrawPageFooters;
|
|
CurBottomY := BottomMargin;
|
|
MasterReport.EMFPages.Add(Self);
|
|
Append := False;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('---- Start of new page ----');
|
|
{$ENDIF}
|
|
ShowBand(Bands[btOverlay]);
|
|
CurY := TopMargin;
|
|
ShowBand(Bands[btPageHeader]);
|
|
if not RowsLayout then
|
|
ShowBand(Bands[btColumnHeader]);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TFrPage.NewPage END PageNo=%d CurBottomY=%d CurY=%d XAdjust=%d',
|
|
[PageNo, CurBottomY, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrPage.NewColumn(Band: TfrBand);
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrPage.NewColumn INI CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
|
|
[CurColumn, ColCount, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
if CurColumn < ColCount - 1 then
|
|
begin
|
|
ShowBand(Bands[btColumnFooter]);
|
|
Inc(CurColumn);
|
|
Inc(XAdjust, ColWidth + ColGap);
|
|
CurY := LastStaticColumnY;
|
|
ShowBand(Bands[btColumnHeader]);
|
|
end
|
|
else
|
|
NewPage;
|
|
b := Bands[btGroupHeader];
|
|
if b <> nil then
|
|
while (b <> nil) and (b <> Band) do
|
|
begin
|
|
b.DisableInit := True;
|
|
if (b.Flags and flBandRepeatHeader) <> 0 then
|
|
ShowBand(b);
|
|
b.DisableInit := False;
|
|
b := b.Next;
|
|
end;
|
|
if Band.Typ in [btMasterData, btDetailData, btSubDetailData] then
|
|
begin
|
|
if (Band.HeaderBand <> nil) and
|
|
((Band.HeaderBand.Flags and flBandRepeatHeader) <> 0) then
|
|
ShowBand(Band.HeaderBand);
|
|
Band.ResetLastValues;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrPage.NewColumn END CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
|
|
[CurColumn, ColCount, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrPage.NextColumn(Band: TFrBand);
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrPage.NextColumn INI CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
|
|
[CurColumn, ColCount, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
if CurColumn < ColCount - 1 then
|
|
begin
|
|
Inc(CurColumn);
|
|
Inc(XAdjust, ColWidth + ColGap);
|
|
Inc(ColPos);
|
|
end
|
|
else
|
|
StartColumn;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrPage.NextColumn END CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
|
|
[CurColumn, ColCount, CurY, XAdjust]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrPage.RowsLayout: boolean;
|
|
begin
|
|
result := (ColCount>1) and (LayoutOrder=loRows)
|
|
end;
|
|
|
|
procedure TfrPage.StartColumn;
|
|
begin
|
|
CurColumn := 0;
|
|
ColPos:=1;
|
|
XAdjust := LeftMargin;
|
|
end;
|
|
|
|
procedure TfrPage.StartRowsLayoutNonDataBand(Band: TfrBand);
|
|
begin
|
|
|
|
// reset starting column
|
|
if Band.ForceNewPage then begin
|
|
CurColumn := ColCount - 1;
|
|
NewColumn(Band);
|
|
end else
|
|
StartColumn;
|
|
|
|
// check for partial rows
|
|
if LastBandType in [btMasterData, btDetailData, btSubdetailData] then
|
|
begin
|
|
if not RowStarted then
|
|
Inc(CurY, LastRowHeight);
|
|
end;
|
|
|
|
end;
|
|
|
|
function TfrPage.AdvanceRow(Band: TfrBand): boolean;
|
|
begin
|
|
result := not RowsLayout or (not Band.IsDataBand) or (CurColumn=ColCount-1);
|
|
RowStarted := result;
|
|
end;
|
|
|
|
procedure TfrPage.DoAggregate(a: Array of TfrBandType);
|
|
var
|
|
i: Integer;
|
|
procedure DoAggregate1(bt: TfrBandType);
|
|
var
|
|
b: TfrBand;
|
|
begin
|
|
b := Bands[bt];
|
|
while b <> nil do
|
|
begin
|
|
b.DoAggregate;
|
|
b := b.Next;
|
|
end;
|
|
end;
|
|
begin
|
|
for i := Low(a) to High(a) do
|
|
DoAggregate1(a[i]);
|
|
end;
|
|
|
|
procedure TfrPage.FormPage;
|
|
type
|
|
TBookRecord = record
|
|
Dataset: TfrDataset;
|
|
Bookmark: Pointer;
|
|
end;
|
|
var
|
|
BndStack: Array[1..MAXBNDS * 3] of TfrBand;
|
|
MaxLevel, BndStackTop: Integer;
|
|
i, sfPage : Integer;
|
|
HasGroups : Boolean;
|
|
DetailCount : Integer;
|
|
BooksBkUp : array of TBookRecord;
|
|
CurGroupValue : variant;
|
|
BookPrev : pointer;
|
|
{$IFDEF DebugLR}
|
|
mys : string;
|
|
{$ENDIF}
|
|
|
|
procedure AddToStack(b: TfrBand);
|
|
begin
|
|
if b <> nil then
|
|
begin
|
|
Inc(BndStackTop);
|
|
BndStack[BndStackTop] := b;
|
|
end;
|
|
end;
|
|
|
|
procedure BackupBookmark(b: TfrBand);
|
|
var
|
|
n: Integer;
|
|
begin
|
|
if b.Dataset <> nil then
|
|
begin
|
|
n := Length(BooksBkUp);
|
|
SetLength(BooksBkUp, n+1);
|
|
BooksBkUp[n].Dataset := b.Dataset;
|
|
BooksBkUp[n].Bookmark := b.Dataset.GetBookmark;
|
|
end;
|
|
if b.Typ in [btDetailData,btSubDetailData] then
|
|
inc(DetailCount);
|
|
end;
|
|
|
|
procedure RestoreBookmarks;
|
|
var
|
|
n: Integer;
|
|
begin
|
|
for n:=0 to Length(BooksBkUp)-1 do
|
|
with BooksBkUp[n] do begin
|
|
Dataset.GotoBookMark(Bookmark);
|
|
Dataset.FreeBookMark(Bookmark);
|
|
if DetailCount=0 then
|
|
Dataset.EnableControls;
|
|
end;
|
|
SetLength(BooksBkUp, 0);
|
|
end;
|
|
|
|
procedure DisableControls;
|
|
var
|
|
n: Integer;
|
|
begin
|
|
if DetailCount=0 then
|
|
for n:=0 to Length(BooksBkUp)-1 do
|
|
BooksBkUp[n].Dataset.DisableControls;
|
|
end;
|
|
|
|
procedure ShowStack;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('ShowStack INI');
|
|
{$ENDIF}
|
|
for i := 1 to BndStackTop do
|
|
if BandExists(BndStack[i]) then
|
|
ShowBand(BndStack[i]);
|
|
BndStackTop := 0;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('ShowStack END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure DoLoop(Level: Integer);
|
|
var
|
|
WasPrinted: Boolean;
|
|
b, b1, b2: TfrBand;
|
|
procedure InitGroups(b: TfrBand);
|
|
begin
|
|
while b <> nil do
|
|
begin
|
|
Inc(b.Positions[psLocal]);
|
|
Inc(b.Positions[psGlobal]);
|
|
ShowBand(b);
|
|
b := b.Next;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
b := Bands[Bnds[Level, bpData]];
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('Doop(Level=%d) INI b=%s mode=',[Level,bandinfo(b)]);
|
|
{$ENDIF}
|
|
while (b <> nil) and (b.Dataset <> nil) do
|
|
begin
|
|
b.ResetLastValues;
|
|
try
|
|
b.DataSet.First;
|
|
|
|
//if Level<>1 then begin
|
|
// b.Dataset.Refresh;
|
|
//end;
|
|
|
|
if Mode = pmBuildList then
|
|
AddRecord(b, rtFirst)
|
|
else
|
|
b.Positions[psLocal] := 1;
|
|
|
|
b1 := Bands[btGroupHeader];
|
|
while b1 <> nil do
|
|
begin
|
|
b1.Positions[psLocal] := 0;
|
|
b1.Positions[psGlobal] := 0;
|
|
b1 := b1.Next;
|
|
end;
|
|
|
|
if not b.DataSet.Eof then
|
|
begin
|
|
if (Level = 1) and HasGroups then
|
|
InitGroups(Bands[btGroupHeader]);
|
|
if b.HeaderBand <> nil then
|
|
AddToStack(b.HeaderBand);
|
|
if b.FooterBand <> nil then
|
|
b.FooterBand.InitValues;
|
|
|
|
while not b.DataSet.Eof do
|
|
begin
|
|
Application.ProcessMessages;
|
|
if MasterReport.Terminated then
|
|
break;
|
|
AddToStack(b);
|
|
WasPrinted := True;
|
|
if Level < MaxLevel then
|
|
begin
|
|
DoLoop(Level + 1);
|
|
if BndStackTop > 0 then
|
|
if b.PrintIfSubsetEmpty then
|
|
ShowStack
|
|
else
|
|
begin
|
|
Dec(BndStackTop);
|
|
WasPrinted := False;
|
|
end;
|
|
end
|
|
else
|
|
ShowStack;
|
|
|
|
if (Level = 1) and HasGroups then
|
|
begin
|
|
// get a bookmark to current record it will be used in case
|
|
// a group change is detected and there are remaining group
|
|
// footers.
|
|
BookPrev := b.DataSet.GetBookMark;
|
|
try
|
|
b.DataSet.Next;
|
|
b1 := Bands[btGroupHeader];
|
|
while b1 <> nil do
|
|
begin
|
|
if not b.dataset.eof then
|
|
curGroupValue := frParser.Calc(b1.GroupCondition);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('GroupCondition=%s LastGroupValue=%s curGroupValue=%s',
|
|
[b1.GroupCondition,varstr(b1.LastGroupValue),varstr(curGroupValue)]);
|
|
{$ENDIF}
|
|
if b.dataset.eof or (curGroupValue <> b1.LastGroupValue) then
|
|
begin
|
|
// next bands should be printed on the previous record context
|
|
// if we have a valid bookmark to previous record
|
|
if BookPrev<>nil then
|
|
b.DataSet.GotoBookMark(BookPrev);
|
|
ShowBand(b.FooterBand);
|
|
b2 := Bands[btGroupHeader].LastBand;
|
|
while b2 <> b1 do
|
|
begin
|
|
ShowBand(b2.FooterBand);
|
|
b2.Positions[psLocal] := 0;
|
|
b2 := b2.Prev;
|
|
end;
|
|
ShowBand(b1.FooterBand);
|
|
// advance to the actual current record
|
|
// if we really were on previous record
|
|
if BookPrev<>nil then
|
|
b.DataSet.Next;
|
|
if not b.Dataset.Eof then
|
|
begin
|
|
if b1.NewPageAfter then NewPage;
|
|
InitGroups(b1);
|
|
ShowBand(b.HeaderBand);
|
|
b.Positions[psLocal] := 0;
|
|
end;
|
|
b.ResetLastValues;
|
|
break;
|
|
end;
|
|
b1 := b1.Next;
|
|
end;
|
|
finally
|
|
b.DataSet.FreeBookMark(BookPrev);
|
|
end;
|
|
end else
|
|
b.DataSet.Next;
|
|
|
|
if Mode = pmBuildList then
|
|
AddRecord(b, rtNext)
|
|
else if WasPrinted then
|
|
begin
|
|
Inc(CurPos);
|
|
Inc(b.Positions[psGlobal]);
|
|
Inc(b.Positions[psLocal]);
|
|
if not b.DataSet.Eof and b.NewPageAfter then
|
|
begin
|
|
NewPage;
|
|
b.ResetLastValues;
|
|
end;
|
|
end;
|
|
if MasterReport.Terminated then
|
|
break;
|
|
end;
|
|
if BndStackTop = 0 then
|
|
ShowBand(b.FooterBand) else
|
|
Dec(BndStackTop);
|
|
end else
|
|
if b.PrintIfSubsetEmpty then begin
|
|
if b.HeaderBand <> nil then
|
|
ShowBand(b.HeaderBand);
|
|
if b.FooterBand <> nil then begin
|
|
b.FooterBand.InitValues;
|
|
ShowBand(b.FooterBand);
|
|
end;
|
|
end;
|
|
finally
|
|
end;
|
|
b := b.Next;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('Doop(Level=%d) END',[Level]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
WriteStr(Mys, Mode);
|
|
DebugLnEnter('TfrPage.FormPage INI Mode=%s',[MyS]);
|
|
{$ENDIF}
|
|
if Mode = pmNormal then
|
|
begin
|
|
if Append then
|
|
begin
|
|
if PrevY = PrevBottomY then
|
|
begin
|
|
Append := False;
|
|
WasPF := False;
|
|
PageNo := MasterReport.EMFPages.Count;
|
|
end;
|
|
end;
|
|
|
|
if Append and WasPF then
|
|
CurBottomY := PrevBottomY
|
|
else
|
|
CurBottomY := BottomMargin;
|
|
|
|
CurColumn := 0;
|
|
XAdjust := LeftMargin;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('XAdjust=%d CurBottomY=%d PrevY=%d',[XAdjust,CurBottomY,PrevY]);
|
|
{$ENDIF}
|
|
if not Append then
|
|
begin
|
|
MasterReport.EMFPages.Add(Self);
|
|
CurY := TopMargin;
|
|
ShowBand(Bands[btOverlay]);
|
|
ShowBand(Bands[btNone]);
|
|
end
|
|
else
|
|
CurY := PrevY;
|
|
sfPage := PageNo;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('XAdjust=%d CurY=%d sfPage=%d',[XAdjust,CurY,sfpage]);
|
|
{$ENDIF}
|
|
ShowBand(Bands[btReportTitle]);
|
|
if PageNo = sfPage then // check if new page was formed
|
|
begin
|
|
if BandExists(Bands[btPageHeader]) and
|
|
((Bands[btPageHeader].Flags and flBandOnFirstPage) <> 0) then
|
|
ShowBand(Bands[btPageHeader]);
|
|
if not RowsLayout then
|
|
ShowBand(Bands[btColumnHeader]);
|
|
end;
|
|
end;
|
|
|
|
BndStackTop := 0;
|
|
SetLength(BooksBkUp, 0);
|
|
DetailCount := 0;
|
|
for i := 1 to MAXBNDS do
|
|
begin
|
|
if BandExists(Bands[Bnds[i, bpData]]) then
|
|
begin
|
|
MaxLevel := i;
|
|
BackupBookmark(Bands[Bnds[i, bpData]]);
|
|
end;
|
|
end;
|
|
HasGroups := Bands[btGroupHeader].Objects.Count > 0;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('GroupsCount=%d MaxLevel=%d doing DoLoop(1)',[
|
|
Bands[btGroupHeader].Objects.Count, MaxLevel]);
|
|
{$ENDIF}
|
|
DisableControls;
|
|
DoLoop(1);
|
|
RestoreBookmarks; // this also enablecontrols
|
|
if Mode = pmNormal then
|
|
begin
|
|
if not RowsLayout then
|
|
ShowBand(Bands[btColumnFooter]);
|
|
ShowBand(Bands[btReportSummary]);
|
|
PrevY := CurY;
|
|
PrevBottomY := CurBottomY;
|
|
if CurColumn > 0 then
|
|
PrevY := BottomMargin;
|
|
CurColumn := 0;
|
|
XAdjust := LeftMargin;
|
|
sfPage := PageNo;
|
|
WasPF := False;
|
|
if (Bands[btPageFooter].Flags and flBandOnLastPage) <> 0 then
|
|
begin
|
|
WasPF := BandExists(Bands[btPageFooter]);
|
|
if WasPF then
|
|
DrawPageFooters;
|
|
end;
|
|
PageNo := sfPage + 1;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrPage.FormPage END PrevY=%d PrevBottomY=%d PageNo=%d XAdjust=%d',
|
|
[PrevY,PrevBottomY,PageNo,XAdjust]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrPage.BandExists(b: TfrBand): Boolean;
|
|
begin
|
|
Result := b.Objects.Count > 0;
|
|
end;
|
|
|
|
procedure TfrPage.AfterPrint;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to HookList.Count - 1 do
|
|
TfrView(HookList[i]).OnHook(CurView);
|
|
end;
|
|
|
|
procedure TfrPage.AfterLoad;
|
|
var
|
|
i:integer;
|
|
begin
|
|
for i:=0 to Objects.Count - 1 do
|
|
TfrObject(Objects[i]).AfterLoad;
|
|
end;
|
|
|
|
procedure TfrPage.LoadFromStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
s: String[6];
|
|
Bool : WordBool;
|
|
Rc : TRect;
|
|
APageType:TfrPageType; //todo: - remove this
|
|
begin
|
|
with Stream do
|
|
begin
|
|
Read(pgSize, 4);
|
|
Read(dx, 4); //Width
|
|
Read(dy, 4); //Height
|
|
Read(Rc{%H-}, Sizeof(Rc));
|
|
Margins.AsRect:=Rc;
|
|
b := 0;
|
|
Read(b, 1);
|
|
Orientation:=TPrinterOrientation(b);
|
|
if frVersion < 23 then
|
|
Read({%H-}s[1], 6);
|
|
Bool := false;
|
|
Read(Bool, 2);
|
|
PrintToPrevPage:=Bool;
|
|
Read(Bool, 2);
|
|
UseMargins:=Bool;
|
|
Read(fColCount, 4);
|
|
Read(fColGap, 4);
|
|
if frVersion>=24 then //todo: - remove this
|
|
Read(APageType, SizeOf(TfrPageType)); //todo: - remove this
|
|
if frVersion>=25 then
|
|
Read(fLayoutOrder, 4);
|
|
end;
|
|
ChangePaper(pgSize, Width, Height, Orientation);
|
|
end;
|
|
|
|
procedure TfrPage.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
b:byte;
|
|
begin
|
|
inherited LoadFromXML(XML,Path);
|
|
|
|
dx := XML.GetValue(Path+'Width/Value'{%H-}, 0); // TODO chk
|
|
dy := XML.GetValue(Path+'Height/Value'{%H-}, 0); // TODO chk
|
|
{ b := XML.GetValue(Path+'PageType/Value'{%H-}, ord(PageType));
|
|
PageType:=TfrPageType(b);}
|
|
|
|
Script.Text:=XML.GetValue(Path+'Script/Value'{%H-}, '');
|
|
end;
|
|
|
|
procedure TfrPage.SaveToStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
Bool : WordBool;
|
|
Rc : TRect;
|
|
begin
|
|
with Stream do
|
|
begin
|
|
Write(pgSize, 4);
|
|
Write(Width, 4);
|
|
Write(Height, 4);
|
|
Rc:=Margins.AsRect;
|
|
Write(Rc, Sizeof(Rc));
|
|
b := Byte(Orientation);
|
|
Write(b, 1);
|
|
Bool:=PrintToPrevPage;
|
|
Write(Bool, 2);
|
|
Bool:=UseMargins;
|
|
Write(Bool, 2);
|
|
Write(ColCount, 4);
|
|
Write(ColGap, 4);
|
|
// new in 2.4
|
|
Write(ord(PageType), SizeOf(TfrPageType)); //todo: - remove this
|
|
// new in 2.5
|
|
Write(LayoutOrder, 4);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPage.SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
Inherited SavetoXML(XML,Path);
|
|
XML.SetValue(Path+'Width/Value'{%H-}, Width);
|
|
XML.SetValue(Path+'Height/Value'{%H-}, Height);
|
|
// XML.SetValue(Path+'PageType/Value'{%H-}, ord(PageType));
|
|
XML.SetValue(Path+'Script/Value'{%H-}, Script.Text);
|
|
end;
|
|
|
|
{-----------------------------------------------------------------------}
|
|
constructor TfrPages.Create(AParent: TfrReport);
|
|
begin
|
|
inherited Create;
|
|
Parent := AParent;
|
|
FPages := TFpList.Create;
|
|
end;
|
|
|
|
destructor TfrPages.Destroy;
|
|
begin
|
|
Clear;
|
|
FPages.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TfrPages.GetCount: Integer;
|
|
begin
|
|
Result := FPages.Count;
|
|
end;
|
|
|
|
function TfrPages.GetPages(Index: Integer): TfrPage;
|
|
begin
|
|
Result :=TfrPage(FPages[Index]);
|
|
end;
|
|
|
|
procedure TfrPages.AfterLoad;
|
|
var
|
|
i:integer;
|
|
begin
|
|
for i := 0 to Count - 1 do // adding pages at first
|
|
Pages[i].AfterLoad;
|
|
end;
|
|
|
|
procedure TfrPages.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FPages.Count - 1 do
|
|
Pages[i].Free;
|
|
FPages.Clear;
|
|
end;
|
|
|
|
procedure TfrPages.Add(const aClassName : string='TfrPageReport');
|
|
Var Pg : TFrPage;
|
|
Rf : TFrPageClass;
|
|
begin
|
|
Pg:=nil;
|
|
|
|
Rf:=TFrPageClass(GetClass(aClassName));
|
|
if Assigned(Rf) then
|
|
begin
|
|
Pg:=Rf.CreatePage;
|
|
|
|
if Assigned(Pg) then
|
|
begin
|
|
Pg.CreateUniqueName;
|
|
FPages.Add(Pg);
|
|
end;
|
|
end
|
|
else showMessage(Format('Class %s not found',[aClassName]))
|
|
end;
|
|
|
|
procedure TfrPages.Delete(Index: Integer);
|
|
begin
|
|
Pages[Index].Free;
|
|
FPages.Delete(Index);
|
|
end;
|
|
|
|
procedure TfrPages.LoadFromStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
t: TfrView;
|
|
s: String;
|
|
buf: String[8];
|
|
|
|
procedure AddObject(ot: Byte; clname: String);
|
|
begin
|
|
Stream.Read(b, 1);
|
|
Pages[b].Objects.Add(frCreateObject(ot, clname, Pages[b]));
|
|
t :=TfrView(Pages[b].Objects.Items[Pages[b].Objects.Count - 1]);
|
|
end;
|
|
|
|
begin
|
|
Clear;
|
|
Stream.Read(Parent.PrintToDefault, 2);
|
|
Stream.Read(Parent.DoublePass, 2);
|
|
Parent.SetPrinterTo(ReadString(Stream));
|
|
while Stream.Position < Stream.Size do
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrPages.LoadFromStream');
|
|
{$ENDIF}
|
|
Stream.Read(b, 1);
|
|
if b = $FF then // page info
|
|
begin
|
|
if frVersion>23 then
|
|
begin
|
|
S:=ReadString(Stream);
|
|
Add(S);
|
|
end
|
|
else
|
|
Add;
|
|
Pages[Count - 1].LoadFromStream(Stream);
|
|
end
|
|
else if b = $FE then // values
|
|
begin
|
|
Parent.FVal.ReadBinaryData(Stream);
|
|
ReadMemo(Stream, SMemo);
|
|
Parent.Variables.Assign(SMemo);
|
|
end
|
|
else if b = $FD then // datasets
|
|
begin
|
|
if frDataManager <> nil then
|
|
frDataManager.LoadFromStream(Stream);
|
|
break;
|
|
end
|
|
else
|
|
begin
|
|
if b > Integer(gtAddIn) then
|
|
begin
|
|
raise Exception.Create('');
|
|
break;
|
|
end;
|
|
s := '';
|
|
if b = gtAddIn then
|
|
begin
|
|
s := ReadString(Stream);
|
|
if UpperCase(s) = 'TFRFRAMEDMEMOVIEW' then
|
|
AddObject(gtMemo, '')
|
|
else
|
|
AddObject(gtAddIn, s);
|
|
end
|
|
else
|
|
AddObject(b, '');
|
|
t.LoadFromStream(Stream);
|
|
if UpperCase(s) = 'TFRFRAMEDMEMOVIEW' then
|
|
Stream.Read({%H-}buf[1], 8);
|
|
end;
|
|
end;
|
|
AfterLoad;
|
|
end;
|
|
|
|
procedure TfrPages.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
t: TfrView;
|
|
procedure AddObject(aPage: TFrPage; ot: Byte; clname: String);
|
|
begin
|
|
aPage.Objects.Add(frCreateObject(ot, clname, aPage));
|
|
t :=TfrView(aPage.Objects.Items[aPage.Objects.Count - 1]);
|
|
end;
|
|
var
|
|
i,j,aCount,oCount: Integer;
|
|
aTyp: byte;
|
|
aPath,aSubPath,clName: string;
|
|
begin
|
|
Clear;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrPages.LoadFromXML: LoadingFrom: ', Path);
|
|
{$ENDIF}
|
|
Parent.PrintToDefault:= XML.GetValue(Path+'PrintToDefault/Value'{%H-}, True);
|
|
Parent.DoublePass := XML.GetValue(Path+'DoublePass/Value'{%H-}, False); // TODO: check default
|
|
clName := XML.GetValue(Path+'SelectedPrinter/Value','');
|
|
Parent.SetPrinterTo(clName); // TODO: check default
|
|
aCount := XML.GetValue(Path+'PageCount/Value'{%H-}, 0);
|
|
for i := 0 to aCount - 1 do // adding pages at first
|
|
begin
|
|
aPath := Path+'Page'+IntToStr(i+1)+'/';
|
|
clname:= XML.GetValue(aPath+'ClassName/Value', 'TFRPAGEREPORT');
|
|
add(clName);
|
|
|
|
Inc(Pages[i].fUpdate);
|
|
Pages[i].LoadFromXML(XML, aPath);
|
|
Dec(Pages[i].fUpdate);
|
|
|
|
oCount := XML.GetValue(aPath+'ObjectCount/Value'{%H-}, 0);
|
|
for j:=0 to oCount - 1 do
|
|
begin
|
|
aSubPath := aPath + 'Object'+IntTostr(j+1)+'/';
|
|
aTyp := StrTofrTypeObject(XML.GetValue(aSubPath+'Typ/Value', '0'));
|
|
if aTyp>gtAddin then
|
|
raise Exception.Create('');
|
|
clname := XML.GetValue(aSubPath+'ClassName/Value', 'TFRVIEW'); // TODO: Check default
|
|
if aTyp=gtAddin then
|
|
begin
|
|
if UpperCase(clname)='TFRFRAMEDMEMOVIEW' then
|
|
addObject(Pages[i], gtMemo, '')
|
|
else
|
|
addObject(Pages[i], gtAddin, clName)
|
|
end else
|
|
AddObject(Pages[i], aTyp, '');
|
|
Inc(t.fUpdate);
|
|
t.LoadFromXML(XML, aSubPath);
|
|
Dec(t.fUpdate);
|
|
end;
|
|
end;
|
|
Parent.FVal.ReadBinaryDataFromXML(XML, Path+'FVal/');
|
|
Parent.Variables.Text:= XML.GetValue(Path+'ParentVars/Value', '' );
|
|
if frDataManager<>nil then
|
|
frDatamanager.LoadFromXML(XML, Path+'Datamanager/');
|
|
AfterLoad;
|
|
end;
|
|
|
|
procedure TfrPages.SaveToStream(Stream: TStream);
|
|
var
|
|
b: Byte;
|
|
i, j: Integer;
|
|
t: TfrView;
|
|
begin
|
|
Stream.Write(Parent.PrintToDefault, 2);
|
|
Stream.Write(Parent.DoublePass, 2);
|
|
frWriteString(Stream, Prn.Printers[Prn.PrinterIndex]);
|
|
for i := 0 to Count - 1 do // adding pages at first
|
|
begin
|
|
b := $FF;
|
|
Stream.Write(b, 1); // page info
|
|
frWriteString(Stream, Pages[i].Classname);
|
|
Pages[i].SaveToStream(Stream);
|
|
end;
|
|
for i := 0 to Count - 1 do
|
|
begin
|
|
for j := 0 to Pages[i].Objects.Count - 1 do // then adding objects
|
|
begin
|
|
t :=TfrView(Pages[i].Objects[j]);
|
|
b := Byte(t.Typ);
|
|
Stream.Write(b, 1);
|
|
if t.Typ = gtAddIn then
|
|
frWriteString(Stream, t.ClassName);
|
|
Stream.Write(i, 1);
|
|
t.SaveToStream(Stream);
|
|
end;
|
|
end;
|
|
b := $FE;
|
|
Stream.Write(b, 1);
|
|
Parent.FVal.WriteBinaryData(Stream);
|
|
SMemo.Assign(Parent.Variables);
|
|
frWriteMemo(Stream, SMemo);
|
|
if frDataManager <> nil then
|
|
begin
|
|
b := $FD;
|
|
Stream.Write(b, 1);
|
|
frDataManager.SaveToStream(Stream);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPages.SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
i, j: Integer;
|
|
t: TfrView;
|
|
aPath,aSubPath: String;
|
|
begin
|
|
XML.SetValue(Path+'PrintToDefault/Value'{%H-}, Parent.PrintToDefault);
|
|
XML.SetValue(Path+'DoublePass/Value'{%H-}, Parent.DoublePass);
|
|
XML.SetValue(Path+'SelectedPrinter/Value', Prn.Printers[Prn.PrinterIndex]);
|
|
XML.SetValue(Path+'PageCount/Value'{%H-}, Count);
|
|
for i := 0 to Count - 1 do // adding pages at first
|
|
begin
|
|
aPath := Path+'Page'+IntToStr(i+1)+'/';
|
|
Pages[i].SaveToXML(XML, aPath);
|
|
XML.SetValue(aPath+'ObjectCount/Value'{%H-}, Pages[i].Objects.count);
|
|
for j:=0 to Pages[i].Objects.count - 1 do
|
|
begin
|
|
aSubPath := aPath + 'Object'+IntTostr(j+1)+'/';
|
|
T := TfrView(Pages[i].Objects[j]);
|
|
T.SaveToXML(XML, aSubPath);
|
|
end;
|
|
end;
|
|
Parent.FVal.WriteBinaryDataToXML(XML, Path+'FVal/');
|
|
XML.SetValue(Path+'ParentVars/Value',Parent.Variables.Text);
|
|
if frDataManager <> nil then
|
|
begin
|
|
frDataManager.SaveToXML(XML, Path+'Datamanager/');
|
|
end;
|
|
end;
|
|
|
|
function TfrPages.PageByName(APageName: string): TfrPage;
|
|
var
|
|
i:integer;
|
|
begin
|
|
APageName:=UpperCase(APageName);
|
|
Result:=nil;
|
|
for i:=0 to FPages.Count - 1 do
|
|
if APageName = UpperCase(TfrPage(FPages[i]).Name) then
|
|
begin
|
|
Result:=TfrPage(FPages[i]);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
{-----------------------------------------------------------------------}
|
|
constructor TfrEMFPages.Create(AParent: TfrReport);
|
|
begin
|
|
inherited Create;
|
|
Parent := AParent;
|
|
FPages := TFpList.Create;
|
|
end;
|
|
|
|
destructor TfrEMFPages.Destroy;
|
|
begin
|
|
Clear;
|
|
FPages.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TfrEMFPages.GetCount: Integer;
|
|
begin
|
|
Result := FPages.Count;
|
|
end;
|
|
|
|
function TfrEMFPages.GetPages(Index: Integer): PfrPageInfo;
|
|
begin
|
|
Result := FPages[Index];
|
|
end;
|
|
|
|
procedure TfrEMFPages.Clear;
|
|
begin
|
|
while FPages.Count > 0 do
|
|
Delete(0);
|
|
end;
|
|
|
|
procedure TfrEMFPages.Draw(Index: Integer; Canvas: TCanvas; DrawRect: TRect);
|
|
var
|
|
p: PfrPageInfo;
|
|
t: TfrView;
|
|
i: Integer;
|
|
sx, sy: Double;
|
|
v, IsPrinting: Boolean;
|
|
h: THandle;
|
|
begin
|
|
IsPrinting := Printer.Printing and (Canvas is TPrinterCanvas);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrEMFPages.Draw IsPrinting=%d PageIndex=%d Canvas.ClassName=%s '+
|
|
'CanvasPPI=%d',[ord(IsPrinting), Index, Canvas.ClassName,
|
|
Canvas.Font.pixelsPerInch]);
|
|
{$ENDIF}
|
|
|
|
DocMode := dmPrinting;
|
|
p := FPages[Index];
|
|
with p^ do
|
|
begin
|
|
if Visible then
|
|
begin
|
|
if Page = nil then
|
|
ObjectsToPage(Index);
|
|
|
|
sx:=(DrawRect.Right-DrawRect.Left)/PrnInfo.PgW;
|
|
sy:=(DrawRect.Bottom-DrawRect.Top)/PrnInfo.PgH;
|
|
h:= Canvas.Handle;
|
|
|
|
for i := 0 to Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Page.Objects[i]);
|
|
v := True;
|
|
|
|
if not IsPrinting then
|
|
begin
|
|
with t, DrawRect do
|
|
begin
|
|
v := RectVisible(h, Rect(Round(x * sx) + Left - 10,
|
|
Round(y * sy) + Top - 10,
|
|
Round((x + dx) * sx) + Left + 10,
|
|
Round((y + dy) * sy) + Top + 10));
|
|
end;
|
|
end;
|
|
|
|
if v then
|
|
begin
|
|
t.ScaleX := sx;
|
|
t.ScaleY := sy;
|
|
t.OffsX := DrawRect.Left;
|
|
t.OffsY := DrawRect.Top;
|
|
t.IsPrinting := IsPrinting;
|
|
t.Draw(Canvas);
|
|
end;
|
|
end
|
|
end
|
|
{ else
|
|
begin
|
|
Page.Free;
|
|
Page := nil;
|
|
end;}
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.ExportData(Index: Integer);
|
|
var
|
|
p: PfrPageInfo;
|
|
b: Byte;
|
|
t: TfrView;
|
|
s: String;
|
|
begin
|
|
p := FPages[Index];
|
|
with p^ do
|
|
begin
|
|
Stream.Position := 0;
|
|
Stream.Read(frVersion, 1);
|
|
while Stream.Position < Stream.Size do
|
|
begin
|
|
b := 0;
|
|
Stream.Read(b, 1);
|
|
if b = gtAddIn then
|
|
s := ReadString(Stream) else
|
|
s := '';
|
|
t := frCreateObject(b, s, P^.Page);
|
|
t.StreamMode := smPrinting;
|
|
t.LoadFromStream(Stream);
|
|
t.ExportData;
|
|
t.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.ObjectsToPage(Index: Integer);
|
|
var
|
|
p: PfrPageInfo;
|
|
b: Byte;
|
|
t: TfrView;
|
|
s: String;
|
|
begin
|
|
p := FPages[Index];
|
|
with p^ do
|
|
begin
|
|
if Page <> nil then
|
|
Page.Free;
|
|
Page := TfrPageReport.Create(pgSize, pgWidth, pgHeight, pgOr);
|
|
Stream.Position := 0;
|
|
Stream.Read(frVersion, 1);
|
|
while Stream.Position < Stream.Size do
|
|
begin
|
|
b := 0;
|
|
Stream.Read(b, 1);
|
|
if b = gtAddIn then
|
|
s := ReadString(Stream)
|
|
else
|
|
s := '';
|
|
t := frCreateObject(b, s, P^.Page);
|
|
t.StreamMode := smPrinting;
|
|
t.LoadFromStream(Stream);
|
|
t.StreamMode := smDesigning;
|
|
Page.Objects.Add(t);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.PageToObjects(Index: Integer);
|
|
var
|
|
i: Integer;
|
|
p: PfrPageInfo;
|
|
t: TfrView;
|
|
begin
|
|
p := FPages[Index];
|
|
with p^ do
|
|
begin
|
|
Stream.Clear;
|
|
frVersion := frCurrentVersion;
|
|
Stream.Write(frVersion, 1);
|
|
for i := 0 to Page.Objects.Count - 1 do
|
|
begin
|
|
t :=TfrView(Page.Objects[i]);
|
|
t.StreamMode := smPrinting;
|
|
Stream.Write(t.Typ, 1);
|
|
if t.Typ = gtAddIn then
|
|
frWriteString(Stream, t.ClassName);
|
|
t.Memo1.Assign(t.Memo);
|
|
t.SaveToStream(Stream);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.Insert(Index: Integer; APage: TfrPage);
|
|
var
|
|
p: PfrPageInfo;
|
|
begin
|
|
GetMem(p, SizeOf(TfrPageInfo));
|
|
FillChar(p^, SizeOf(TfrPageInfo), 0);
|
|
if Index >= FPages.Count then
|
|
FPages.Add(p)
|
|
else
|
|
FPages.Insert(Index, p);
|
|
|
|
with p^ do
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
frVersion := frCurrentVersion;
|
|
Stream.Write(frVersion, 1);
|
|
pgSize := APage.pgSize;
|
|
pgWidth := APage.Width;
|
|
pgHeight := APage.Height;
|
|
pgOr := APage.Orientation;
|
|
pgMargins := APage.UseMargins;
|
|
PrnInfo := APage.PrnInfo;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.Add(APage: TfrPage);
|
|
begin
|
|
Insert(FPages.Count, APage);
|
|
if CurReport <> nil then
|
|
CurReport.DoBeginPage(PageNo);
|
|
if (MasterReport <> CurReport) and (MasterReport <> nil) then
|
|
MasterReport.DoBeginPage(PageNo);
|
|
end;
|
|
|
|
procedure TfrEMFPages.Delete(Index: Integer);
|
|
begin
|
|
if Pages[Index]^.Page <> nil then Pages[Index]^.Page.Free;
|
|
if Pages[Index]^.Stream <> nil then Pages[Index]^.Stream.Free;
|
|
FreeMem(Pages[Index], SizeOf(TfrPageInfo));
|
|
FPages.Delete(Index);
|
|
end;
|
|
|
|
function TfrEMFPages.DoMouseClick(Index: Integer; pt: TPoint; var AInfo: String
|
|
): Boolean;
|
|
var
|
|
PgInf: PfrPageInfo;
|
|
V: TfrView;
|
|
i: Integer;
|
|
R1:TRect;
|
|
begin
|
|
Result := False;
|
|
PgInf := FPages[Index];
|
|
if not Assigned(PgInf) then exit;
|
|
|
|
AInfo := '';
|
|
if not Assigned(PgInf^.Page) then
|
|
ObjectsToPage(Index);
|
|
|
|
for i := 0 to PgInf^.Page.Objects.Count - 1 do
|
|
begin
|
|
V := TfrView(PgInf^.Page.Objects[i]);
|
|
R1:=Rect(Round(V.X), Round(V.Y), Round((V.X + V.DX)), Round((V.Y + V.DY)));
|
|
if PtInRect(R1, pt) then
|
|
begin
|
|
if Assigned(Parent.OnObjectClick) then
|
|
begin
|
|
Parent.OnObjectClick(V);
|
|
Result := True;
|
|
AInfo:=V.FURLInfo;
|
|
end;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrEMFPages.DoMouseMove(Index: Integer; pt: TPoint;
|
|
var Cursor: TCursor; var AInfo: String): Boolean;
|
|
var
|
|
PgInf: PfrPageInfo;
|
|
V: TfrView;
|
|
i: Integer;
|
|
R1:TRect;
|
|
begin
|
|
Result := False;
|
|
PgInf := FPages[Index];
|
|
if not Assigned(PgInf) then exit;
|
|
|
|
AInfo := '';
|
|
if not Assigned(PgInf^.Page) then
|
|
ObjectsToPage(Index);
|
|
|
|
for i := 0 to PgInf^.Page.Objects.Count - 1 do
|
|
begin
|
|
V := TfrView(PgInf^.Page.Objects[i]);
|
|
R1:=Rect(Round(V.X), Round(V.Y), Round((V.X + V.DX)), Round((V.Y + V.DY)));
|
|
if PtInRect(R1, pt) then
|
|
begin
|
|
if Assigned(Parent.OnMouseOverObject) then
|
|
begin
|
|
Parent.OnMouseOverObject(V, Cursor);
|
|
Result := True;
|
|
end;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrEMFPages.LoadFromStream(AStream: TStream);
|
|
var
|
|
i, o, c: Integer;
|
|
b, compr: Byte;
|
|
p: PfrPageInfo;
|
|
procedure ReadVersion22;
|
|
var
|
|
Pict: TfrPictureView;
|
|
begin
|
|
frReadMemo22(AStream, SMemo);
|
|
if SMemo.Count > 0 then
|
|
Parent.SetPrinterTo(SMemo[0]);
|
|
AStream.Read(c, 4);
|
|
i := 0;
|
|
repeat
|
|
AStream.Read(o, 4);
|
|
GetMem(p, SizeOf(TfrPageInfo));
|
|
FillChar(p^, SizeOf(TfrPageInfo), 0);
|
|
FPages.Add(p);
|
|
with p^ do
|
|
begin
|
|
AStream.Read(pgSize, 2);
|
|
AStream.Read(pgWidth, 4);
|
|
AStream.Read(pgHeight, 4);
|
|
AStream.Read(b, 1);
|
|
pgOr := TPrinterOrientation(b);
|
|
AStream.Read(b, 1);
|
|
pgMargins := Boolean(b);
|
|
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
|
|
Pict := TfrPictureView.Create(P^.Page);
|
|
Pict.SetBounds(0, 0, PrnInfo.PgW, PrnInfo.PgH);
|
|
Pict.Picture.Graphic.LoadFromStream(AStream);
|
|
|
|
Stream := TMemoryStream.Create;
|
|
b := frCurrentVersion;
|
|
Stream.Write(b, 1);
|
|
Pict.StreamMode := smPrinting;
|
|
Stream.Write(Pict.Typ, 1);
|
|
Pict.SaveToStream(Stream);
|
|
Pict.Free;
|
|
end;
|
|
AStream.Seek(o, soFromBeginning);
|
|
Inc(i);
|
|
until i >= c;
|
|
end;
|
|
|
|
begin
|
|
Clear;
|
|
compr := 0;
|
|
AStream.Read(compr, 1);
|
|
if not (compr in [0, 1, 255]) then
|
|
begin
|
|
AStream.Seek(0, soFromBeginning);
|
|
ReadVersion22;
|
|
Exit;
|
|
end;
|
|
AddPagesFromStream(AStream, false);
|
|
end;
|
|
|
|
procedure TfrEMFPages.AddPagesFromStream(AStream: TStream;
|
|
AReadHeader: boolean=true);
|
|
var
|
|
i, o, c: Integer;
|
|
b, compr: Byte;
|
|
p: PfrPageInfo;
|
|
s: TMemoryStream;
|
|
|
|
begin
|
|
Compr := 0;
|
|
if AReadHeader then begin
|
|
AStream.Read(compr, 1);
|
|
if not (compr in [0, 1, 255]) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
end;
|
|
Parent.SetPrinterTo(frReadString(AStream));
|
|
c := 0;
|
|
AStream.Read(c, 4);
|
|
i := 0;
|
|
repeat
|
|
o := 0;
|
|
AStream.Read(o, 4);
|
|
GetMem(p, SizeOf(TfrPageInfo));
|
|
FillChar(p^, SizeOf(TfrPageInfo), #0);
|
|
FPages.Add(p);
|
|
with p^ do
|
|
begin
|
|
AStream.Read(pgSize, 2);
|
|
AStream.Read(pgWidth, 4);
|
|
AStream.Read(pgHeight, 4);
|
|
b := 0;
|
|
AStream.Read(b, 1);
|
|
pgOr := TPrinterOrientation(b);
|
|
AStream.Read(b, 1);
|
|
pgMargins := Boolean(b);
|
|
if compr <> 0 then
|
|
begin
|
|
s := TMemoryStream.Create;
|
|
s.CopyFrom(AStream, o - AStream.Position);
|
|
Stream := TMemoryStream.Create;
|
|
frCompressor.DeCompress(s, Stream);
|
|
s.Free;
|
|
end
|
|
else
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
Stream.CopyFrom(AStream, o - AStream.Position);
|
|
end;
|
|
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
end;
|
|
AStream.Seek(o, soFromBeginning);
|
|
Inc(i);
|
|
until i >= c;
|
|
end;
|
|
|
|
procedure TfrEMFPages.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
// todo
|
|
end;
|
|
|
|
procedure TfrEMFPages.SaveToStream(AStream: TStream);
|
|
var
|
|
i, o, n: Integer;
|
|
b: Byte;
|
|
s: TMemoryStream;
|
|
begin
|
|
b := Byte(frCompressor.Enabled);
|
|
AStream.Write(b, 1);
|
|
frWriteString(AStream, Prn.Printers[Prn.PrinterIndex]);
|
|
n := Count;
|
|
AStream.Write(n, 4);
|
|
i := 0;
|
|
repeat
|
|
o := AStream.Position;
|
|
AStream.Write(o, 4); // dummy write
|
|
with Pages[i]^ do
|
|
begin
|
|
AStream.Write(pgSize, 2);
|
|
AStream.Write(pgWidth, 4);
|
|
AStream.Write(pgHeight, 4);
|
|
b := Byte(pgOr);
|
|
AStream.Write(b, 1);
|
|
b := Byte(pgMargins);
|
|
AStream.Write(b, 1);
|
|
Stream.Position := 0;
|
|
if frCompressor.Enabled then
|
|
begin
|
|
s := TMemoryStream.Create;
|
|
frCompressor.Compress(Stream, s);
|
|
AStream.CopyFrom(s, s.Size);
|
|
s.Free;
|
|
end
|
|
else
|
|
AStream.CopyFrom(Stream, Stream.Size);
|
|
end;
|
|
n := AStream.Position;
|
|
AStream.Seek(o, soFromBeginning);
|
|
AStream.Write(n, 4);
|
|
AStream.Seek(0, soFromEnd);
|
|
Inc(i);
|
|
until i >= Count;
|
|
end;
|
|
|
|
procedure TfrEMFPages.SavePageToStream(PageNo:Integer; AStream: TStream);
|
|
var
|
|
o, n: Integer;
|
|
b: Byte;
|
|
s: TMemoryStream;
|
|
begin
|
|
if (PageNo >= 0) and (PageNo < Count) then // fool-proof :)
|
|
begin
|
|
b := Byte(frCompressor.Enabled);
|
|
AStream.Write(b, 1);
|
|
frWriteString(AStream, Prn.Printers[Prn.PrinterIndex]);
|
|
n := 1;
|
|
AStream.Write(n, 4);
|
|
o := AStream.Position;
|
|
AStream.Write(o, 4); // dummy write
|
|
with Pages[PageNo]^ do
|
|
begin
|
|
AStream.Write(pgSize, 2);
|
|
AStream.Write(pgWidth, 4);
|
|
AStream.Write(pgHeight, 4);
|
|
b := Byte(pgOr);
|
|
AStream.Write(b, 1);
|
|
b := Byte(pgMargins);
|
|
AStream.Write(b, 1);
|
|
Stream.Position := 0;
|
|
if frCompressor.Enabled then
|
|
begin
|
|
s := TMemoryStream.Create;
|
|
frCompressor.Compress(Stream, s);
|
|
AStream.CopyFrom(s, s.Size);
|
|
s.Free;
|
|
end
|
|
else
|
|
AStream.CopyFrom(Stream, Stream.Size);
|
|
end;
|
|
n := AStream.Position;
|
|
AStream.Seek(o, soFromBeginning);
|
|
AStream.Write(n, 4);
|
|
AStream.Seek(0, soFromEnd);
|
|
end
|
|
else
|
|
raise ERangeError.CreateFmt('Save page: PageNo %d out of range [0..%d]', [PageNo, Count-1]);
|
|
end;
|
|
|
|
procedure TfrEMFPages.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
// Todo
|
|
end;
|
|
|
|
{-----------------------------------------------------------------------}
|
|
constructor TfrValues.Create;
|
|
begin
|
|
inherited Create;
|
|
FItems := TStringList.Create;
|
|
end;
|
|
|
|
destructor TfrValues.Destroy;
|
|
begin
|
|
Clear;
|
|
FItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrValues.WriteBinaryData(Stream: TStream);
|
|
var
|
|
i, n: Integer;
|
|
|
|
procedure WriteStr(s: String);
|
|
var
|
|
n: Byte;
|
|
begin
|
|
n := Length(s);
|
|
Stream.Write(n, 1);
|
|
Stream.Write(s[1], n);
|
|
end;
|
|
|
|
begin
|
|
with Stream do
|
|
begin
|
|
n := FItems.Count;
|
|
WriteBuffer(n, SizeOf(n));
|
|
for i := 0 to n - 1 do
|
|
with Objects[i] do
|
|
begin
|
|
WriteBuffer(Typ, SizeOf(Typ));
|
|
WriteBuffer(OtherKind, SizeOf(OtherKind));
|
|
WriteStr(DataSet);
|
|
WriteStr(Field);
|
|
WriteStr(FItems[i]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrValues.WriteBinaryDataToXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
i: integer;
|
|
aSubPath: String;
|
|
begin
|
|
XML.SetValue(Path+'Count/Value'{%H-}, FItems.Count);
|
|
for i:= 0 to FItems.Count-1 do
|
|
with Objects[i] do
|
|
begin
|
|
aSubPath := Path+'Objects'+InttoStr(i+1)+'/';
|
|
XML.SetValue(aSubPath+'Typ/Value'{%H-}, Ord(Typ));
|
|
XML.SetValue(aSubPath+'OtherKind/Value'{%H-}, OtherKind);
|
|
XML.SetValue(aSubPath+'Dataset/Value', DataSet);
|
|
XML.SetValue(aSubPath+'Field/Value', Field);
|
|
XML.SetValue(aSubPath+'Item/Value', FItems[i]);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrValues.ReadBinaryData(Stream: TStream);
|
|
var
|
|
i, j, n: Integer;
|
|
li: longint;
|
|
b: byte;
|
|
val: TfrValue;
|
|
|
|
function ReadStr: String;
|
|
var
|
|
n: Byte;
|
|
begin
|
|
n := 0;
|
|
Stream.Read(n, 1);
|
|
SetLength(Result, n);
|
|
Stream.Read(Result[1], n);
|
|
end;
|
|
|
|
begin
|
|
Clear;
|
|
FItems.Sorted := False;
|
|
with Stream do
|
|
begin
|
|
n := 0;
|
|
ReadBuffer(n, SizeOf(n));
|
|
for i := 0 to n - 1 do
|
|
begin
|
|
j := AddValue;
|
|
val := Objects[j];
|
|
with val do
|
|
begin
|
|
if frVersion=23 then
|
|
begin
|
|
Read(b, 1);
|
|
Read(li, 4);
|
|
typ := TfrValueType(b);
|
|
OtherKind := li;
|
|
end else
|
|
if frVersion>23 then
|
|
begin
|
|
ReadBuffer(Typ, SizeOf(Typ));
|
|
ReadBuffer(OtherKind, SizeOf(OtherKind));
|
|
end;
|
|
DataSet := ReadStr;
|
|
Field := ReadStr;
|
|
FItems[j] := ReadStr;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrValues.ReadBinaryDataFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
i,j,n: Integer;
|
|
aSubPath: String;
|
|
begin
|
|
clear;
|
|
FItems.Sorted := False;
|
|
n := XML.GetValue(Path+'Count/Value'{%H-}, 0);
|
|
for i:= 0 to n - 1 do
|
|
begin
|
|
j := AddValue;
|
|
with Objects[j] do
|
|
begin
|
|
aSubPath := Path+'Objects'+InttoStr(i+1)+'/';
|
|
Typ := TfrValueType(XML.GetValue(aSubPath+'Typ/Value'{%H-}, 0)); // TODO check default value
|
|
OtherKind := XML.GetValue( aSubPath+'OtherKind/Value'{%H-}, 0); // TODO check default value
|
|
DataSet := XML.GetValue(aSubPath+'Dataset/Value', ''); // TODO check default value
|
|
Field := XML.GetValue(aSubPath+'Field/Value', ''); // TODO check default value
|
|
FItems[j] := XML.GetValue(aSubPath+'Item/Value', ''); // TODO check default value
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrValues.GetValue(Index: Integer): TfrValue;
|
|
begin
|
|
Result := TfrValue(FItems.Objects[Index]);
|
|
end;
|
|
|
|
function TfrValues.AddValue: Integer;
|
|
begin
|
|
Result := FItems.AddObject('', TfrValue.Create);
|
|
end;
|
|
|
|
procedure TfrValues.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FItems.Count - 1 do
|
|
TfrValue(FItems.Objects[i]).Free;
|
|
FItems.Clear;
|
|
end;
|
|
|
|
function TfrValues.FindVariable(const s: String): TfrValue;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
i := FItems.IndexOf(s);
|
|
if i <> -1 then
|
|
Result := Objects[i];
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrReport.Create(AOwner: TComponent);
|
|
const
|
|
Clr: Array[0..1] of TColor = (clWhite, clSilver);
|
|
|
|
var
|
|
j: Integer;
|
|
i: Integer;
|
|
begin
|
|
inherited Create(AOwner);
|
|
if not FRInitialized then
|
|
begin
|
|
FRInitialized := True;
|
|
SBmp := TBitmap.Create;
|
|
TempBmp := TBitmap.Create;
|
|
SBmp.Width := 8;
|
|
SBmp.Height := 8;
|
|
TempBmp.Width := 8;
|
|
TempBmp.Height := 8;
|
|
for j := 0 to 7 do
|
|
begin
|
|
for i := 0 to 7 do
|
|
SBmp.Canvas.Pixels[i, j] := Clr[(j + i) mod 2];
|
|
end;
|
|
frProgressForm := TfrProgressForm.Create(nil);
|
|
end;
|
|
|
|
FPages := TfrPages.Create(Self);
|
|
FEMFPages := TfrEMFPages.Create(Self);
|
|
FVars := TStringList.Create;
|
|
FVal := TfrValues.Create;
|
|
FShowProgress := True;
|
|
FModalPreview := True;
|
|
FModifyPrepared := True;
|
|
FPreviewButtons := [pbZoom, pbLoad, pbSave, pbPrint, pbFind, pbHelp, pbExit];
|
|
FInitialZoom := pzDefault;
|
|
FileName := sUntitled;
|
|
FComments:=TStringList.Create;
|
|
FScript:=TfrScriptStrings.Create;
|
|
UpdateObjectStringResources;
|
|
end;
|
|
|
|
destructor TfrReport.Destroy;
|
|
begin
|
|
if CurReport=Self then
|
|
CurReport:=nil;
|
|
FVal.Free;
|
|
FVars.Free;
|
|
FEMFPages.Free;
|
|
FEMFPages := nil;
|
|
FPages.Free;
|
|
FComments.Free;
|
|
FreeAndNil(FScript);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrReport.Clear;
|
|
begin
|
|
Pages.Clear;
|
|
if frDataManager <> nil then
|
|
frDataManager.Clear;
|
|
DoublePass := False;
|
|
ClearAttribs;
|
|
DocMode := dmDesigning;
|
|
end;
|
|
|
|
procedure TfrReport.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited DefineProperties(Filer);
|
|
Filer.DefineProperty('StoreInDFM', @ReadStoreInDFM, nil, false);
|
|
Filer.DefineProperty('ReportXML', @ReadReportXML, @WriteReportXML, fStoreInForm);
|
|
Filer.DefineBinaryProperty('ReportForm', @ReadBinaryData, nil, false);
|
|
end;
|
|
|
|
procedure TfrReport.ReadBinaryData(Stream: TStream);
|
|
var
|
|
n: Integer;
|
|
begin
|
|
n := 0;
|
|
Stream.Read(n, 4); // version
|
|
if FStoreInDFM then
|
|
begin
|
|
Stream.Read(n, 4);
|
|
FDFMStream := TMemoryStream.Create;
|
|
FDFMStream.CopyFrom(Stream, n);
|
|
FDFMStream.Position := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (Operation = opRemove) and (AComponent = Dataset) then
|
|
Dataset := nil;
|
|
if (Operation = opRemove) and (AComponent = Preview) then
|
|
Preview := nil;
|
|
end;
|
|
|
|
// report building events
|
|
procedure TfrReport.InternalOnProgress(Percent: Integer);
|
|
begin
|
|
if Assigned(FOnProgress) then
|
|
FOnProgress(Percent)
|
|
else
|
|
if fShowProgress then
|
|
begin
|
|
with frProgressForm do
|
|
begin
|
|
if (MasterReport.DoublePass and MasterReport.FinalPass) or
|
|
(FCurrentFilter <> nil) then
|
|
Label1.Caption:=Format('%s %d %s %d',[FirstCaption,Percent,sFrom,SavedAllPages])
|
|
else
|
|
Label1.Caption:=Format('%s %d',[FirstCaption,Percent]);
|
|
|
|
Application.ProcessMessages;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function CopyVarString(V: Variant): String;
|
|
begin
|
|
Result := pchar(TVarData(V).VString)
|
|
end;
|
|
|
|
procedure TfrReport.InternalOnGetValue(ParName: String; var ParValue: String);
|
|
var
|
|
i, j, AFormat: Integer;
|
|
AFormatStr: String;
|
|
begin
|
|
SubValue := '';
|
|
if Assigned(CurView) then
|
|
begin
|
|
AFormat := CurView.Format;
|
|
AFormatStr := CurView.FormatStr;
|
|
end
|
|
else
|
|
begin
|
|
AFormat := 0;
|
|
AFormatStr := '';
|
|
end;
|
|
i := Pos(' #', ParName);
|
|
if i <> 0 then
|
|
begin
|
|
AFormatStr := Copy(ParName, i + 2, Length(ParName) - i - 1);
|
|
ParName := Copy(ParName, 1, i - 1);
|
|
|
|
if AFormatStr[1] in ['0'..'9', 'N', 'n'] then
|
|
begin
|
|
if AFormatStr[1] in ['0'..'9'] then
|
|
AFormatStr := 'N' + AFormatStr;
|
|
AFormat := $01000000;
|
|
if AFormatStr[2] in ['0'..'9'] then
|
|
AFormat := AFormat + $00010000;
|
|
i := Length(AFormatStr);
|
|
while i > 1 do
|
|
begin
|
|
if AFormatStr[i] in ['.', ',', '-'] then
|
|
begin
|
|
AFormat := AFormat + Ord(AFormatStr[i]);
|
|
AFormatStr[i] := '.';
|
|
if AFormatStr[2] in ['0'..'9'] then
|
|
begin
|
|
Inc(i);
|
|
j := i;
|
|
while (i <= Length(AFormatStr)) and (AFormatStr[i] in ['0'..'9']) do
|
|
Inc(i);
|
|
AFormat := AFormat + 256 * StrToInt(Copy(AFormatStr, j, i - j));
|
|
end;
|
|
break;
|
|
end;
|
|
Dec(i);
|
|
end;
|
|
if not (AFormatStr[2] in ['0'..'9']) then
|
|
begin
|
|
AFormatStr := Copy(AFormatStr, 2, 255);
|
|
AFormat := AFormat + $00040000;
|
|
end;
|
|
end
|
|
else if AFormatStr[1] in ['D', 'T', 'd', 't'] then
|
|
begin
|
|
AFormat := $02040000;
|
|
AFormatStr := Copy(AFormatStr, 2, 255);
|
|
end
|
|
else if AFormatStr[1] in ['B', 'b'] then
|
|
begin
|
|
AFormat := $04040000;
|
|
AFormatStr := Copy(AFormatStr, 2, 255);
|
|
end;
|
|
end;
|
|
|
|
CurVariable := ParName;
|
|
CurValue := 0;
|
|
GetVariableValue(ParName, CurValue);
|
|
ParValue := FormatValue(CurValue, AFormat, AFormatStr);
|
|
{
|
|
if TVarData(CurValue).VType=varString then
|
|
ValStr := CopyVarString(CurValue)
|
|
else
|
|
ValStr := CurValue;
|
|
ParValue := FormatValueStr(ValStr, Format, FormatStr);
|
|
}
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrReport.InternalOnGetValue(%s) Value=%s',[ParName,ParValue]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrReport.InternalOnEnterRect(Memo: TStringList; View: TfrView);
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TfrReport.InternalOnEnterRect View=%s',[ViewInfo(View)]);
|
|
{$ENDIF}
|
|
with View do
|
|
if (FDataSet <> nil) and frIsBlob(TfrTField(FDataSet.FindField(FField))) then
|
|
GetBlob(TfrTField(FDataSet.FindField(FField)));
|
|
DoEnterRect(Memo, View);
|
|
end;
|
|
|
|
procedure TfrReport.InternalOnExportData(View: TfrView);
|
|
begin
|
|
FCurrentFilter.OnData(View.x, View.y, View);
|
|
end;
|
|
|
|
procedure TfrReport.InternalOnExportText(x, y: Integer; const text: String;
|
|
View: TfrView);
|
|
begin
|
|
FCurrentFilter.OnText(x, y, text, View);
|
|
end;
|
|
|
|
procedure TfrReport.InternalOnExported(View: TfrView);
|
|
begin
|
|
FCurrentFilter.OnExported(View.x, View.y, View);
|
|
end;
|
|
|
|
procedure TfrReport.ReadStoreInDFM(Reader: TReader);
|
|
begin
|
|
FStoreInDFM := Reader.ReadBoolean;
|
|
end;
|
|
|
|
procedure TfrReport.ReadReportXML(Reader: TReader);
|
|
begin
|
|
FXMLReport := Reader.ReadString;
|
|
end;
|
|
|
|
procedure TfrReport.WriteReportXML(Writer: TWriter);
|
|
var
|
|
st: TStringStream;
|
|
begin
|
|
st := TStringStream.Create('');
|
|
SaveToXMLStream(st);
|
|
Writer.WriteString(st.DataString);
|
|
st.free;
|
|
end;
|
|
|
|
function TfrReport.FormatValue(V: Variant;
|
|
AFormat: Integer;
|
|
const AFormatStr: String): String;
|
|
var
|
|
f1, f2: Integer;
|
|
c: Char;
|
|
s: String;
|
|
begin
|
|
if (TVarData(v).VType = varEmpty) {VarIsEmpty(v)} or VarIsNull(v) then
|
|
begin
|
|
Result := ' ';
|
|
Exit;
|
|
end;
|
|
|
|
c := DecimalSeparator;
|
|
f1 := (AFormat div $01000000) and $0F;
|
|
f2 := (AFormat div $00010000) and $FF;
|
|
try
|
|
case f1 of
|
|
fmtText:
|
|
begin
|
|
if VarIsType(v, varDate) and (trunc(Extended(v))=0) then
|
|
begin
|
|
Result := TimeToStr(v);
|
|
if Result='' then
|
|
Result := FormatDateTime('hh:nn:ss', v);
|
|
end
|
|
else
|
|
Result := v;
|
|
end;
|
|
fmtNumber:
|
|
begin
|
|
if not VarIsNumeric(v) then
|
|
result := v
|
|
else begin
|
|
DecimalSeparator := Chr(AFormat and $FF);
|
|
case f2 of
|
|
0: Result := FormatFloat('###.##', v);
|
|
1: Result := FloatToStrF(Extended(v), ffFixed, 15, (AFormat div $0100) and $FF);
|
|
2: Result := FormatFloat('#,###.##', v);
|
|
3: Result := FloatToStrF(Extended(v), ffNumber, 15, (AFormat div $0100) and $FF);
|
|
4: Result := FormatFloat(AFormatStr, v);
|
|
end;
|
|
end;
|
|
end;
|
|
fmtDate:
|
|
if v=0 then
|
|
Result := '' // date is null
|
|
else
|
|
if f2 = 4 then
|
|
Result := SysToUTF8(FormatDateTime(AFormatStr, v))
|
|
else
|
|
Result := FormatDateTime(frDateFormats[f2], v);
|
|
fmtTime:
|
|
if f2 = 4 then
|
|
Result := FormatDateTime(AFormatStr, v)
|
|
else
|
|
Result := FormatDateTime(frTimeFormats[f2], v);
|
|
fmtBoolean :
|
|
begin
|
|
if f2 = 4 then
|
|
s := AFormatStr
|
|
else
|
|
s := BoolStr[f2];
|
|
if Integer(v) = 0 then
|
|
Result := Copy(s, 1, Pos(';', s) - 1)
|
|
else
|
|
Result := Copy(s, Pos(';', s) + 1, 255);
|
|
end;
|
|
end;
|
|
except
|
|
on e:exception do
|
|
Result := v;
|
|
end;
|
|
DecimalSeparator := c;
|
|
end;
|
|
|
|
{
|
|
function TfrReport.GetLRTitle: String;
|
|
begin
|
|
if csDesigning in ComponentState then
|
|
Result:=fDefaultTitle
|
|
else
|
|
begin
|
|
if fTitle<>'' then
|
|
Result:=fTitle
|
|
else
|
|
Result:=fDefaultTitle;
|
|
end;
|
|
end;
|
|
}
|
|
procedure TfrReport.GetVariableValue(const s: String; var aValue: Variant);
|
|
var
|
|
Value: TfrValue;
|
|
D: TfrTDataSet;
|
|
F: TfrTField;
|
|
s1: String;
|
|
|
|
function MasterBand: TfrBand;
|
|
begin
|
|
Result := CurBand;
|
|
if Result.DataSet = nil then
|
|
while Result.Prev <> nil do
|
|
Result := Result.Prev;
|
|
end;
|
|
|
|
begin
|
|
TVarData(aValue).VType := varEmpty;
|
|
|
|
DoGetValue(s,aValue);
|
|
|
|
if TVarData(aValue).VType = varEmpty then
|
|
begin
|
|
Value := Values.FindVariable(s);
|
|
if Assigned(Value) then
|
|
begin
|
|
with Value do
|
|
begin
|
|
case Typ of
|
|
vtNotAssigned: aValue := '';
|
|
vtDBField : begin
|
|
F := TfrTField(DSet.FindField(Field));
|
|
if not F.DataSet.Active then
|
|
F.DataSet.Open;
|
|
if Assigned(F.OnGetText) then
|
|
aValue:=F.DisplayText
|
|
else
|
|
aValue:=lrGetFieldValue(F);//F.AsVariant;
|
|
end;
|
|
vtFRVar : aValue := frParser.Calc(Field);
|
|
vtOther : begin
|
|
if OtherKind = 1 then
|
|
aValue:=frParser.Calc(Field)
|
|
else
|
|
aValue:=frParser.Calc(frSpecFuncs[OtherKind]);
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TVarData(aValue).VType := varEmpty;
|
|
GetIntrpValue(s, aValue);
|
|
if TVarData(aValue).VType = varEmpty then
|
|
begin
|
|
D := GetDefaultDataSet;
|
|
frGetDataSetAndField(s, D, F);
|
|
if F <> nil then
|
|
begin
|
|
if not F.DataSet.Active then
|
|
F.DataSet.Open;
|
|
if Assigned(F.OnGetText) then
|
|
aValue:=F.DisplayText
|
|
else
|
|
aValue:=lrGetFieldValue(F); ///F.AsVariant
|
|
end
|
|
else
|
|
if (D<>nil) and (roIgnoreFieldNotFound in FReportOptions) and
|
|
lrValidFieldReference(s) then
|
|
aValue := Null
|
|
else
|
|
begin
|
|
s1 := UpperCase(s);
|
|
if s1 = 'VALUE' then
|
|
aValue:= CurValue
|
|
else if s1 = frSpecFuncs[0] then
|
|
aValue:= PageNo + 1
|
|
else if s1 = frSpecFuncs[2] then
|
|
aValue := CurDate
|
|
else if s1 = frSpecFuncs[3] then
|
|
aValue:= CurTime
|
|
else if s1 = frSpecFuncs[4] then
|
|
aValue:= MasterBand.Positions[psLocal]
|
|
else if s1 = frSpecFuncs[5] then
|
|
aValue:= MasterBand.Positions[psGlobal]
|
|
else if s1 = frSpecFuncs[6] then
|
|
aValue:= CurPage.ColPos
|
|
else if s1 = frSpecFuncs[7] then
|
|
aValue:= CurPage.CurPos
|
|
else if s1 = frSpecFuncs[8] then
|
|
aValue:= SavedAllPages
|
|
else
|
|
begin
|
|
if frVariables.IndexOf(s) <> -1 then
|
|
begin
|
|
aValue:= frVariables[s];
|
|
Exit;
|
|
end else
|
|
if s1 = 'REPORTTITLE' then
|
|
begin
|
|
aValue := Title;
|
|
Exit;
|
|
end;
|
|
if s <> SubValue then
|
|
begin
|
|
SubValue := s;
|
|
aValue:= frParser.Calc(s);
|
|
SubValue := '';
|
|
end
|
|
else
|
|
begin
|
|
if roIgnoreSymbolNotFound in FReportOptions then
|
|
aValue := Null
|
|
else
|
|
raise(EParserError.Create('Undefined symbol: ' + SubValue));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if Assigned(CurView) and (CurView.Flags and flHideZeros <> 0) then
|
|
begin
|
|
if TVarData(aValue).VType in [varSmallInt, varInteger, varCurrency, varDecimal, varShortInt, varByte, varWord, varLongWord,
|
|
varInt64, varQWord] then
|
|
begin
|
|
if aValue = 0 then
|
|
aValue:='';
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.OnGetParsFunction(const aName: String; p1, p2, p3: Variant;
|
|
var val: Variant);
|
|
|
|
function ProcessObjMethods(Method:string):boolean;
|
|
var
|
|
PgName, ObjName:string;
|
|
Obj:TfrObject;
|
|
i, j:integer;
|
|
begin
|
|
Result:=false;
|
|
Obj:=nil;
|
|
PgName:='';
|
|
ObjName:=Copy2SymbDel(Method, '.');
|
|
|
|
for i:=0 to CurReport.Pages.Count - 1 do
|
|
begin
|
|
if UpperCase(CurReport.Pages[i].Name) = ObjName then
|
|
begin
|
|
// PageName.ObjName.Method
|
|
Obj:=CurReport.Pages[i];
|
|
|
|
if Method<>'' then
|
|
begin
|
|
ObjName:=Copy2SymbDel(Method, '.');
|
|
for j:=0 to CurReport.Pages[i].Objects.Count - 1 do
|
|
begin
|
|
if UpperCase(TfrObject(CurReport.Pages[i].Objects[j]).Name) = ObjName then
|
|
begin
|
|
Obj:=TfrObject(CurReport.Pages[i].Objects[j]);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Break;
|
|
end
|
|
else
|
|
begin
|
|
for j:=0 to CurReport.Pages[i].Objects.Count - 1 do
|
|
begin
|
|
if UpperCase(TfrObject(CurReport.Pages[i].Objects[j]).Name) = ObjName then
|
|
begin
|
|
Obj:=TfrObject(CurReport.Pages[i].Objects[j]);
|
|
break;
|
|
end;
|
|
end;
|
|
if Assigned(Obj) then
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if Assigned(Obj) then
|
|
Result:=Obj.ExecMetod(UpperCase(Method), p1, p2, p3, val);
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
begin
|
|
val := varempty;
|
|
{$ifdef DebugLR}
|
|
DebugLn('OnGetParsFunction aName=%s p1=%s p2=%s p3=%s',[aName,p1,p2,p3]);
|
|
{$endif}
|
|
for i := 0 to frFunctionsCount - 1 do
|
|
if frFunctions[i].FunctionLibrary.OnFunction(aName, p1, p2, p3, val) then
|
|
exit;
|
|
|
|
if (Pos('.', aName)>0) and ProcessObjMethods(aName) then
|
|
exit;
|
|
|
|
if not DoInterpFunction(aName, p1, p2, p3, val) then
|
|
begin
|
|
if Assigned(AggrBand) and AggrBand.Visible then
|
|
DoUserFunction(aName, p1, p2, p3, val);
|
|
end;
|
|
end;
|
|
|
|
function TfrReport.DoInterpFunction(const aName: String; p1, p2, p3: Variant;
|
|
var val: Variant): boolean;
|
|
var
|
|
Obj:TfrObject;
|
|
ObjProp:string;
|
|
ArrInd:Variant;
|
|
begin
|
|
Result:=true;
|
|
if aName = 'NEWPAGE' then
|
|
begin
|
|
CurBand.ForceNewPage := True;
|
|
Val := '0';
|
|
end
|
|
else
|
|
if aName = 'NEWCOLUMN' then
|
|
begin
|
|
CurBand.ForceNewColumn := True;
|
|
Val := '0';
|
|
end
|
|
else
|
|
if aName = 'STOPREPORT' then
|
|
CurReport.Terminated:=true
|
|
else
|
|
if aName = 'SHOWBAND' then
|
|
CurPage.ShowBandByName(p1)
|
|
else
|
|
if aName = 'INC' then
|
|
begin
|
|
frParser.OnGetValue(p1, ArrInd);
|
|
frInterpretator.SetValue(p1, ArrInd + 1);
|
|
end
|
|
else
|
|
if aName = 'DEC' then
|
|
begin
|
|
frParser.OnGetValue(p1, ArrInd);
|
|
frInterpretator.SetValue(p1, ArrInd - 1);
|
|
end
|
|
else
|
|
if aName = 'SETARRAY' then
|
|
begin
|
|
ObjProp:='';
|
|
Obj:=DoFindObjMetod(p1, ObjProp);
|
|
|
|
if Assigned(Obj) then
|
|
Obj.ExecMetod('SETINDEXPROPERTY', UpperCase(ObjProp), frParser.Calc(p2), frParser.Calc(p3), Val)
|
|
else
|
|
frVariables['frA_' + p1 + '_' + VarToStr(frParser.Calc(p2))] := frParser.Calc(p3);
|
|
end
|
|
else
|
|
if aName = 'GETARRAY' then
|
|
begin
|
|
ObjProp:='';
|
|
Obj:=DoFindObjMetod(p1, ObjProp);
|
|
|
|
if Assigned(Obj) then
|
|
Obj.ExecMetod('GETINDEXPROPERTY', UpperCase(ObjProp), frParser.Calc(p2), frParser.Calc(p3), Val)
|
|
else
|
|
Val:=frVariables['frA_' + p1 + '_' + VarToStr(frParser.Calc(p2))];
|
|
end
|
|
else
|
|
Result:=false;
|
|
end;
|
|
|
|
// load/save methods
|
|
procedure TfrReport.LoadFromStream(Stream: TStream);
|
|
begin
|
|
CurReport := Self;
|
|
Stream.Read(frVersion, 1);
|
|
if frVersion < 21 then
|
|
begin
|
|
frVersion := 21;
|
|
Stream.Position := 0;
|
|
end;
|
|
if frVersion <= frCurrentVersion then
|
|
try
|
|
{$IFDEF FREEREP2217READ}
|
|
if FRE_COMPATIBLE_READ and (frVersion >= 23) then
|
|
frVersion := 22;
|
|
{$ENDIF}
|
|
Pages.LoadFromStream(Stream);
|
|
except
|
|
on E:Exception do
|
|
begin
|
|
Pages.Clear;
|
|
Pages.Add;
|
|
MessageDlg(sFRFError+^M+E.Message,mtError,[mbOk],0)
|
|
end;
|
|
end
|
|
else
|
|
MessageDlg(sFRFError,mtError,[mbOk],0);
|
|
end;
|
|
|
|
procedure TfrReport.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
ATitle: string;
|
|
begin
|
|
CurReport := Self;
|
|
frVersion := XML.GetValue(Path+'Version/Value'{%H-}, 21);
|
|
fComments.Text := XML.GetValue(Path+'Comments/Value', '');
|
|
fKeyWords := XML.GetValue(Path+'KeyWords/Value', '');
|
|
fSubject := XML.GetValue(Path+'Subject/Value', '');
|
|
ATitle := XML.GetValue(Path+'Title/Value', '');
|
|
if ATitle<>'' then
|
|
fTitle := ATitle;
|
|
|
|
FReportCreateDate:=lrStrToDateTime(XML.GetValue(Path+'ReportCreateDate/Value', lrDateTimeToStr(Now)));
|
|
FReportLastChange:=lrStrToDateTime(XML.GetValue(Path+'ReportLastChange/Value', lrDateTimeToStr(Now)));
|
|
|
|
FReportVersionBuild:=XML.GetValue(Path+'ReportVersionBuild/Value', '');
|
|
FReportVersionMajor:=XML.GetValue(Path+'ReportVersionMajor/Value', '');
|
|
FReportVersionMinor:=XML.GetValue(Path+'ReportVersionMinor/Value', '');
|
|
FReportVersionRelease:=XML.GetValue(Path+'ReportVersionRelease/Value', '');
|
|
FReportAutor:=XML.GetValue(Path+'ReportAutor/Value', '');
|
|
FScript.Text:= XML.GetValue(Path+'Script/Value', '');
|
|
|
|
if frVersion < 21 then
|
|
frVersion := 21;
|
|
|
|
if frVersion <= frCurrentVersion then
|
|
try
|
|
{$IFDEF FREEREP2217READ}
|
|
if FRE_COMPATIBLE_READ and (frVersion >= 23) then
|
|
frVersion := 22;
|
|
{$ENDIF}
|
|
pages.LoadFromXML(XML, Path+'Pages/');
|
|
except
|
|
on E:Exception do
|
|
begin
|
|
Pages.Clear;
|
|
Pages.Add;
|
|
MessageDlg(sReportLoadingError+^M+E.Message,mtError,[mbOk],0)
|
|
end;
|
|
end
|
|
else
|
|
MessageDlg(sReportLoadingError,mtError,[mbOk],0);
|
|
end;
|
|
|
|
procedure TfrReport.SaveToStream(Stream: TStream);
|
|
begin
|
|
CurReport := Self;
|
|
frVersion := frCurrentVersion;
|
|
Stream.Write(frVersion, 1);
|
|
Pages.SaveToStream(Stream);
|
|
end;
|
|
|
|
procedure TfrReport.LoadFromFile(const FName: String);
|
|
var
|
|
Stream: TFileStream;
|
|
Ext : String;
|
|
begin
|
|
Ext:=ExtractFileExt(fName);
|
|
if SameText('.lrf',Ext) then
|
|
LoadFromXMLFile(fName)
|
|
else
|
|
begin
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
|
|
LoadFromStream(Stream);
|
|
Stream.Free;
|
|
FileName := FName;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.LoadFromXMLFile(const Fname: String);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.Filename := UTF8ToSys(FName);
|
|
try
|
|
LoadFromXML(XML, 'LazReport/');
|
|
FileName := FName;
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.LoadFromXMLStream(const Stream: TStream);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.LoadFromStream(Stream);
|
|
try
|
|
LoadFromXML(XML, 'LazReport/');
|
|
FileName := '-stream-';
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.SaveToFile(FName: String);
|
|
var
|
|
Stream: TFileStream;
|
|
Ext : string;
|
|
begin
|
|
Ext:=ExtractFileExt(fName);
|
|
if (Ext='') or (Ext='.') then
|
|
begin
|
|
Ext:='.lrf';
|
|
fName:=ChangeFileExt(fName,Ext);
|
|
end;
|
|
|
|
if SameText('.lrf',Ext) then
|
|
SaveToXMLFile(fName)
|
|
else
|
|
begin
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
|
|
SaveToStream(Stream);
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
CurReport := Self;
|
|
frVersion := frCurrentVersion;
|
|
XML.SetValue(Path+'Version/Value'{%H-}, frVersion);
|
|
|
|
XML.SetValue(Path+'Title/Value', fTitle);
|
|
XML.SetValue(Path+'Subject/Value', fSubject);
|
|
XML.SetValue(Path+'KeyWords/Value', fKeyWords);
|
|
XML.SetValue(Path+'Comments/Value', fComments.Text);
|
|
|
|
XML.SetValue(Path+'ReportCreateDate/Value', lrDateTimeToStr(FReportCreateDate));
|
|
XML.SetValue(Path+'ReportLastChange/Value', lrDateTimeToStr(FReportLastChange));
|
|
XML.SetValue(Path+'ReportVersionBuild/Value', FReportVersionBuild);
|
|
XML.SetValue(Path+'ReportVersionMajor/Value', FReportVersionMajor);
|
|
XML.SetValue(Path+'ReportVersionMinor/Value', FReportVersionMinor);
|
|
XML.SetValue(Path+'ReportVersionRelease/Value', FReportVersionRelease);
|
|
XML.SetValue(Path+'ReportAutor/Value', FReportAutor);
|
|
|
|
XML.SetValue(Path+'Script/Value', FScript.Text);
|
|
|
|
Pages.SaveToXML(XML, Path+'Pages/');
|
|
end;
|
|
|
|
procedure TfrReport.SaveToXMLFile(const FName: String);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.StartEmpty := True;
|
|
XML.Filename := UTF8ToSys(FName);
|
|
try
|
|
SaveToXML(XML, 'LazReport/');
|
|
XML.Flush;
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.SaveToXMLStream(const Stream: TStream);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.StartEmpty := True;
|
|
try
|
|
SaveToXML(XML, 'LazReport/');
|
|
XML.SaveToStream(Stream);
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.LoadFromDB(Table: TDataSet; DocN: Integer);
|
|
var
|
|
Stream: TMemoryStream;
|
|
begin
|
|
Table.First;
|
|
while not Table.Eof do
|
|
begin
|
|
if Table.Fields[0].AsInteger = DocN then
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
TfrTBlobField(Table.Fields[1]).SaveToStream(Stream);
|
|
Stream.Position := 0;
|
|
LoadFromStream(Stream);
|
|
Stream.Free;
|
|
Exit;
|
|
end;
|
|
Table.Next;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.SaveToDB(Table: TDataSet; DocN: Integer);
|
|
var
|
|
Stream: TMemoryStream;
|
|
Found: Boolean;
|
|
begin
|
|
Found := False;
|
|
Table.First;
|
|
while not Table.Eof do
|
|
begin
|
|
if Table.Fields[0].AsInteger = DocN then
|
|
begin
|
|
Found := True;
|
|
break;
|
|
end;
|
|
Table.Next;
|
|
end;
|
|
|
|
if Found then
|
|
Table.Edit else
|
|
Table.Append;
|
|
Table.Fields[0].AsInteger := DocN;
|
|
Stream := TMemoryStream.Create;
|
|
SaveToStream(Stream);
|
|
Stream.Position := 0;
|
|
TfrTBlobField(Table.Fields[1]).LoadFromStream(Stream);
|
|
Stream.Free;
|
|
Table.Post;
|
|
end;
|
|
|
|
procedure TfrReport.LoadPreparedReport(const FName: String);
|
|
var
|
|
Stream: TFileStream;
|
|
begin
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
|
|
EMFPages.LoadFromStream(Stream);
|
|
Stream.Free;
|
|
CanRebuild := False;
|
|
end;
|
|
|
|
procedure TfrReport.SavePreparedReport(const FName: String);
|
|
var
|
|
Stream: TFileStream;
|
|
begin
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
|
|
EMFPages.SaveToStream(Stream);
|
|
Stream.Free;
|
|
end;
|
|
|
|
procedure TfrReport.LoadTemplate(const fname: String; comm: TStrings;
|
|
Bmp: TBitmap; Load: Boolean);
|
|
var
|
|
Stream: TFileStream;
|
|
b: Byte;
|
|
fb: TBitmap;
|
|
fm: TStringList;
|
|
pos: Integer;
|
|
begin
|
|
fb := TBitmap.Create;
|
|
fm := TStringList.Create;
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
|
|
if Load then
|
|
begin
|
|
ReadMemo(Stream, fm);
|
|
pos := 0;
|
|
Stream.Read(pos, 4);
|
|
b := 0;
|
|
Stream.Read(b, 1);
|
|
if b <> 0 then
|
|
fb.LoadFromStream(Stream);
|
|
Stream.Position := pos;
|
|
Stream.Read(frVersion, 1);
|
|
Pages.LoadFromStream(Stream);
|
|
end
|
|
else
|
|
begin
|
|
ReadMemo(Stream, Comm);
|
|
Stream.Read(pos, 4);
|
|
Bmp.Assign(nil);
|
|
Stream.Read(b, 1);
|
|
if b <> 0 then
|
|
Bmp.LoadFromStream(Stream);
|
|
end;
|
|
fm.Free; fb.Free;
|
|
Stream.Free;
|
|
end;
|
|
|
|
procedure TfrReport.LoadTemplateXML(const fname: String; comm: TStrings;
|
|
Bmp: TBitmap; Load: Boolean);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
BMPSize:integer;
|
|
M:TMemoryStream;
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.Filename := UTF8ToSys(FName);
|
|
try
|
|
if Load then
|
|
begin
|
|
LoadFromXML(XML, lrTemplatePath);
|
|
FileName := '';
|
|
end
|
|
else
|
|
begin
|
|
comm.Text:=XML.GetValue(lrTemplatePath + 'Description/Value', '');
|
|
BMPSize:=XML.GetValue(lrTemplatePath + 'Picture/Size/Value', 0);
|
|
if BMPSize>0 then
|
|
begin
|
|
M:=TMemoryStream.Create;
|
|
XMLToStream(XML, lrTemplatePath + 'Picture/', M);
|
|
M.Position:=0;
|
|
BMP.LoadFromStream(M);
|
|
M.Free;
|
|
end;
|
|
end;
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.SaveTemplate(const fname: String; comm: TStrings;
|
|
Bmp: TBitmap);
|
|
var
|
|
Stream: TFileStream;
|
|
b: Byte;
|
|
pos, lpos: Integer;
|
|
begin
|
|
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
|
|
frWriteMemo(Stream, Comm);
|
|
b := 0;
|
|
pos := Stream.Position;
|
|
lpos := 0;
|
|
Stream.Write(lpos, 4);
|
|
if Bmp.Empty then
|
|
Stream.Write(b, 1)
|
|
else
|
|
begin
|
|
b := 1;
|
|
Stream.Write(b, 1);
|
|
Bmp.SaveToStream(Stream);
|
|
end;
|
|
lpos := Stream.Position;
|
|
Stream.Position := pos;
|
|
Stream.Write(lpos, 4);
|
|
Stream.Position := lpos;
|
|
frVersion := frCurrentVersion;
|
|
Stream.Write(frVersion, 1);
|
|
Pages.SaveToStream(Stream);
|
|
Stream.Free;
|
|
end;
|
|
|
|
procedure TfrReport.SaveTemplateXML(const fname: String; Desc: TStrings;
|
|
Bmp: TBitmap);
|
|
var
|
|
XML: TLrXMLConfig;
|
|
|
|
procedure SavePicture;
|
|
var
|
|
m: TMemoryStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
BMP.SaveToStream(M);
|
|
M.Position:=0;
|
|
StreamToXML(XML, lrTemplatePath+'Picture/', M);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
XML := TLrXMLConfig.Create(nil);
|
|
XML.StartEmpty := True;
|
|
XML.Filename := UTF8ToSys(FName);
|
|
try
|
|
XML.SetValue(lrTemplatePath + 'Description/Value', Desc.Text);
|
|
if not Bmp.Empty then
|
|
SavePicture;
|
|
SaveToXML(XML, lrTemplatePath);
|
|
XML.Flush;
|
|
finally
|
|
XML.Free;
|
|
end;
|
|
end;
|
|
|
|
// report manipulation methods
|
|
function TfrReport.DesignReport: Integer;
|
|
var
|
|
HF: String;
|
|
begin
|
|
CurReport := Self;
|
|
if Pages.Count = 0 then
|
|
Pages.Add;
|
|
HF := Application.HelpFile;
|
|
Application.HelpFile := 'FRuser.hlp';
|
|
if not Assigned(frDesigner) and Assigned(ProcedureInitDesigner) then
|
|
ProcedureInitDesigner();
|
|
if frDesigner <> nil then
|
|
begin
|
|
{$IFDEF MODALDESIGNER}
|
|
Result:=frDesigner.ShowModal;
|
|
{$ELSE}
|
|
frDesigner.Show;
|
|
Result:=mrOk;
|
|
{$ENDIF}
|
|
end;
|
|
Application.HelpFile := HF;
|
|
end;
|
|
|
|
var
|
|
FirstPassTerminated, FirstTime: Boolean;
|
|
|
|
procedure TfrReport.BuildBeforeModal(Sender: TObject);
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrReport.BuildBeforeModal INIT FinalPass=%s DoublePass=%s',[dbgs(FinalPass),dbgs(DoublePass)]);
|
|
{$ENDIF}
|
|
DoBuildReport;
|
|
if FinalPass then
|
|
begin
|
|
if Terminated then
|
|
frProgressForm.ModalDone(mrCancel)
|
|
else
|
|
frProgressForm.ModalDone(mrOk);
|
|
end
|
|
else
|
|
begin
|
|
FirstPassTerminated := Terminated;
|
|
SavedAllPages := EMFPages.Count;
|
|
DoublePass := False;
|
|
FirstTime := False;
|
|
DoPrepareReport; // do final pass
|
|
DoublePass := True;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrReport.BuildBeforeModal DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrReport.PrepareReport: Boolean;
|
|
var
|
|
ParamOk: Boolean;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrReport.PrepareReport INIT');
|
|
{$ENDIF}
|
|
|
|
AggrBand:= nil;
|
|
DocMode := dmPrinting;
|
|
CurDate := Date;
|
|
CurTime := Time;
|
|
MasterReport := Self;
|
|
CurReport := Self;
|
|
Values.Items.Sorted := True;
|
|
frParser.OnGetValue := @GetVariableValue;
|
|
frParser.OnFunction := @OnGetParsFunction;
|
|
DoBeginDoc;
|
|
|
|
Result := False;
|
|
ParamOk := True;
|
|
if frDataManager <> nil then
|
|
begin
|
|
FillQueryParams;
|
|
ParamOk := frDataManager.ShowParamsDialog;
|
|
end;
|
|
|
|
if ParamOk then
|
|
Result := DoPrepareReport;
|
|
|
|
FinalPass := False;
|
|
if frDataManager <> nil then
|
|
frDataManager.AfterParamsDialog;
|
|
|
|
DoEndDoc;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrReport.PrepareReport DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TfrReport.DoPrepareReport: Boolean;
|
|
var
|
|
s: String;
|
|
begin
|
|
Result := True;
|
|
Terminated := False;
|
|
Append := False;
|
|
DisableDrawing := False;
|
|
FinalPass := True;
|
|
FirstTime := True;
|
|
PageNo := 0;
|
|
EMFPages.Clear;
|
|
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('DoPrepareReport INIT DoublePass=%s',[BoolToStr(DoublePass)]);
|
|
{$ENDIF}
|
|
|
|
s := sReportPreparing;
|
|
if DoublePass then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('DoPrepareReport FirstPass Begin');
|
|
{$ENDIF}
|
|
|
|
DisableDrawing := True;
|
|
FinalPass := False;
|
|
if not Assigned(FOnProgress) and FShowProgress then
|
|
begin
|
|
with frProgressForm do
|
|
begin
|
|
if Title = '' then
|
|
Caption := s
|
|
else
|
|
Caption := s + ' - ' + Title;
|
|
|
|
FirstCaption := sFirstPass;
|
|
Label1.Caption := FirstCaption + ' 1';
|
|
OnBeforeModal := @BuildBeforeModal;
|
|
Show_Modal(Self);
|
|
end;
|
|
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('DoPrepareReport FirstPass End');
|
|
{$ENDIF}
|
|
end
|
|
else BuildBeforeModal(nil);
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('DoPrepareReport DONE');
|
|
{$ENDIF}
|
|
Exit;
|
|
end;
|
|
|
|
if not Assigned(FOnProgress) and FShowProgress then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('DoPrepareReport SecondPass begin');
|
|
{$ENDIF}
|
|
|
|
with frProgressForm do
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('1');
|
|
{$ENDIF}
|
|
if Title = '' then
|
|
Caption := s
|
|
else
|
|
Caption := s + ' - ' + Title;
|
|
FirstCaption := sPagePreparing;
|
|
Label1.Caption := FirstCaption + ' 1';
|
|
OnBeforeModal:=@BuildBeforeModal;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('2');
|
|
{$ENDIF}
|
|
if Visible then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('3');
|
|
{$ENDIF}
|
|
if not FirstPassTerminated then
|
|
DoublePass := True;
|
|
|
|
BuildBeforeModal(nil);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('4');
|
|
{$ENDIF}
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('5');
|
|
{$ENDIF}
|
|
SavedAllPages := 0;
|
|
if Show_Modal(Self) = mrCancel then
|
|
Result := False;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('6');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('DoPrepareReport SecondPass End');
|
|
{$ENDIF}
|
|
end;
|
|
end
|
|
else BuildBeforeModal(nil);
|
|
Terminated := False;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('DoPrepareReport DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
var
|
|
ExportStream: TFileStream;
|
|
|
|
procedure TfrReport.ExportBeforeModal(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Application.ProcessMessages;
|
|
for i := 0 to EMFPages.Count - 1 do
|
|
begin
|
|
FCurrentFilter.OnBeginPage;
|
|
EMFPages.ExportData(i);
|
|
InternalOnProgress(i + 1);
|
|
Application.ProcessMessages;
|
|
FCurrentFilter.OnEndPage;
|
|
end;
|
|
FCurrentFilter.OnEndDoc;
|
|
frProgressForm.ModalResult := mrOk;
|
|
end;
|
|
|
|
procedure TfrReport.ExportTo(FilterClass: TfrExportFilterClass; aFileName: String);
|
|
var
|
|
s: String;
|
|
i: Integer;
|
|
begin
|
|
// try to find a export filter from registered list
|
|
if (FilterClass=nil) and (fDefExportFilterClass<>'') then
|
|
begin
|
|
for i:=0 to Length(frFilters)-1 do
|
|
if (frFilters[i].ClassRef.ClassName=fDefExportFilterClass) then
|
|
begin
|
|
FilterClass := frFilters[i].ClassRef;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if (aFileName='') and (fDefExportFileName<>'') then
|
|
aFileName := fDefExportFileName;
|
|
|
|
if FilterClass=nil then begin
|
|
raise Exception.Create('No valid filterclass was supplied');
|
|
end;
|
|
|
|
if aFilename='' then begin
|
|
raise Exception.create('No valid export filename was supplied');
|
|
end;
|
|
|
|
ExportStream := TFileStream.Create(UTF8ToSys(aFileName), fmCreate);
|
|
FCurrentFilter := FilterClass.Create(ExportStream);
|
|
|
|
CurReport := Self;
|
|
MasterReport := Self;
|
|
|
|
FCurrentFilter.OnSetup:=CurReport.OnExportFilterSetup;
|
|
|
|
FCurrentFilter.Setup;
|
|
FCurrentFilter.OnBeginDoc;
|
|
|
|
SavedAllPages := EMFPages.Count;
|
|
|
|
if FCurrentFilter.UseProgressbar then
|
|
with frProgressForm do
|
|
begin
|
|
s := sReportPreparing;
|
|
if Title = '' then
|
|
Caption := s
|
|
else
|
|
Caption := s + ' - ' + Title;
|
|
FirstCaption := sPagePreparing;
|
|
Label1.Caption := FirstCaption + ' 1';
|
|
OnBeforeModal := @ExportBeforeModal;
|
|
Show_Modal(Self);
|
|
end else
|
|
ExportBeforeModal(nil);
|
|
|
|
fDefExportFilterClass := FCurrentFilter.ClassName;
|
|
fDefExportFileName := aFileName;
|
|
|
|
FreeAndNil(FCurrentFilter);
|
|
ExportStream.Free;
|
|
end;
|
|
|
|
procedure TfrReport.FillQueryParams;
|
|
var
|
|
i, j: Integer;
|
|
t: TfrView;
|
|
procedure PrepareDS(ds: TComponent);
|
|
begin
|
|
if ds is TfrDBDataSet then
|
|
frDataManager.PrepareDataSet(TfrDBDataSet(ds).GetDataSet);
|
|
end;
|
|
begin
|
|
if frDataManager = nil then Exit;
|
|
frDataManager.BeforePreparing;
|
|
PrepareDS(DataSet);
|
|
for i := 0 to Pages.Count - 1 do
|
|
for j := 0 to Pages[i].Objects.Count-1 do
|
|
begin
|
|
t :=TfrView(Pages[i].Objects[j]);
|
|
if t is TfrBandView then
|
|
PrepareDS(frFindComponent(CurReport.Owner, TfrBandView(t).DataSet));
|
|
end;
|
|
frDataManager.AfterPreparing;
|
|
end;
|
|
|
|
procedure TfrReport.DoBuildReport;
|
|
var
|
|
i : Integer;
|
|
b : Boolean;
|
|
BM : Pointer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrReport.DoBuildReport INIT');
|
|
{$ENDIF}
|
|
HookList.Clear;
|
|
CanRebuild := True;
|
|
DocMode := dmPrinting;
|
|
CurReport := Self;
|
|
Values.Items.Sorted := True;
|
|
frParser.OnGetValue := @GetVariableValue;
|
|
frParser.OnFunction := @OnGetParsFunction;
|
|
ErrorFlag := False;
|
|
b := (Dataset <> nil) and (ReportType = rtMultiple);
|
|
if b then
|
|
begin
|
|
BM:=DataSet.GetBookMark;
|
|
DataSet.DisableControls;
|
|
Dataset.Init;
|
|
Dataset.First;
|
|
end;
|
|
try
|
|
if (DoublePass and not FinalPass) or (not DoublePass) then
|
|
begin
|
|
ExecScript;
|
|
|
|
for i := 0 to Pages.Count - 1 do
|
|
Pages[i].Skip := False;
|
|
|
|
for i := 0 to Pages.Count - 1 do
|
|
begin
|
|
if Pages[i] is TfrPageDialog then
|
|
begin
|
|
Pages[i].InitReport;
|
|
if Terminated then
|
|
begin
|
|
FinalPass:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not Terminated then
|
|
begin
|
|
for i := 0 to Pages.Count - 1 do
|
|
if Pages[i] is TfrPageReport then
|
|
Pages[i].InitReport;
|
|
|
|
PrepareDataSets;
|
|
for i := 0 to Pages.Count - 1 do
|
|
if Pages[i]is TfrPageReport then
|
|
Pages[i].PrepareObjects;
|
|
|
|
repeat
|
|
{$IFDEF DebugLR}
|
|
DebugLn('p1');
|
|
{$ENDIF}
|
|
InternalOnProgress(PageNo + 1);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('p2');
|
|
{$ENDIF}
|
|
|
|
for i := 0 to Pages.Count - 1 do
|
|
begin
|
|
if Pages[i] is TfrPageReport then
|
|
begin
|
|
FCurPage := Pages[i];
|
|
if FCurPage.Skip or (not FCurPage.Visible) then
|
|
Continue;
|
|
FCurPage.Mode := pmNormal;
|
|
if Assigned(FOnManualBuild) then
|
|
FOnManualBuild(FCurPage)
|
|
else
|
|
FCurPage.FormPage;
|
|
|
|
{$IFDEF DebugLR}
|
|
debugLn('p3');
|
|
{$ENDIF}
|
|
|
|
Append := False;
|
|
if ((i = Pages.Count - 1) and CompositeMode and (not b or Dataset.Eof)) or
|
|
((i <> Pages.Count - 1) and Pages[i + 1].PrintToPrevPage) then
|
|
begin
|
|
Dec(PageNo);
|
|
Append := True;
|
|
end;
|
|
if not Append then
|
|
begin
|
|
PageNo := MasterReport.EMFPages.Count;
|
|
InternalOnProgress(PageNo);
|
|
end;
|
|
if MasterReport.Terminated then
|
|
Break;
|
|
end;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('p4');
|
|
{$ENDIF}
|
|
|
|
InternalOnProgress(PageNo);
|
|
if b then
|
|
Dataset.Next;
|
|
until MasterReport.Terminated or not b or Dataset.Eof;
|
|
|
|
for i := 0 to Pages.Count - 1 do
|
|
Pages[i].DoneReport;
|
|
|
|
end;
|
|
finally
|
|
if b then
|
|
begin
|
|
Dataset.Exit;
|
|
DataSet.GotoBookMark(BM);
|
|
DataSet.FreeBookMark(BM);
|
|
DataSet.EnableControls;
|
|
end;
|
|
end;
|
|
if (frDataManager <> nil) and FinalPass then
|
|
frDataManager.AfterPreparing;
|
|
Values.Items.Sorted := False;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrReport.DoBuildReport DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrReport.ShowReport;
|
|
begin
|
|
PrepareReport;
|
|
if ErrorFlag then
|
|
begin
|
|
MessageDlg(ErrorStr,mtError,[mbOk],0);
|
|
EMFPages.Clear;
|
|
end
|
|
else
|
|
ShowPreparedReport;
|
|
end;
|
|
|
|
procedure TfrReport.ShowPreparedReport;
|
|
var
|
|
s: String;
|
|
p: TfrPreviewForm;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrReport.ShowPreparedReport INIT');
|
|
{$ENDIF}
|
|
CurReport := Self;
|
|
MasterReport := Self;
|
|
DocMode := dmPrinting;
|
|
if EMFPages.Count = 0 then Exit;
|
|
s := sPreview;
|
|
if Title <> '' then
|
|
s := s + ' - ' + Title;
|
|
|
|
if not (csDesigning in ComponentState) and Assigned(Preview) then
|
|
begin
|
|
Preview.Connect(Self);
|
|
end
|
|
else
|
|
begin
|
|
p := TfrPreviewForm.Create(nil);
|
|
p.BorderIcons:=p.BorderIcons - [biMinimize];
|
|
{$IFDEF DebugLR}
|
|
DebugLn('1 TfrPreviewForm.visible=%s',[BooLToStr(p.Visible)]);
|
|
{$ENDIF}
|
|
p.Caption := s;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('2 TfrPreviewForm.visible=%s',[BooLToStr(p.Visible)]);
|
|
{$ENDIF}
|
|
if ExportFilename<>'' then
|
|
begin
|
|
p.SaveDialog.InitialDir := ExtractFilePath(ExportFileName);
|
|
p.SaveDialog.FileName := ExportFilename;
|
|
end;
|
|
p.Show_Modal(Self);
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrReport.ShowPreparedReport DONE');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrReport.PrintBeforeModal(Sender: TObject);
|
|
begin
|
|
DoPrintReport(FPageNumbers, FCopies);
|
|
frProgressForm.ModalResult := mrOk;
|
|
end;
|
|
|
|
procedure TfrReport.PrintPreparedReport(const PageNumbers: String; Copies: Integer);
|
|
var
|
|
s: String;
|
|
begin
|
|
CurReport:=Self;
|
|
MasterReport:=Self;
|
|
s:=sReportPreparing;
|
|
Terminated:=False;
|
|
FPageNumbers:=PageNumbers;
|
|
FCopies:=Copies;
|
|
|
|
if not Assigned(FOnProgress) and FShowProgress then
|
|
begin
|
|
with frProgressForm do
|
|
begin
|
|
if Title = '' then
|
|
Caption := s
|
|
else
|
|
Caption := s + ' - ' + Title;
|
|
|
|
FirstCaption := sPagePrinting;
|
|
Label1.Caption := FirstCaption;
|
|
OnBeforeModal := @PrintBeforeModal;
|
|
|
|
Show_Modal(Self);
|
|
end
|
|
end
|
|
else PrintBeforeModal(nil);
|
|
|
|
Terminated := False;
|
|
end;
|
|
|
|
procedure TfrReport.DoPrintReport(const PageNumbers: String; Copies: Integer);
|
|
var
|
|
k, FCollateCopies: Integer;
|
|
f: Boolean;
|
|
pgList: TStringList;
|
|
|
|
procedure ParsePageNumbers;
|
|
var
|
|
i, j, n1, n2: Integer;
|
|
s: String;
|
|
IsRange: Boolean;
|
|
begin
|
|
s := PageNumbers;
|
|
|
|
while Pos(' ', s) <> 0 do
|
|
Delete(s, Pos(' ', s), 1);
|
|
if s = '' then Exit;
|
|
|
|
s := s + ',';
|
|
i := 1; j := 1; n1 := 1;
|
|
IsRange := False;
|
|
while i <= Length(s) do
|
|
begin
|
|
if s[i] = ',' then
|
|
begin
|
|
n2 := StrToInt(Copy(s, j, i - j));
|
|
j := i + 1;
|
|
if IsRange then
|
|
begin
|
|
while n1 <= n2 do
|
|
begin
|
|
pgList.Add(IntToStr(n1));
|
|
Inc(n1);
|
|
end;
|
|
end
|
|
else
|
|
pgList.Add(IntToStr(n2));
|
|
|
|
IsRange := False;
|
|
end
|
|
else if s[i] = '-' then
|
|
begin
|
|
IsRange := True;
|
|
n1 := StrToInt(Copy(s, j, i - j));
|
|
j := i + 1;
|
|
end;
|
|
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
procedure PrintPage(n: Integer);
|
|
begin
|
|
with Printer, EMFPages[n]^ do
|
|
begin
|
|
if not Prn.IsEqual(pgSize, pgWidth, pgHeight, pgOr) then
|
|
begin
|
|
EndDoc;
|
|
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
|
|
BeginDoc;
|
|
end
|
|
else if not f then
|
|
NewPage;
|
|
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
Visible := True;
|
|
|
|
with PrnInfo do
|
|
begin
|
|
if pgMargins then
|
|
EMFPages.Draw(n, Printer.Canvas, Rect(-POfx, -POfy, PPgw - POfx, PPgh - POfy))
|
|
else
|
|
EMFPages.Draw(n, Printer.Canvas, Rect(0, 0, PPw, PPh));
|
|
end;
|
|
|
|
Visible := False;
|
|
EMFPages.Draw(n, Printer.Canvas, Rect(0, 0, 0, 0));
|
|
end;
|
|
InternalOnProgress(n + 1);
|
|
Application.ProcessMessages;
|
|
f := False;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
procedure DebugPrnInfo(msg: string);
|
|
var
|
|
k: integer;
|
|
begin
|
|
DebugLn('--------------------------------------------------');
|
|
DebugLn(Msg);
|
|
for k:=0 to EMFPages.Count-1 do begin
|
|
DebugLn('EMFPage ',dbgs(k));
|
|
with EmfPages[k]^.PrnInfo do begin
|
|
DebugLn(Format(' Ppgw=%d PPgh=%d Pgw=%d Pgh=%d',[PPgw,PPgh,Pgw,Pgh]));
|
|
DebugLn(Format(' Pofx=%d POfy=%d Ofx=%d Ofy=%d',[POfx,POfy,Ofx,Ofy]));
|
|
DebugLn(Format(' Ppw=%d Pph=%d Pw=%d Ph=%d',[Ppw,Pph,Pw,Ph]));
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure InternalPrintEMFPage;
|
|
var
|
|
i, j:integer;
|
|
begin
|
|
for i := 0 to EMFPages.Count - 1 do
|
|
begin
|
|
if (pgList.Count = 0) or (pgList.IndexOf(IntToStr(i + 1)) <> -1) then
|
|
begin
|
|
for j := 0 to Copies - 1 do
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugPrnInfo('=== Before PrintPage('+IntToStr(i)+')');
|
|
{$ENDIF}
|
|
PrintPage(i);
|
|
|
|
if Terminated then
|
|
begin
|
|
Printer.Abort;
|
|
pgList.Free;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('DoPrintReport INIT');
|
|
DebugPrnInfo('=== INIT');
|
|
{$ENDIF}
|
|
Prn.Printer := Printer;
|
|
pgList := TStringList.Create;
|
|
|
|
ParsePageNumbers;
|
|
|
|
if Copies <= 0 then
|
|
Copies := 1;
|
|
|
|
FCollateCopies:=Copies;
|
|
|
|
with EMFPages[0]^ do
|
|
begin
|
|
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
|
|
Prn.FillPrnInfo(PrnInfo);
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugPrnInfo('=== AFTER EMFPages[0]^');
|
|
{$ENDIF}
|
|
if Title <> '' then
|
|
Printer.Title:=Format('%s',[Title])
|
|
else
|
|
Printer.Title:=Format('LazReport : %s',[sUntitled]);
|
|
|
|
Printer.BeginDoc;
|
|
f:= True;
|
|
|
|
if FDefaultCollate then
|
|
begin
|
|
Copies:=1;
|
|
for k:=1 to FCollateCopies do
|
|
InternalPrintEMFPage;
|
|
end
|
|
else
|
|
InternalPrintEMFPage;
|
|
|
|
Printer.EndDoc;
|
|
pgList.Free;
|
|
{$IFDEF DebugLR}
|
|
DebugPrnInfo('=== END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TfrReport.SetComments(const AValue: TStringList);
|
|
begin
|
|
FComments.Assign(AValue);
|
|
end;
|
|
|
|
// printer manipulation methods
|
|
|
|
procedure TfrReport.SetPrinterTo(const PrnName: String);
|
|
begin
|
|
{$ifdef dbgPrinter}
|
|
DebugLn;
|
|
DebugLnENTER('TfrReport.SetPrinterTo PrnName="%s" PrnExist?=%s CurPrinter=%s',
|
|
[prnName, dbgs(Prn.Printers.IndexOf(PrnName)>=0), prn.Printer.PrinterName]);
|
|
DebugLn(['PrintToDefault=',PrintToDefault,' prnIndex=',prn.PrinterIndex,
|
|
' PrinterIndex=',Prn.Printer.PrinterIndex]);
|
|
{$endif}
|
|
if not PrintToDefault then
|
|
begin
|
|
if Prn.Printers.IndexOf(PrnName) <> -1 then
|
|
Prn.PrinterIndex := Prn.Printers.IndexOf(PrnName)
|
|
else
|
|
if Prn.Printers.Count>0 then
|
|
Prn.PrinterIndex := 0 // either the system default or
|
|
// own virtual default printer
|
|
end;
|
|
{$ifdef dbgPrinter}
|
|
DebugLnExit('TfrReport.SetPrinterTo DONE Printer="%s"',[Prn.Printer.PrinterName]);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrReport.SetScript(AValue: TfrScriptStrings);
|
|
begin
|
|
fScript.Assign(AValue);
|
|
end;
|
|
|
|
function TfrReport.ChangePrinter(OldIndex, NewIndex: Integer): Boolean;
|
|
|
|
procedure ChangePages;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Pages.Count - 1 do
|
|
begin
|
|
if Pages[i] is TfrPageReport then
|
|
Pages[i].ChangePaper(Pages[i].pgSize, Pages[i].Width, Pages[i].Height, Pages[i].Orientation);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
{$ifdef dbgPrinter}
|
|
DebugLn;
|
|
DebugLnEnter('TfrReport.ChangePrinter INIT CurIndex=%d OldIndex=%d NewIndex=%d',
|
|
[Prn.PrinterIndex,OldIndex,NewIndex]);
|
|
DebugLn('CurPrinter=%s NewPrinter=%s',[prn.Printer.PrinterName, prn.Printer.Printers[NewIndex]]);
|
|
{$endif}
|
|
Result := True;
|
|
try
|
|
Prn.PrinterIndex := NewIndex;
|
|
Prn.PaperSize := -1;
|
|
ChangePages;
|
|
except
|
|
on E:Exception do
|
|
begin
|
|
{$ifdef dbgPrinter}DebugLn('Change printer error: %s',[E.Message]);{$endif}
|
|
MessageDlg(sPrinterError,mtError,[mbOk],0);
|
|
Prn.PrinterIndex := OldIndex;
|
|
ChangePages;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
{$ifdef dbgPrinter}
|
|
DebugLnExit('TfrReport.ChangePrinter DONE Printer=%s', [Prn.Printer.PrinterName]);
|
|
{$endif}
|
|
end;
|
|
|
|
procedure TfrReport.EditPreparedReport(PageIndex: Integer);
|
|
var
|
|
p: PfrPageInfo;
|
|
Stream: TMemoryStream;
|
|
Designer: TfrReportDesigner;
|
|
DesName: String;
|
|
begin
|
|
if frDesigner = nil then Exit;
|
|
Screen.Cursor := crHourGlass;
|
|
Designer := frDesigner;
|
|
DesName := Designer.Name;
|
|
Designer.Name := DesName + '__';
|
|
Designer.Page := nil;
|
|
frDesigner := TfrReportDesigner(frDesigner.ClassType.NewInstance);
|
|
frDesigner.Create(nil){%H-};
|
|
frDesigner.PreparedReportEditor:=true;
|
|
Stream := TMemoryStream.Create;
|
|
SaveToStream(Stream);
|
|
Pages.Clear;
|
|
EMFPages.ObjectsToPage(PageIndex);
|
|
p := EMFPages[PageIndex];
|
|
Pages.FPages.Add(p^.Page);
|
|
CurReport := Self;
|
|
Screen.Cursor := crDefault;
|
|
try
|
|
frDesigner.ShowModal;
|
|
if frDesigner.Modified then
|
|
if MessageDlg(sSaveChanges+' ?',mtConfirmation,[mbYes,mbNo],0)=mrYes then
|
|
EMFPages.PageToObjects(PageIndex);
|
|
finally
|
|
Pages.FPages.Clear;
|
|
Stream.Position := 0;
|
|
LoadFromStream(Stream);
|
|
Stream.Free;
|
|
frDesigner.Free;
|
|
frDesigner := Designer;
|
|
frDesigner.Name := DesName;
|
|
if Pages.Count>0 then
|
|
begin
|
|
frDesigner.Page := Pages[0];
|
|
frDesigner.RedrawPage;
|
|
end
|
|
else
|
|
frDesigner.Page := nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
// miscellaneous methods
|
|
procedure TfrReport.PrepareDataSets;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
with Values do
|
|
for i := 0 to Items.Count - 1 do
|
|
with Objects[i] do
|
|
if Typ = vtDBField then
|
|
DSet := frGetDataSet(DataSet);
|
|
end;
|
|
|
|
procedure TfrReport.SetVars(Value: TStrings);
|
|
begin
|
|
FVars.Assign(Value);
|
|
end;
|
|
|
|
procedure TfrReport.ClearAttribs;
|
|
begin
|
|
// FDefaultTitle:='';
|
|
FTitle:='';
|
|
FSubject:='';
|
|
FKeyWords:='';
|
|
FComments.Clear;
|
|
|
|
ReportAutor := '';
|
|
ReportVersionMajor := '';
|
|
ReportVersionMinor := '';
|
|
ReportVersionRelease := '';
|
|
ReportVersionBuild := '';
|
|
ReportCreateDate := Now;
|
|
ReportLastChange := Now;
|
|
end;
|
|
|
|
function TfrReport.FindObjectByName(AName: string): TfrObject;
|
|
var
|
|
APgName:string;
|
|
Pg:TfrPage;
|
|
begin
|
|
AName:=UpperCase(AName);
|
|
Result:=nil;
|
|
if (Pos('.', AName)>0) then
|
|
begin
|
|
APgName:=Copy2SymbDel(AName, '.');
|
|
Pg:=FPages.PageByName(APgName);
|
|
if Assigned(Pg) then
|
|
Result:=Pg.FindObject(AName);
|
|
end
|
|
else
|
|
Result:=FindObject(AName);
|
|
end;
|
|
|
|
procedure TfrReport.ExecScript;
|
|
var
|
|
CmdList, ErrorList:TStringList;
|
|
begin
|
|
if DocMode = dmPrinting then
|
|
begin
|
|
CmdList:=TStringList.Create;
|
|
ErrorList:=TStringList.Create;
|
|
try
|
|
CurView := nil;
|
|
CurPage := nil;
|
|
frInterpretator.PrepareScript(Script, CmdList, ErrorList);
|
|
frInterpretator.DoScript(CmdList);
|
|
finally
|
|
FreeAndNil(CmdList);
|
|
FreeAndNil(ErrorList);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.DoBeginBand(Band: TfrBand);
|
|
begin
|
|
if Assigned(FOnBeginBand) then
|
|
FOnBeginBand(Band);
|
|
end;
|
|
|
|
procedure TfrReport.DoBeginColumn(Band: TfrBand);
|
|
begin
|
|
if Assigned(FOnBeginColumn) then
|
|
OnBeginColumn(Band);
|
|
end;
|
|
|
|
procedure TfrReport.DoBeginDoc;
|
|
begin
|
|
if Assigned(FOnBeginDoc) then
|
|
FOnBeginDoc;
|
|
end;
|
|
|
|
procedure TfrReport.DoBeginPage(pgNo: Integer);
|
|
begin
|
|
if Assigned(FOnBeginPage) then
|
|
FOnBeginPage(pgNo);
|
|
end;
|
|
|
|
procedure TfrReport.DoEndBand(Band: TfrBand);
|
|
begin
|
|
if Assigned(FOnEndBand) then
|
|
FOnEndBand(Band);
|
|
end;
|
|
|
|
procedure TfrReport.DoEndDoc;
|
|
begin
|
|
if Assigned(FOnEndDoc) then
|
|
FOnEndDoc;
|
|
end;
|
|
|
|
procedure TfrReport.DoEndPage(pgNo: Integer);
|
|
begin
|
|
if Assigned(FOnEndPage) then
|
|
FOnEndPage(pgNo);
|
|
end;
|
|
|
|
procedure TfrReport.DoEnterRect(Memo: TStringList; View: TfrView);
|
|
begin
|
|
if Assigned(FOnEnterRect) then
|
|
FOnEnterRect(Memo, View);
|
|
end;
|
|
|
|
procedure TfrReport.DoGetValue(const ParName: String; var ParValue: Variant);
|
|
begin
|
|
if Assigned(FOnGetValue) then
|
|
FOnGetValue(ParName, ParValue);
|
|
end;
|
|
|
|
procedure TfrReport.DoPrintColumn(ColNo: Integer; var Width: Integer);
|
|
begin
|
|
if Assigned(FOnPrintColumn) then
|
|
FOnPrintColumn(ColNo, Width);
|
|
end;
|
|
|
|
procedure TfrReport.DoUserFunction(const AName: String; p1, p2, p3: Variant;
|
|
var Val: Variant);
|
|
begin
|
|
if Assigned(FOnFunction) then
|
|
FOnFunction(AName, p1, p2, p3, Val);
|
|
end;
|
|
|
|
procedure TfrReport.Loaded;
|
|
var
|
|
st: TStringStream;
|
|
begin
|
|
inherited Loaded;
|
|
if FXMLReport<>'' then
|
|
begin
|
|
st := TStringStream.Create(FXMLReport);
|
|
LoadFromXMLStream(st);
|
|
st.free;
|
|
FXMLReport := '';
|
|
end;
|
|
if assigned(FDFMStream) then
|
|
begin
|
|
LoadFromStream(FDFMStream);
|
|
FreeAndNil(FDFMStream);
|
|
FStoreInForm := true;
|
|
FStoreInDFM := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.GetVarList(CatNo: Integer; List: TStrings);
|
|
var
|
|
i, n: Integer;
|
|
s: String;
|
|
begin
|
|
List.Clear;
|
|
i := 0; n := 0;
|
|
if FVars.Count > 0 then
|
|
repeat
|
|
s := FVars[i];
|
|
if Length(s) > 0 then
|
|
if s[1] <> ' ' then Inc(n);
|
|
Inc(i);
|
|
until n > CatNo;
|
|
while i < FVars.Count do
|
|
begin
|
|
s := FVars[i];
|
|
if (s <> '') and (s[1] = ' ') then
|
|
List.Add(Copy(s, 2, Length(s) - 1)) else
|
|
break;
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.GetIntrpValue(AName: String; var AValue: Variant);
|
|
var
|
|
t: TfrObject;
|
|
Prop: String;
|
|
n:integer;
|
|
PropInfo:PPropInfo;
|
|
St:string;
|
|
i:integer;
|
|
begin
|
|
|
|
t := CurView;
|
|
Prop := AName;
|
|
|
|
if frVariables.IndexOf(AName) <> -1 then
|
|
begin
|
|
AValue := frVariables[AName];
|
|
exit;
|
|
end;
|
|
|
|
if AName = 'FREESPACE' then
|
|
begin
|
|
AValue:=IntToStr(CurPage.CurBottomY-CurPage.CurY);
|
|
exit;
|
|
end;
|
|
|
|
N:=PosLast('.', AName);
|
|
t:=nil;
|
|
|
|
if N>0 then
|
|
begin
|
|
Prop:=Copy(AName, N+1, Length(AName));
|
|
Delete(AName, N, Length(AName));
|
|
//Проверим - существует ли такой объект?
|
|
t := FindObjectByName(AName);
|
|
end;
|
|
|
|
if Assigned(t) then
|
|
begin
|
|
//Retreive property informations
|
|
PropInfo:=GetPropInfo(t,Prop);
|
|
if Assigned(PropInfo) then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TInterpretator.GetValue(',Name,') Prop=',Prop, ' Kind=',InttoStr(Ord(PropInfo^.PropType^.Kind)));
|
|
{$ENDIF}
|
|
case PropInfo^.PropType^.Kind of
|
|
tkChar,tkAString,tkWString,
|
|
tkSString,tkLString :
|
|
begin
|
|
St:=GetStrProp(t, Prop);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('St=',St);
|
|
{$ENDIF}
|
|
AValue:=St;
|
|
end;
|
|
tkBool,tkInt64,tkQWord,
|
|
tkInteger : AValue:=GetOrdProp(t,PropInfo);
|
|
tkSet : begin
|
|
St:=GetSetProp(t,Prop);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('St=',St);
|
|
{$ENDIF}
|
|
AValue:=St;
|
|
end;
|
|
tkFloat : AValue:=GetFloatProp(t,Prop);
|
|
tkEnumeration : begin
|
|
St:=GetEnumProp(t,Prop);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('St=',St);
|
|
{$ENDIF}
|
|
AValue:=St;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// it's not a property of t, try with known color names first
|
|
for i := 0 to 16 do
|
|
if AnsiCompareText(ColNames[i], Prop) = 0 then
|
|
begin
|
|
// color constant found.
|
|
if i <> 16 then
|
|
AValue := frColors[i]
|
|
else
|
|
AValue := clNone;
|
|
exit;
|
|
end;
|
|
|
|
// it's not a color name, try with customized properties
|
|
// not included directly in t
|
|
if not (t is TfrBandView) then
|
|
begin
|
|
for i:=0 to propcount-1 do
|
|
if CompareText(PropNames[i], Prop)=0 then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DbgOut('A CustomField was found ', Prop);
|
|
if i=0 then
|
|
DbgOut(', t.memo.text=',DbgStr(t.Memo.Text));
|
|
DebugLn;
|
|
{$ENDIF}
|
|
case i of
|
|
0: AValue := t.GetText; //t.Memo.Text;
|
|
1: AValue := TfrMemoView(t).Font.Name;
|
|
2: AValue := TfrMemoView(t).Font.Size;
|
|
3: AValue := frGetFontStyle(TfrMemoView(t).Font.Style);
|
|
4: AValue := TfrMemoView(t).Font.Color;
|
|
5: AValue := TfrMemoView(t).Adjust;
|
|
end;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TInterpretator.GetValue(',Name,') No Propinfo for Prop=',Prop,' Value=',dbgs(AValue));
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TfrReport.GetCategoryList(List: TStrings);
|
|
var
|
|
i: Integer;
|
|
s: String;
|
|
begin
|
|
List.Clear;
|
|
for i := 0 to FVars.Count - 1 do
|
|
begin
|
|
s := FVars[i];
|
|
if (Length(s)>0) and (s[1]<>' ') then
|
|
List.Add(s);
|
|
end;
|
|
end;
|
|
|
|
function TfrReport.FindVariable(Variable: String): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := -1;
|
|
Variable := ' ' + Variable;
|
|
for i := 0 to FVars.Count - 1 do
|
|
if Variable = FVars[i] then
|
|
begin
|
|
Result := i;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TfrReport.FindObject(const aName: String): TfrObject;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
for i := 0 to Pages.Count - 1 do
|
|
begin
|
|
Result:=Pages[i].FindObject(aName);
|
|
if Assigned(Result) then
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrCompositeReport.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
Reports := TFpList.Create;
|
|
end;
|
|
|
|
destructor TfrCompositeReport.Destroy;
|
|
begin
|
|
Reports.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrCompositeReport.DoBuildReport;
|
|
var
|
|
i: Integer;
|
|
Doc: TfrReport;
|
|
ParamOk: Boolean;
|
|
begin
|
|
CanRebuild := True;
|
|
PageNo := 0;
|
|
for i := 0 to Reports.Count - 1 do
|
|
begin
|
|
Doc := TfrReport(Reports[i]);
|
|
CompositeMode := False;
|
|
if i <> Reports.Count - 1 then
|
|
if (TfrReport(Reports[i + 1]).Pages.Count > 0) and
|
|
TfrReport(Reports[i + 1]).Pages[0].PrintToPrevPage then
|
|
CompositeMode := True;
|
|
CurReport := Doc;
|
|
if FirstTime then
|
|
Doc.DoBeginDoc;
|
|
ParamOk := True;
|
|
if (frDataManager <> nil) and FirstTime then
|
|
begin
|
|
Doc.FillQueryParams;
|
|
ParamOk := frDataManager.ShowParamsDialog;
|
|
end;
|
|
if ParamOk then
|
|
Doc.DoBuildReport;
|
|
if (frDataManager <> nil) and FinalPass then
|
|
frDataManager.AfterParamsDialog;
|
|
if FinalPass then
|
|
Doc.DoEndDoc;
|
|
Append := CompositeMode;
|
|
CompositeMode := False;
|
|
if Terminated then break;
|
|
end;
|
|
end;
|
|
|
|
|
|
{----------------------------------------------------------------------------}
|
|
procedure TfrObjEditorForm.ShowEditor(t: TfrView);
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrExportFilter.Create(AStream: TStream);
|
|
begin
|
|
inherited Create;
|
|
Stream := AStream;
|
|
Lines := TFpList.Create;
|
|
FBandTypes := [btReportTitle..btNone];
|
|
end;
|
|
|
|
destructor TfrExportFilter.Destroy;
|
|
begin
|
|
ClearLines;
|
|
Lines.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrExportFilter.ClearLines;
|
|
var
|
|
i: Integer;
|
|
p, p1: PfrTextRec;
|
|
begin
|
|
for i := 0 to Lines.Count - 1 do
|
|
begin
|
|
p := PfrTextRec(Lines[i]);
|
|
while p <> nil do
|
|
begin
|
|
p1 := p;
|
|
p := p^.Next;
|
|
SetLength(p1^.Text, 0);
|
|
FreeMem(p1, SizeOf(TfrTextRec));
|
|
end;
|
|
end;
|
|
Lines.Clear;
|
|
FLineIndex := -1;
|
|
end;
|
|
|
|
procedure TfrExportFilter.Setup;
|
|
begin
|
|
if assigned(FOnSetup) then
|
|
FOnSetup(Self);
|
|
end;
|
|
|
|
function TfrExportFilter.AddData(x, y: Integer; view: TfrView):pointer;
|
|
var
|
|
p: PfrTextRec;
|
|
s: string;
|
|
begin
|
|
result := nil;
|
|
|
|
if (View = nil) or not (View.ParentBandType in BandTypes) then
|
|
exit;
|
|
|
|
if View.Flags and flStartRecord<>0 then
|
|
Inc(FLineIndex);
|
|
|
|
if CheckView(View) then
|
|
begin
|
|
s := GetViewText(View);
|
|
p := nil;
|
|
NewRec(View, s, p);
|
|
AddRec(FLineIndex, p);
|
|
result := p;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrExportFilter.NewRec(View: TfrView; const AText: string;
|
|
var p:pointer);
|
|
begin
|
|
GetMem(p, SizeOf(TfrTextRec));
|
|
FillChar(p^, SizeOf(TfrTextRec), 0);
|
|
with PfrTextRec(p)^ do
|
|
begin
|
|
Next := nil;
|
|
X := View.X;
|
|
W := round(View.Width);
|
|
Typ := View.Typ;
|
|
Text := AText;
|
|
FillColor := View.FillColor;
|
|
Borders := View.Frames;
|
|
BorderColor := View.FrameColor;
|
|
BorderStyle := View.FrameStyle;
|
|
BorderWidth := Round(View.FrameWidth);
|
|
if View is TfrMemoView then
|
|
with View as TfrMemoView do
|
|
begin
|
|
FontName := Font.Name;
|
|
FontSize := Font.Size;
|
|
FontStyle := frGetFontStyle(Font.Style);
|
|
FontColor := Font.Color;
|
|
FontCharset := Font.Charset;
|
|
Alignment := Alignment;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrExportFilter.AddRec(ALineIndex: Integer; ARec: pointer);
|
|
var
|
|
p, p1, p2: PfrTextRec;
|
|
begin
|
|
|
|
p := ARec;
|
|
p1 := Lines[ALineIndex];
|
|
if p1 = nil then
|
|
Lines[ALineIndex] := TObject(p)
|
|
else
|
|
begin
|
|
p2 := p1;
|
|
while (p1 <> nil) and (p1^.X <= p^.X) do
|
|
begin
|
|
p2 := p1;
|
|
p1 := p1^.Next;
|
|
end;
|
|
if p2 <> p1 then
|
|
begin
|
|
p2^.Next := p;
|
|
p^.Next := p1;
|
|
end
|
|
else
|
|
begin
|
|
Lines[ALineIndex] := TObject(p);
|
|
p^.Next := p1;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TfrExportFilter.GetviewText(View: TfrView): string;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
result := '';
|
|
for i:=0 to View.Memo.Count-1 do begin
|
|
result := result + View.Memo[i];
|
|
if i<>View.Memo.Count-1 then
|
|
result := result + LineEnding;
|
|
end;
|
|
end;
|
|
|
|
function TfrExportFilter.CheckView(View: TfrView): boolean;
|
|
begin
|
|
result := true;
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnBeginDoc;
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnEndDoc;
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnBeginPage;
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnEndPage;
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnData(x, y: Integer; View: TfrView);
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnText(x, y: Integer; const text: String; View: TfrView);
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrExportFilter.OnExported(x, y: Integer; View: TfrView);
|
|
begin
|
|
end;
|
|
|
|
function TfrFunctionLibrary.GetCount: integer;
|
|
begin
|
|
result := List.Count + Extra.Count;
|
|
end;
|
|
|
|
function TfrFunctionLibrary.GetDescription(AIndex: Integer
|
|
): TfrFunctionDescription;
|
|
begin
|
|
result := nil;
|
|
if (AIndex>=0) and (AIndex<FunctionCount) then
|
|
begin
|
|
if AIndex<List.Count then
|
|
result := TfrFunctionDescription(List.Objects[AIndex])
|
|
else
|
|
result := TfrFunctionDescription(Extra.Objects[AIndex-List.Count]);
|
|
end;
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrFunctionLibrary.Create;
|
|
begin
|
|
inherited Create;
|
|
List := TStringList.Create;
|
|
Extra:= TStringList.Create;
|
|
//List.Sorted := True;
|
|
end;
|
|
|
|
destructor TfrFunctionLibrary.Destroy;
|
|
procedure FreeList(AList:TStringList);
|
|
var
|
|
i:integer;
|
|
begin
|
|
for i:=0 to AList.Count-1 do
|
|
if Assigned(AList.Objects[i]) then
|
|
begin
|
|
AList.Objects[i].Free;
|
|
AList.Objects[i]:=nil;
|
|
end;
|
|
AList.Free;
|
|
end;
|
|
|
|
begin
|
|
FreeList(List);
|
|
FreeList(Extra);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TfrFunctionLibrary.OnFunction(const FName: String; p1, p2, p3: Variant;
|
|
var val: Variant): Boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := False;
|
|
// if List.Find(FName, i) then
|
|
I:=List.IndexOf(FName);
|
|
if I>=0 then
|
|
begin
|
|
DoFunction(i, p1, p2, p3, val);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrFunctionLibrary.UpdateDescriptions;
|
|
begin
|
|
end;
|
|
|
|
procedure TfrFunctionLibrary.Add(const funName: string; IsExtra:boolean=false);
|
|
begin
|
|
if IsExtra then
|
|
Extra.Add(funName)
|
|
else
|
|
List.Add(FunName);
|
|
end;
|
|
|
|
procedure TfrFunctionLibrary.AddFunctionDesc(const funName, funGroup,
|
|
funDescription: string);
|
|
var
|
|
i: Integer;
|
|
|
|
procedure AddDesc(AList:TStringList);
|
|
begin
|
|
if not Assigned(AList.Objects[i]) then
|
|
AList.Objects[i]:=TfrFunctionDescription.Create;
|
|
TfrFunctionDescription(AList.Objects[i]).funName:=funName;
|
|
TfrFunctionDescription(AList.Objects[i]).funGroup:=funGroup;
|
|
TfrFunctionDescription(AList.Objects[i]).funDescription:=funDescription;
|
|
end;
|
|
|
|
begin
|
|
if List.Find(funName, i) then
|
|
AddDesc(List)
|
|
else
|
|
begin
|
|
i := Extra.IndexOf(funName);
|
|
if i>=0 then
|
|
AddDesc(Extra);
|
|
end;
|
|
end;
|
|
|
|
|
|
{----------------------------------------------------------------------------}
|
|
constructor TfrStdFunctionLibrary.Create;
|
|
begin
|
|
inherited Create;
|
|
Add('AVG'); {0}
|
|
Add('COUNT'); {1}
|
|
Add('DAYOF'); {2}
|
|
Add('FORMATDATETIME'); {3}
|
|
Add('FORMATFLOAT'); {4}
|
|
Add('FORMATTEXT'); {5}
|
|
Add('INPUT'); {6}
|
|
Add('LENGTH'); {7}
|
|
Add('LOWERCASE'); {8}
|
|
Add('MAX'); {9}
|
|
Add('MAXNUM'); {10}
|
|
Add('MESSAGEBOX'); {11}
|
|
Add('MIN'); {12}
|
|
Add('MINNUM'); {13}
|
|
Add('MONTHOF'); {14}
|
|
Add('NAMECASE'); {15}
|
|
Add('POS'); {16}
|
|
Add('STRTODATE'); {17}
|
|
Add('STRTOTIME'); {18}
|
|
Add('SUM'); {19}
|
|
Add('TRIM'); {20}
|
|
Add('UPPERCASE'); {21}
|
|
Add('YEAROF'); {22}
|
|
// internal functions/operators
|
|
Add('COPY', true);
|
|
Add('STR', true);
|
|
Add('INT', true);
|
|
Add('ROUND', true);
|
|
Add('FRAC', true);
|
|
Add('MOD', true);
|
|
|
|
Add('NEWPAGE', true);
|
|
Add('NEWCOLUMN', true);
|
|
Add('STOPREPORT', true);
|
|
Add('SHOWBAND', true);
|
|
Add('INC', true);
|
|
Add('DEC', true);
|
|
end;
|
|
|
|
procedure TfrStdFunctionLibrary.UpdateDescriptions;
|
|
begin
|
|
AddFunctionDesc('AVG', SAggregateCategory, SDescriptionAVG);
|
|
AddFunctionDesc('COUNT', SAggregateCategory, SDescriptionCOUNT);
|
|
AddFunctionDesc('MAX', SAggregateCategory, SDescriptionMAX);
|
|
AddFunctionDesc('MIN', SAggregateCategory, SDescriptionMIN);
|
|
AddFunctionDesc('SUM', SAggregateCategory, SDescriptionSUM);
|
|
|
|
AddFunctionDesc('DAYOF', SDateTimeCategory, SDescriptionDAYOF);
|
|
AddFunctionDesc('MONTHOF', SDateTimeCategory, SDescriptionMONTHOF);
|
|
AddFunctionDesc('STRTODATE', SDateTimeCategory, SDescriptionSTRTODATE);
|
|
AddFunctionDesc('STRTOTIME', SDateTimeCategory, SDescriptionSTRTOTIME);
|
|
AddFunctionDesc('YEAROF', SDateTimeCategory, SDescriptionYEAROF);
|
|
|
|
AddFunctionDesc('FORMATDATETIME', SStringCategory, SDescriptionFORMATDATETIME);
|
|
AddFunctionDesc('FORMATFLOAT', SStringCategory, SDescriptionFORMATFLOAT);
|
|
AddFunctionDesc('FORMATTEXT', SStringCategory, SDescriptionFORMATTEXT);
|
|
AddFunctionDesc('LENGTH', SStringCategory, SDescriptionLENGTH);
|
|
AddFunctionDesc('LOWERCASE', SStringCategory, SDescriptionLOWERCASE);
|
|
AddFunctionDesc('NAMECASE', SStringCategory, SDescriptionNAMECASE);
|
|
AddFunctionDesc('TRIM', SStringCategory, SDescriptionTRIM);
|
|
AddFunctionDesc('UPPERCASE', SStringCategory, SDescriptionUPPERCASE);
|
|
AddFunctionDesc('POS', SStringCategory, SDescriptionPOS);
|
|
AddFunctionDesc('COPY', SStringCategory, SDescriptionCOPY);
|
|
AddFunctionDesc('STR', SStringCategory, SDescriptionSTR);
|
|
|
|
AddFunctionDesc('INPUT', SOtherCategory, SDescriptionINPUT);
|
|
AddFunctionDesc('MESSAGEBOX', SOtherCategory, SDescriptionMESSAGEBOX);
|
|
|
|
AddFunctionDesc('MAXNUM', SMathCategory, SDescriptionMAXNUM);
|
|
AddFunctionDesc('MINNUM', SMathCategory, SDescriptionMINNUM);
|
|
AddFunctionDesc('INT', SMathCategory, SDescriptionINT);
|
|
AddFunctionDesc('ROUND', SMathCategory, SDescriptionROUND);
|
|
AddFunctionDesc('FRAC', SMathCategory, SDescriptionFRAC);
|
|
|
|
AddFunctionDesc('NEWPAGE', SInterpretator, SDescriptionNEWPAGE);
|
|
AddFunctionDesc('NEWCOLUMN', SInterpretator, SDescriptionNEWCOLUMN);
|
|
AddFunctionDesc('STOPREPORT', SInterpretator, SDescriptionSTOPREPORT);
|
|
AddFunctionDesc('SHOWBAND', SInterpretator, SDescriptionSHOWBAND);
|
|
AddFunctionDesc('INC', SInterpretator, SDescriptionINC);
|
|
AddFunctionDesc('DEC', SInterpretator, SDescriptionDEC);
|
|
end;
|
|
|
|
procedure TfrStdFunctionLibrary.DoFunction(FNo: Integer; p1, p2, p3: Variant;
|
|
var val: Variant);
|
|
var
|
|
DataSet: TfrTDataSet;
|
|
Field: TfrTField;
|
|
Obj: TFrObject;
|
|
s1, s2, VarName: String;
|
|
min, max, avg, sum, count, d, v: Double;
|
|
dk: (dkNone, dkSum, dkMin, dkMax, dkAvg, dkCount);
|
|
vv, v2, v1: Variant;
|
|
BM : TBookMark;
|
|
{$IFDEF DebugLR}
|
|
function FNoStr: string;
|
|
begin
|
|
if FNo<=List.Count then
|
|
result := List[FNo]
|
|
else
|
|
result := '???';
|
|
end;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLnEnter('TfrStdFunctionLibrary.DoFunction FNo=%d (%s) p1=%s p2=%s p3=%s val=%s',[FNo,FNoStr,p1,p2,p3,val]);
|
|
{$ENDIF}
|
|
dk := dkNone;
|
|
val := '0';
|
|
case FNo of
|
|
0: dk := dkAvg; //Add('AVG'); {0}
|
|
1: dk := dkCount; //Add('COUNT'); {1}
|
|
2: val := DayOf(frParser.Calc(p1)); //Add('DAYOF'); {2}
|
|
3: val := FormatDateTime(frParser.Calc(p1), frParser.Calc(p2)); //Add('FORMATDATETIME'); {3}
|
|
4: val := FormatFloat(frParser.Calc(p1), frParser.Calc(p2)); //Add('FORMATFLOAT'); {4}
|
|
5: val := FormatMaskText(frParser.Calc(p1) + ';0; ', frParser.Calc(p2)); //Add('FORMATTEXT'); {5}
|
|
6:begin //Add('INPUT'); {6}
|
|
s1 := InputBox('', frParser.Calc(p1), frParser.Calc(p2));
|
|
val := s1;
|
|
end;
|
|
7:val := UTF8Length(frParser.Calc(p1)); //Add('LENGTH'); {7}
|
|
8: val := UTF8LowerCase(frParser.Calc(p1)); //Add('LOWERCASE'); {8}
|
|
9: dk := dkMax; //Add('MAX'); {9}
|
|
10:begin //Add('MAXNUM'); {10}
|
|
v2 := frParser.Calc(p1);
|
|
v1 := frParser.Calc(p2);
|
|
if v2 > v1 then
|
|
val := v2 else
|
|
val := v1;
|
|
end;
|
|
11:val := Application.MessageBox(PChar(String(frParser.Calc(p1))), //Add('MESSAGEBOX'); {11}
|
|
PChar(String(frParser.Calc(p2))), frParser.Calc(p3));
|
|
12: dk := dkMin; //Add('MIN'); {12}
|
|
13:begin //Add('MINNUM'); {13}
|
|
v2 := frParser.Calc(p1);
|
|
v1 := frParser.Calc(p2);
|
|
if v2 < v1 then
|
|
val := v2 else
|
|
val := v1;
|
|
end;
|
|
14: val := MonthOf(frParser.Calc(p1)); //Add('MONTHOF'); {14}
|
|
15:begin //Add('NAMECASE'); {15}
|
|
s1 := UTF8LowerCase(frParser.Calc(p1));
|
|
if Length(s1) > 0 then
|
|
val := UTF8UpperCase(UTF8Copy(S1, 1, 1)) + UTF8Copy(s1, 2, UTF8Length(s1))
|
|
else
|
|
val := '';
|
|
end;
|
|
16:begin // Add('POS'); {16}
|
|
S1:=frParser.Calc(p1);
|
|
S2:=frParser.Calc(p2);
|
|
val := UTF8Pos(S1, S2);
|
|
end;
|
|
17: val := StrToDate(frParser.Calc(p1)); //Add('STRTODATE'); {17}
|
|
18: val := StrToTime(frParser.Calc(p1)); //Add('STRTOTIME'); {18}
|
|
19: dk := dkSum; //Add('SUM'); {19}
|
|
20: begin //Add('TRIM'); {20}
|
|
S1:=frParser.Calc(p1);
|
|
val := Trim(S1);
|
|
end;
|
|
21: val := UTF8UpperCase(frParser.Calc(p1)); //Add('UPPERCASE'); {21}
|
|
22: val := YearOf(frParser.Calc(p1)); //Add('YEAROF'); {22}
|
|
end;
|
|
|
|
if dk <> dkNone then
|
|
begin
|
|
|
|
if dk = dkCount then
|
|
DataSet := frGetDataSet(lrGetUnBrackedStr(p1))
|
|
else
|
|
begin
|
|
// if bandname is provided if yes, don't try to use dataset/field
|
|
Obj := curPage.FindObject(trim(P2));
|
|
|
|
if (obj is TfrBandView) and
|
|
(TfrBandView(Obj).BandType in [btMasterData,btDetailData,
|
|
btSubDetailData,btCrossData])
|
|
then
|
|
DataSet := nil
|
|
else begin
|
|
Dataset := nil;
|
|
frGetDataSetAndField(lrGetUnBrackedStr(p1), DataSet, Field);
|
|
end;
|
|
end;
|
|
|
|
if (DataSet <> nil) and (Field <> nil) and AggrBand.Visible then
|
|
begin
|
|
min := 1e200; max := -1e200; sum := 0; count := 0; avg := 0;
|
|
BM:=DataSet.GetBookMark;
|
|
DataSet.DisableControls;
|
|
try
|
|
DataSet.First;
|
|
while not DataSet.Eof do
|
|
begin
|
|
v := 0;
|
|
if dk <> dkCount then
|
|
begin
|
|
if not Field.IsNull then
|
|
v := Field.AsFloat
|
|
else
|
|
v := 0;
|
|
end;
|
|
|
|
if v > max then max := v;
|
|
if v < min then min := v;
|
|
sum := sum + v;
|
|
count := count + 1;
|
|
DataSet.Next;
|
|
end;
|
|
finally
|
|
DataSet.GotoBookMark(BM);
|
|
DataSet.FreeBookMark(BM);
|
|
DataSet.EnableControls;
|
|
end;
|
|
|
|
if count > 0 then
|
|
avg := sum / count;
|
|
d := 0;
|
|
case dk of
|
|
dkSum: d := sum;
|
|
dkMin: d := min;
|
|
dkMax: d := max;
|
|
dkAvg: d := avg;
|
|
dkCount: d := count;
|
|
end;
|
|
val := d;
|
|
end
|
|
else if (CurBand.View<>nil) and ((DataSet = nil) or (Field = nil)) then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('CurBand=%s CurBand.View=%s AggrBand=%s',
|
|
[BandInfo(CurBand),dbgsName(CurBand.View),BandInfo(AggrBand)]);
|
|
{$ENDIF}
|
|
s1 := Trim(string(p2));
|
|
if s1 = '' then begin
|
|
if (dk=dkCount) and (p1+''<>'') then
|
|
s1 := p1
|
|
else
|
|
s1 := CurBand.View.Name;
|
|
end;
|
|
if dk <> dkCount then
|
|
s2 := Trim(string(p3)) else
|
|
s2 := Trim(string(p2));
|
|
if (AggrBand.Typ in [btPageFooter, btMasterFooter, btDetailFooter,
|
|
btSubDetailFooter, btGroupFooter, btCrossFooter, btReportSummary]) and
|
|
((s2 = '1') or ((s2 <> '1') and CurBand.Visible)) then
|
|
begin
|
|
VarName := List[FNo] + p1;
|
|
if IsColumns then
|
|
if AggrBand.Typ = btCrossFooter then
|
|
VarName := VarName + '00' else
|
|
VarName := VarName + IntToStr(CurPage.ColPos);
|
|
{$ifdef DebugLR}
|
|
dbgOut('VarName=', QuotedStr(VarName));
|
|
{$endif}
|
|
if not AggrBand.Visible and (AnsiCompareText(CurBand.View.Name, s1) = 0) then
|
|
begin
|
|
s1 := AggrBand.Values.Values[VarName];
|
|
{$IFDEF DebugLR}
|
|
dbgOut(' values[',QuotedStr(VarName),']=',QuotedStr(DecodeValue(s1)));
|
|
{$ENDIF}
|
|
if (s1='') or ((s1 <> '') and (s1[1] <> '1')) then
|
|
begin
|
|
s1 := Copy(s1, 2, 255);
|
|
vv := 0;
|
|
if dk <> dkCount then
|
|
vv := frParser.Calc(p1);
|
|
if VarIsNull(vv) or (TVarData(vv).VType=varEmpty) then
|
|
vv := 0;
|
|
{$IFDEF DebugLR}
|
|
dbgOut(' Calc(',QuotedStr(p1),')=',varstr(vv));
|
|
{$ENDIF}
|
|
d := vv;
|
|
if s1 = '' then
|
|
if dk = dkMin then s1 := '1e200'
|
|
else if dk = dkMax then s1 := '-1e200'
|
|
else s1 := '0';
|
|
v := StrToFloat(s1);
|
|
case dk of
|
|
dkAvg: v := v + d;
|
|
dkCount: v := v + 1;
|
|
dkMax: if v < d then v := d;
|
|
dkMin: if v > d then v := d;
|
|
dkSum: v := v + d;
|
|
end;
|
|
AggrBand.Values.Values[VarName] := '1' + FloatToStr(v);
|
|
{$IFDEF DebugLR}
|
|
dbgOut(' NewVal=',dbgs(v),' values[',Quotedstr(VarName),']=',DecodeValue(AggrBand.Values.Values[VarName]));
|
|
{$ENDIF}
|
|
end;
|
|
{$ifdef DebugLR}
|
|
DebugLn('');
|
|
{$endif}
|
|
end
|
|
else if AggrBand.Visible then
|
|
begin
|
|
val := StrToFloatDef(Copy(AggrBand.Values.Values[VarName], 2, 255),0);
|
|
if dk = dkAvg then
|
|
val := val / AggrBand.Count;
|
|
{$ifdef DebugLR}
|
|
DebugLn('Value=%s',[Val]);
|
|
{$endif}
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLnExit('TfrStdFunctionLibrary.DoFunction DONE val=%s',[val]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TInterpretator.GetValue(const Name: String; var Value: Variant);
|
|
begin
|
|
if Assigned(frParser.OnGetValue) then
|
|
frParser.OnGetValue(Name, Value);
|
|
end;
|
|
|
|
procedure TInterpretator.SetValue(const Name: String; Value: Variant);
|
|
var
|
|
t : TfrObject;
|
|
Prop : String;
|
|
PropInfo : PPropInfo;
|
|
St : String;
|
|
i : Integer;
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DebugLn('TInterpretator.SetValue(',Name,',',Value,')');
|
|
|
|
if VarIsNull(Value) or VarIsEmpty(Value) then
|
|
DebugLn('Value=NULL');
|
|
{$ENDIF}
|
|
|
|
t := CurView;
|
|
Prop := Name;
|
|
if Pos('.', Name) <> 0 then
|
|
begin
|
|
St := Copy(Name, 1, Pos('.', Name) - 1);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('Trying to find RT Object "',St,'"');
|
|
{$ENDIF}
|
|
if Assigned(CurPage) then
|
|
t := CurPage.FindRTObject(St);
|
|
if not Assigned(t) then
|
|
t:=CurReport.FindObject(Copy(Name, 1, Pos('.', Name) - 1));
|
|
Prop := Copy(Name, Pos('.', Name) + 1, 255);
|
|
end;
|
|
{$IFDEF DebugLR}
|
|
DebugLn('t=', dbgsName(t),' Prop=',Prop);
|
|
{$ENDIF}
|
|
|
|
//Retreive property informations
|
|
if t is TfrBandView then
|
|
t := TfrBandView(t).Parent;
|
|
|
|
if Assigned(t) then
|
|
PropInfo:=GetPropInfo(t,Prop)
|
|
else
|
|
PropInfo:=nil;
|
|
|
|
if Assigned(PropInfo) then
|
|
begin
|
|
St:=VarToStr(Value);
|
|
{$IFDEF DebugLR}
|
|
DebugLn('PropInfo for ',prop,' found, Setting Value=',St);
|
|
{$ENDIF}
|
|
|
|
Case PropInfo^.PropType^.Kind of
|
|
tkChar,tkAString,tkWString,
|
|
tkSString,tkLString : SetStrProp(t,Prop,St);
|
|
tkBool,tkInt64,tkQWord,
|
|
tkInteger : begin
|
|
if AnsiCompareText(PropInfo^.PropType^.Name,'TGraphicsColor')=0 then
|
|
SetOrdProp(t,PropInfo,StringToColor(St))
|
|
else
|
|
SetOrdProp(t,PropInfo,Value)
|
|
end;
|
|
tkSet : SetSetProp(t,Prop,St);
|
|
tkFloat : SetFloatProp(t,Prop,Value);
|
|
tkEnumeration : SetEnumProp(t,Prop,St);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Assigned(t) and not (t is TfrBandView) then
|
|
begin
|
|
// try with customized properties not included directly in t
|
|
for i:=0 to propcount-1 do
|
|
if CompareText(PropNames[i], Prop)=0 then
|
|
begin
|
|
{$IFDEF DebugLR}
|
|
DbgOut('A CustomField was found ', Prop);
|
|
if i=0 then
|
|
DbgOut(', t.memo.text=',DbgStr(t.Memo.Text),' nuevo valor=',VarToStr(Value));
|
|
DebugLn;
|
|
{$ENDIF}
|
|
case i of
|
|
0: T.SetText(Value); //t.Memo.Text := Value;
|
|
1: TfrMemoView(t).Font.Name := Value;
|
|
2: TfrMemoView(t).Font.Size := Value;
|
|
3: TfrMemoView(t).Font.Style := frSetFontStyle(Value);
|
|
4: TfrMemoView(t).Font.Color := Value;
|
|
5: TfrMemoView(t).Adjust := Value;
|
|
end;
|
|
exit;
|
|
end;
|
|
end;
|
|
// not found, treat it as a variable
|
|
{$IFDEF DebugLR}
|
|
DebugLn('frVariables[',Name,'] := ',Value);
|
|
{$ENDIF}
|
|
|
|
if IsValidIdent(Name) then
|
|
frVariables[Name] := Value
|
|
else
|
|
raise Exception.CreateFmt('"%s" is not a valid variable name.', [Name]); //TODO: Translate this
|
|
end;
|
|
end;
|
|
|
|
procedure TInterpretator.DoFunction(const name: String; p1, p2, p3: Variant;
|
|
var val: Variant);
|
|
begin
|
|
frParser.OnFunction(Name, p1, p2, p3, val);
|
|
end;
|
|
|
|
|
|
{----------------------------------------------------------------------------}
|
|
procedure TfrCompressor.Compress(StreamIn, StreamOut: TStream);
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
procedure TfrCompressor.DeCompress(StreamIn, StreamOut: TStream);
|
|
begin
|
|
// abstract method
|
|
end;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
procedure DoInit;
|
|
begin
|
|
RegisterClasses([TfrPageReport,TfrPageDialog]);
|
|
|
|
frDesigner:=nil;
|
|
|
|
SMemo := TStringList.Create;
|
|
|
|
frRegisterFunctionLibrary(TfrStdFunctionLibrary);
|
|
|
|
frParser := TfrParser.Create;
|
|
frInterpretator := TInterpretator.Create;
|
|
frVariables := TfrVariables.Create;
|
|
frCompressor := TfrCompressor.Create;
|
|
HookList := TFpList.Create;
|
|
end;
|
|
|
|
procedure DoExit;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FHyp.Free;
|
|
SBmp.Free;
|
|
TempBmp.Free;
|
|
SMemo.Free;
|
|
frProgressForm.Free;
|
|
for i := 0 to frFunctionsCount - 1 do
|
|
frFunctions[i].FunctionLibrary.Free;
|
|
frParser.Free;
|
|
frInterpretator.Free;
|
|
frVariables.Free;
|
|
frCompressor.Free;
|
|
HookList.Free;
|
|
end;
|
|
|
|
|
|
{ TfrObject }
|
|
|
|
procedure TfrObject.SetMemo(const AValue: TfrMemoStrings);
|
|
begin
|
|
if fMemo=AValue then exit;
|
|
fMemo.Assign(AValue);
|
|
end;
|
|
|
|
function TfrObject.GetHeight: Integer;
|
|
begin
|
|
Result:=DY;
|
|
end;
|
|
|
|
procedure TfrObject.SetHeight(AValue: Integer);
|
|
begin
|
|
DY:=AValue;
|
|
if Assigned(frDesigner) then
|
|
frDesigner.Invalidate;
|
|
end;
|
|
|
|
function TfrObject.GetWidth: Integer;
|
|
begin
|
|
Result:=DX;
|
|
end;
|
|
|
|
function TfrObject.GetTop: Integer;
|
|
begin
|
|
Result:=Y;
|
|
end;
|
|
|
|
function TfrObject.GetLeft: Integer;
|
|
begin
|
|
Result:=X;
|
|
end;
|
|
|
|
procedure TfrObject.SetLeft(AValue: Integer);
|
|
begin
|
|
X:=AValue;
|
|
if Assigned(frDesigner) then
|
|
frDesigner.Invalidate;
|
|
end;
|
|
|
|
procedure TfrObject.SetName(const AValue: string);
|
|
begin
|
|
if fName=AValue then exit;
|
|
|
|
if (frDesigner<>nil) and (CurReport<>nil) then
|
|
begin
|
|
if CurReport.FindObject(AValue)<>nil then
|
|
begin
|
|
MessageDlg(format(sDuplicatedObjectName,[AValue]),mtError,[mbOk],0);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
fName:=AValue;
|
|
end;
|
|
|
|
procedure TfrObject.AfterLoad;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
function TfrObject.ExecMetod(const AName: String; p1, p2, p3: Variant;
|
|
var Val: Variant): boolean;
|
|
begin
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TfrObject.SetScript(const AValue: TfrScriptStrings);
|
|
begin
|
|
if fScript=AValue then exit;
|
|
fScript.Assign(AValue);
|
|
end;
|
|
|
|
procedure TfrObject.SetVisible(AValue: Boolean);
|
|
begin
|
|
if fVisible=AValue then Exit;
|
|
fVisible:=AValue;
|
|
end;
|
|
|
|
function TfrObject.GetText: string;
|
|
begin
|
|
Result:=fMemo.Text;
|
|
end;
|
|
|
|
procedure TfrObject.SetText(AValue: string);
|
|
begin
|
|
fMemo.Text:=AValue;
|
|
end;
|
|
|
|
procedure TfrObject.SetWidth(AValue: Integer);
|
|
begin
|
|
DX:=AValue;
|
|
if Assigned(frDesigner) then
|
|
frDesigner.Invalidate;
|
|
end;
|
|
|
|
procedure TfrObject.SetTop(AValue: Integer);
|
|
begin
|
|
Y:=AValue;
|
|
if Assigned(frDesigner) then
|
|
frDesigner.Invalidate;
|
|
end;
|
|
|
|
//Code from FormStorage
|
|
function TfrObject.GetSaveProperty(const Prop: String; aObj : TPersistent=nil): string;
|
|
Var PropInfo : PPropInfo;
|
|
Obj : TObject;
|
|
begin
|
|
Result:='';
|
|
|
|
if not Assigned(aObj) then
|
|
aObj:=Self;
|
|
|
|
Try
|
|
PropInfo:=GetPropInfo(aObj,Prop);
|
|
if Assigned(PropInfo) then
|
|
begin
|
|
Case PropInfo^.PropType^.Kind of
|
|
tkChar,tkAString,tkWString,
|
|
tkSString,tkLString : Result:=GetStrProp(aObj,Prop);
|
|
tkBool,tkInt64,tkQWord,
|
|
tkInteger : begin
|
|
if PropInfo^.PropType^.Name='TGraphicsColor' then
|
|
Result:=ColorToString(GetOrdProp(aObj,PropInfo))
|
|
else
|
|
Result:=IntToStr(GetOrdProp(aObj,PropInfo));
|
|
end;
|
|
tkSet : Result:=GetSetProp(aObj,Prop);
|
|
tkFloat : begin
|
|
lrNormalizeLocaleFloats(True);
|
|
Result := FloatToStr(GetFloatProp(aObj,Prop));
|
|
lrNormalizeLocaleFloats(false);
|
|
end;
|
|
tkEnumeration : Result:=GetEnumProp(aObj,Prop);
|
|
tkClass : Begin
|
|
Obj:=GetObjectProp(aObj,Prop);
|
|
if Obj Is TStrings then
|
|
Result:=TStrings(Obj).CommaText
|
|
else
|
|
Result:=Format('Object "%s" not implemented',[PropInfo^.PropType^.Name]);
|
|
end;
|
|
end;
|
|
end
|
|
else Result:='??';
|
|
Except
|
|
End;
|
|
end;
|
|
|
|
//Code from formStorage
|
|
procedure TfrObject.RestoreProperty(const Prop, aValue: String; aObj : TPersistent=nil);
|
|
Var PropInfo : PPropInfo;
|
|
Obj : TObject;
|
|
begin
|
|
Try
|
|
if not Assigned(aObj) then
|
|
aObj:=Self;
|
|
|
|
PropInfo:=GetPropInfo(aObj,Prop);
|
|
if Assigned(PropInfo) then
|
|
begin
|
|
Case PropInfo^.PropType^.Kind of
|
|
tkChar,tkAString,tkWString,
|
|
tkSString,tkLString : SetStrProp(aObj,Prop,aValue);
|
|
tkBool,tkInt64,tkQWord,
|
|
tkInteger : begin
|
|
if PropInfo^.PropType^.Name='TGraphicsColor' then
|
|
SetOrdProp(aObj,PropInfo,StringToColor(aValue))
|
|
else
|
|
SetOrdProp(aObj,PropInfo,StrToInt(aValue))
|
|
end;
|
|
tkSet : SetSetProp(aObj,Prop,aValue);
|
|
tkFloat : begin
|
|
lrNormalizeLocaleFloats(true);
|
|
SetFloatProp(aObj,Prop,StrToFloat(aValue));
|
|
lrNormalizeLocaleFloats(false);
|
|
end;
|
|
tkEnumeration : SetEnumProp(aObj,Prop,aValue);
|
|
tkClass : Begin
|
|
Obj:=GetObjectProp(aObj,Prop);
|
|
if Obj Is TStrings then
|
|
TStrings(Obj).CommaText:=aValue;
|
|
end;
|
|
end;
|
|
end;
|
|
Except
|
|
End;
|
|
end;
|
|
|
|
constructor TfrObject.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create;
|
|
OwnerPage:=AOwnerPage;
|
|
fUpdate:=0;
|
|
BaseName:='LRObj';
|
|
fVisible:=True;
|
|
fMemo:=TfrMemoStrings.Create;
|
|
fScript:=TfrScriptStrings.Create;
|
|
FDesignOptions:=[];
|
|
end;
|
|
|
|
destructor TfrObject.Destroy;
|
|
begin
|
|
fmemo.Free;
|
|
fScript.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TfrObject.Assign(From: TfrView);
|
|
begin
|
|
x := From.x;
|
|
y := From.y;
|
|
dx := From.dx;
|
|
dy := From.dy;
|
|
|
|
Memo.Assign(From.Memo);
|
|
Script.Assign(From.Script);
|
|
Visible:=From.Visible;
|
|
end;
|
|
|
|
procedure TfrObject.BeginUpdate;
|
|
begin
|
|
Inc(fUpdate)
|
|
end;
|
|
|
|
procedure TfrObject.EndUpdate;
|
|
begin
|
|
if fUpdate>0 then
|
|
Dec(fUpdate)
|
|
end;
|
|
|
|
procedure TfrObject.CreateUniqueName;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
fName := '';
|
|
if Assigned(CurReport) then
|
|
begin
|
|
i:=1;
|
|
while Assigned(CurReport.FindObject(BaseName + IntToStr(i))) do
|
|
inc(i);
|
|
Name := BaseName + IntToStr(i);
|
|
end
|
|
else
|
|
Name := BaseName + '1';
|
|
end;
|
|
|
|
procedure TfrObject.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
//ClassName not read here.
|
|
Name:=XML.GetValue(Path+'Name/Value','');
|
|
if Name='' then
|
|
CreateUniqueName;
|
|
|
|
Visible:=XML.GetValue(Path+'Visible/Value'{%H-}, true);
|
|
end;
|
|
|
|
procedure TfrObject.SaveToXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
XML.SetValue(Path+'Name/Value', GetSaveProperty('Name'));
|
|
XML.SetValue(Path+'ClassName/Value', self.Classname);
|
|
|
|
XML.SetValue(Path+'Visible/Value', Visible);
|
|
end;
|
|
|
|
{ TfrRect }
|
|
|
|
function TfrRect.GetRect: TRect;
|
|
begin
|
|
Result:=Rect(Left,Top,Right,Bottom);
|
|
end;
|
|
|
|
procedure TfrRect.SetRect(const AValue: TRect);
|
|
begin
|
|
fLeft:=aValue.Left;
|
|
fRight:=aValue.Right;
|
|
fBottom:=aValue.Bottom;
|
|
fTop:=aValue.Top;
|
|
end;
|
|
|
|
{ TfrPageReport }
|
|
|
|
procedure TfrPageReport.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
Rc : TRect;
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
|
|
|
|
pgSize := XML.GetValue(Path+'PgSize/Value'{%H-}, 0); // TODO chk
|
|
rc.left := XML.GetValue(Path+'Margins/left/Value'{%H-}, 0); // TODO chk
|
|
rc.top := XML.GetValue(Path+'Margins/Top/Value'{%H-}, 0); // TODO chk
|
|
rc.Right := XML.GetValue(Path+'Margins/Right/Value'{%H-}, 0); // TODO chk
|
|
rc.Bottom := XML.GetValue(Path+'Margins/Bottom/Value'{%H-}, 0); // TODO chk
|
|
Margins.AsRect := rc;
|
|
RestoreProperty('Orientation',XML.GetValue(Path+'Orientation/Value',''));
|
|
|
|
UseMargins := XML.GetValue(Path+'UseMargins/Value'{%H-}, True); // TODO chk
|
|
PrintToPrevPage := XML.GetValue(Path+'PrintToPrevPage/Value'{%H-}, True); // TODO chk
|
|
ColCount := XML.GetValue(Path+'ColCount/Value'{%H-}, 1); // TODO chk
|
|
ColGap := XML.GetValue(Path+'ColGap/Value'{%H-}, 0);
|
|
RestoreProperty('LayoutOrder',XML.GetValue(Path+'LayoutOrder/Value','loColumns'));
|
|
ChangePaper(pgSize, Width, Height, Orientation);
|
|
end;
|
|
|
|
procedure TfrPageReport.SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
var
|
|
Rc : TRect;
|
|
begin
|
|
inherited SavetoXML(XML, Path);
|
|
|
|
Rc:=Margins.AsRect;
|
|
XML.SetValue(Path+'PgSize/Value'{%H-}, PgSize);
|
|
XML.SetValue(Path+'Margins/left/Value'{%H-}, Rc.Left);
|
|
XML.SetValue(Path+'Margins/Top/Value'{%H-}, Rc.Top);
|
|
XML.SetValue(Path+'Margins/Right/Value'{%H-}, Rc. Right);
|
|
XML.SetValue(Path+'Margins/Bottom/Value'{%H-}, Rc.Bottom);
|
|
XML.SetValue(Path+'Orientation/Value', GetSaveProperty('Orientation'));
|
|
XML.SetValue(Path+'UseMargins/Value'{%H-}, UseMargins);
|
|
XML.SetValue(Path+'PrintToPrevPage/Value'{%H-}, PrintToPrevPage);
|
|
XML.SetValue(Path+'ColCount/Value'{%H-}, ColCount);
|
|
XML.SetValue(Path+'ColGap/Value'{%H-}, ColGap);
|
|
XML.SetValue(Path+'LayoutOrder/Value', GetSaveProperty('LayoutOrder'));
|
|
end;
|
|
|
|
constructor TfrPageReport.CreatePage;
|
|
begin
|
|
self.Create(prn.DefaultPageSize, 0, 0, poPortrait);
|
|
end;
|
|
|
|
{ TfrPageDialog }
|
|
|
|
procedure TfrPageDialog.EditFormDestroy(Sender: TObject);
|
|
begin
|
|
fForm:=nil;
|
|
end;
|
|
|
|
function TfrPageDialog.GetCaption: string;
|
|
begin
|
|
Result:=FForm.Caption;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetCaption(AValue: string);
|
|
begin
|
|
FForm.Caption:=AValue;
|
|
end;
|
|
|
|
procedure TfrPageDialog.UpdateControlPosition;
|
|
begin
|
|
FForm.Left:=Left;
|
|
FForm.Top:=Top;
|
|
FForm.Width:=Width;
|
|
FForm.Height:=Height - 20;
|
|
FForm.Position:=poScreenCenter;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetName(const AValue: string);
|
|
var
|
|
S:string;
|
|
i:integer;
|
|
F:TComponent;
|
|
begin
|
|
inherited SetName(AValue);
|
|
S:=AValue;
|
|
F:=Application.FindComponent(S);
|
|
if Assigned(F) and (F<>FForm) then
|
|
begin
|
|
i:=1;
|
|
while Assigned(Application.FindComponent(AValue + IntToStr(i))) do inc(i);
|
|
S:=AValue + IntToStr(i);
|
|
end;
|
|
FForm.Name:=S;
|
|
end;
|
|
|
|
procedure TfrPageDialog.PrepareObjects;
|
|
begin
|
|
//Do nothing
|
|
end;
|
|
|
|
procedure TfrPageDialog.InitReport;
|
|
var
|
|
i:integer;
|
|
P:TfrControl;
|
|
begin
|
|
if not fVisible then
|
|
exit;
|
|
fHasVisibleControls:=False;
|
|
for i:=0 to Objects.Count - 1 do
|
|
begin
|
|
P:=TfrControl(Objects[i]);
|
|
if not (P is TfrNonVisualControl) then
|
|
begin
|
|
fHasVisibleControls:=true;
|
|
P.AttachToParent;
|
|
P.UpdateControlPosition;
|
|
end;
|
|
end;
|
|
|
|
ExecScript;
|
|
|
|
if fHasVisibleControls then
|
|
begin
|
|
UpdateControlPosition;
|
|
if FForm.ShowModal <> mrOk then
|
|
CurReport.Terminated:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetLeft(AValue: Integer);
|
|
begin
|
|
inherited SetLeft(AValue);
|
|
FForm.Left:=AValue;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetTop(AValue: Integer);
|
|
begin
|
|
inherited SetTop(AValue);
|
|
FForm.Top:=AValue;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetWidth(AValue: Integer);
|
|
begin
|
|
inherited SetWidth(AValue);
|
|
FForm.Width:=AValue;
|
|
end;
|
|
|
|
procedure TfrPageDialog.SetHeight(AValue: Integer);
|
|
begin
|
|
inherited SetHeight(AValue);
|
|
FForm.Height:=AValue;
|
|
end;
|
|
|
|
procedure TfrPageDialog.ExecScript;
|
|
var
|
|
FSavePage:TfrPage;
|
|
CmdList, ErrorList:TStringList;
|
|
begin
|
|
if DocMode = dmPrinting then
|
|
begin
|
|
FSavePage:=CurPage;
|
|
|
|
CmdList:=TStringList.Create;
|
|
ErrorList:=TStringList.Create;
|
|
try
|
|
CurView := nil;
|
|
CurPage := Self;
|
|
frInterpretator.PrepareScript(Script, CmdList, ErrorList);
|
|
frInterpretator.DoScript(CmdList);
|
|
finally
|
|
CurPage:=FSavePage;
|
|
FreeAndNil(CmdList);
|
|
FreeAndNil(ErrorList);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
constructor TfrPageDialog.Create(AOwnerPage: TfrPage);
|
|
begin
|
|
inherited Create(AOwnerPage);
|
|
|
|
fForm :=TfrDialogForm.CreateNew(Application);
|
|
fForm.OnDestroy:=@EditFormDestroy;
|
|
BaseName:='Dialog';
|
|
|
|
Width :=400;
|
|
Height:=250;
|
|
PageType:=ptDialog;
|
|
end;
|
|
|
|
destructor TfrPageDialog.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
if Assigned(fForm) then
|
|
begin
|
|
fForm.OnDestroy:=nil;
|
|
FreeAndNil(fForm);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrPageDialog.LoadFromXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited LoadFromXML(XML, Path);
|
|
Caption:=XML.GetValue(Path+'Caption/Value', '');
|
|
end;
|
|
|
|
procedure TfrPageDialog.SavetoXML(XML: TLrXMLConfig; const Path: String);
|
|
begin
|
|
inherited SavetoXML(XML, Path);
|
|
XML.SetValue(Path+'Caption/Value', Caption);
|
|
end;
|
|
|
|
{ TLrXMLConfig }
|
|
|
|
procedure TLrXMLConfig.LoadFromStream(const Stream: TStream);
|
|
begin
|
|
|
|
Flush;
|
|
FreeAndNil(Doc);
|
|
|
|
if csLoading in ComponentState then
|
|
exit;
|
|
|
|
if assigned(Stream) and not StartEmpty then
|
|
ReadXMLFile(Doc, Stream);
|
|
|
|
if not Assigned(Doc) then
|
|
Doc := TXMLDocument.Create;
|
|
|
|
if not Assigned(Doc.DocumentElement) then
|
|
Doc.AppendChild(Doc.CreateElement(RootName))
|
|
else
|
|
if Doc.DocumentElement.NodeName <> RootName then
|
|
raise EXMLConfigError.Create(SWrongRootName);
|
|
end;
|
|
|
|
procedure TLrXMLConfig.SaveToStream(const Stream: TStream);
|
|
begin
|
|
WriteXMLFile(Doc, Stream);
|
|
Flush;
|
|
end;
|
|
|
|
procedure TLrXMLConfig.SetValue(const APath: string; const AValue: string);
|
|
begin
|
|
inherited SetValue(UTF8Decode(APath), UTF8Decode(AValue));
|
|
end;
|
|
|
|
function TLrXMLConfig.GetValue(const APath: string; const ADefault: string
|
|
): string;
|
|
var
|
|
wValue: widestring;
|
|
begin
|
|
if frUnWrapRead then
|
|
result := {%H-}inherited GetValue(APath, ADefault{%H-})
|
|
else
|
|
begin
|
|
result := UTF16ToUTF8(inherited GetValue(APath, ADefault));
|
|
{ WValue := inherited GetValue(UTF8Decode(APath), UTF8Decode(ADefault));
|
|
Result := UTF8Encode(WValue);}
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
DoInit;
|
|
|
|
finalization
|
|
DoExit;
|
|
|
|
end.
|
|
|