lazarus/components/lazreport/source/lr_class.pas

13499 lines
351 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, strutils, DateUtils, {$IFDEF UNIX}CLocale,{$ENDIF}
Classes, TypInfo, MaskUtils, Variants, DB, DOM, XMLWrite, XMLRead, XMLConf,
Controls, Forms, Dialogs, Menus, Graphics, LCLProc, LCLType, LCLIntf,
Printers, osPrinters,
// LazUtils
LazFileUtils, LazUTF8, LazUTF8Classes,
// IDEIntf
PropEdits,
// LazReport
LR_View, LR_Pars, LR_Intrp, LR_DSet, LR_DBSet, LR_DBRel, LR_Const, DbCtrls;
const
lrMaxBandsInReport = 256; //temp fix. in future need remove this limit
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;
flBandPrintChildIfNotVisible = $100;
flBandKeepChild = $200;
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, btChild, 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,
roDontUpgradePreparedReport, // on saving an old prepared report don't update to current version
roSaveAndRestoreBookmarks, // try to save and later restore dataset bookmarks on building report
roPageHeaderBeforeReportTitle, // PageHeader band is printed before ReportTitle band
roDisableCancelBuild // Disable cancel button in build progress form
);
TfrReportOptions = set of TfrReportOption;
TfrObjectType = (otlReportView, otlUIControl);
TlrDesignOption = (doUndoDisable, doChildComponent);
TlrDesignOptions = set of TlrDesignOption;
TlrRestriction = (lrrDontModify, lrrDontSize, lrrDontMove, lrrDontDelete);
TlrRestrictions = set of TlrRestriction;
TfrObject = class;
TfrView = class;
TfrBand = class;
TfrPage = class;
TfrReport = class;
TfrExportFilter = class;
TfrMemoStrings = class;
TfrScriptStrings = 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;
TPrintReportEvent = procedure(Sender: TfrReport) of object;
TFormPageBookmarksEvent = procedure(Sender: TfrReport; Backup: boolean) of object;
TExecScriptEvent = procedure(frObject:TfrObject; AScript:TfrScriptStrings) 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);
ELazReportException = class(Exception);
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;
FOnExecScriptEvent : TExecScriptEvent;
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;
procedure AfterCreate;virtual;
function ExecMetod(const {%H-}AName: String; {%H-}p1, {%H-}p2, {%H-}p3: Variant; var {%H-}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;
procedure InternalExecScript;virtual;
public
x, y, dx, dy: Integer;
constructor Create(AOwnerPage:TfrPage); virtual;
destructor Destroy; override;
{ TODO : check this!! }
procedure AssignTo(Dest: TPersistent); override;
procedure Assign(Source: TPersistent); override; //virtual; overload;
procedure BeginUpdate;virtual;
procedure EndUpdate;virtual;
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;
FRestrictions: TlrRestrictions;
fStreamMode: TfrStreamMode;
fFormat : Integer;
fFormatStr : string;
fFrameTyp : word;
FTag: string;
FURLInfo: string;
FFindHighlight : boolean;
FGapX:Integer;
FGapY:Integer;
function GetDataField: string;
function GetLeft: Double;
function GetStretched: Boolean;
function GetTop: Double;
procedure P1Click(Sender: TObject);
procedure SetDataField(AValue: string);
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;
InternalGapX, InternalGapY: 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 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;
procedure PrepareObject;virtual;
property DataField : string read GetDataField write SetDataField;
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(Source: TPersistent); 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;
property Restrictions:TlrRestrictions read FRestrictions write FRestrictions;
property FindHighlight : boolean read FFindHighlight write FFindHighlight;
property GapX:Integer read FGapX write FGapX;
property GapY:Integer read FGapY write FGapY;
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;
{ TfrCustomMemoView }
TfrCustomMemoView = class(TfrStretcheable)
private
FCursor: TCursor;
FDetailReport: string;
fFont : TFont;
fLastValue : TStringList;
FOnClick: TfrScriptStrings;
FOnMouseEnter: TfrScriptStrings;
FOnMouseLeave: TfrScriptStrings;
FParagraphGap: integer;
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 SetCursor(AValue: TCursor);
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 SetOnClick(AValue: TfrScriptStrings);
procedure SetOnMouseEnter(AValue: TfrScriptStrings);
procedure SetOnMouseLeave(AValue: TfrScriptStrings);
procedure SetWordBreak(AValue: Boolean);
procedure SetWordWrap(const AValue: Boolean);
protected
Streaming: Boolean;
TextHeight: Integer;
CurStrNo: Integer;
Exporting: Boolean;
FLineSpacing: Integer;
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;
procedure DoRunScript(AScript: TfrScriptStrings);
procedure DoOnClick;
procedure DoMouseEnter;
procedure DoMouseLeave;
property IsLastValueSet: boolean read GetIsLastValueSet write SetIsLastValueSet;
public
Adjust: Integer; // bit format xxxLLRAA: LL=Layout, R=Rotated, AA=Alignment
Highlight: TfrHighlightAttr;
HighlightStr: String;
CharacterSpacing: Integer;
LastLine: boolean; // are we painting/exporting the last line?
FirstLine: boolean;
constructor Create(AOwnerPage:TfrPage); override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); 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;
property Cursor: TCursor read FCursor write SetCursor default crDefault;
property DetailReport : string read FDetailReport write FDetailReport;
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 OnClick : TfrScriptStrings read FOnClick write SetOnClick;
property OnMouseEnter : TfrScriptStrings read FOnMouseEnter write SetOnMouseEnter;
property OnMouseLeave : TfrScriptStrings read FOnMouseLeave write SetOnMouseLeave;
property ParagraphGap : integer read FParagraphGap write FParagraphGap;
property LineSpacing : integer read FLineSpacing write FLineSpacing;
end;
TfrMemoView = class(TfrCustomMemoView)
published
property Cursor;
property DetailReport;
property Font;
property Alignment;
property Layout;
property Angle;
property WordBreak;
property WordWrap;
property AutoSize;
property HideDuplicates;
property HideZeroValues;
property FillColor;
property Memo;
property Script;
property Frames;
property FrameColor;
property FrameStyle;
property FrameWidth;
property Format;
property FormatStr;
property Restrictions;
property ParagraphGap;
property OnClick;
property OnMouseEnter;
property OnMouseLeave;
property LineSpacing;
property GapX;
property GapY;
end;
{ TfrBandView }
TfrBandView = class(TfrView)
private
fDataSetStr : String;
fBandType : TfrBandType;
fCondition : String;
fChild : 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);
procedure P7Click(Sender: TObject);
procedure P8Click(Sender: TObject);
function GetTitleRect: TRect;
function TitleSize: Integer;
procedure CalcTitleSize;
procedure FixPrintChildIfNotVisible;
protected
procedure SetHeight(const AValue: Double); override;
procedure SetVisible(AValue: Boolean);override;
public
constructor Create(AOwnerPage:TfrPage); override;
procedure Assign(Source: TPersistent); 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 Child: String read fChild write fChild;
property BandType: TfrBandType read fBandType write fBandType;
property Script;
property Stretched;
property Restrictions;
end;
{ TfrSubReportView }
TfrSubReportView = class(TfrView)
private
FSubPageIndex: Integer; //temp var for find page on load
FSubPage : TfrPage;
protected
procedure AfterLoad;override;
public
//SubPage: Integer;
constructor Create(AOwnerPage:TfrPage); override;
procedure Assign(Source: TPersistent); 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;
property SubPage : TfrPage read FSubPage write FSubPage;
published
property Restrictions;
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(Source: TPersistent); 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 DataField;
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;
property Restrictions;
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;
property Restrictions;
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;
EOFArr: Array[0..lrMaxBandsInReport - 1] of Boolean;
Positions: Array[TfrDatasetPosition] of Integer;
LastGroupValue: Variant;
HeaderBand, FooterBand, LastBand: TfrBand;
ChildBand: 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
EOFReached: Boolean;
MaxDY: Integer;
Typ: TfrBandType;
PrintIfSubsetEmpty, NewPageAfter, Stretched, PageBreak: Boolean;
PrintChildIfNotVisible: 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
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;
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;
procedure DrawPageFooters;
function BandExists(b: TfrBand): Boolean;
function GetPageIndex: integer;
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
procedure SetPageIndex(AValue: integer);
procedure ShowBand(b: TfrBand);
protected
List : TFpList;
Bands : Array[TfrBandType] of TfrBand;
Mode : TfrPageMode;
PlayFrom : Integer;
function PlayRecList: Boolean;
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;
property PageIndex:integer read GetPageIndex write SetPageIndex;
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;
FCaption : string;
procedure EditFormDestroy(Sender: TObject);
function GetCaption: string;
procedure SetCaption(AValue: string);
procedure UpdateControlPosition;
protected
procedure PrepareObjects; override;
procedure InitReport; override;
procedure DoneReport; 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;
function Add(const aClassName : string='TfrPageReport'):TfrPage;
procedure Delete(Index: Integer);
procedure Move(OldIndex, NewIndex: 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);
procedure ResetFindData;
function DoMouseClick(Index: Integer; pt: TPoint; var AInfo: String): Boolean;
function DoMouseMove(Index: Integer; pt: TPoint; var Cursor: TCursor; var AInfo: String): TfrView;
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);
procedure UpgradeToCurrentVersion;
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;
function Setup:boolean; 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;
procedure AfterExport; 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;
{ TlrDetailReport }
TlrDetailReport = class
private
FReportBody: TStream;
FReportDescription: string;
FReportName: string;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String);
procedure SaveToXML(XML: TLrXMLConfig; const Path: String);
procedure SaveToStream(Stream: TStream);
procedure LoadFromStream(Stream: TStream);
property ReportDescription:string read FReportDescription write FReportDescription;
property ReportBody:TStream read FReportBody;
property ReportName:string read FReportName write FReportName;
end;
{ TlrDetailReports }
TlrDetailReports = class
private
FList:TFPList;
function GetCount: integer;
function GetItems(AReportName: string): TlrDetailReport;
procedure Clear;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromStream(Stream: TStream);
procedure LoadFromXML(XML: TLrXMLConfig; const Path: String);
procedure SaveToStream(Stream: TStream);
procedure SaveToXML(XML: TLrXMLConfig; const Path: String);
function GetItem(AItem:integer): TlrDetailReport;
function Add(AReportName: string):TlrDetailReport;
property Items[AReportName:string]:TlrDetailReport read GetItems; default;
property Count:integer read GetCount;
end;
TfrDataType = (dtDataSet,dtDataSource);
{ TfrReport }
TfrReport = class(TComponent)
private
FDataType: TfrDataType;
FDefaultCollate: boolean;
FDetailReports: TlrDetailReports;
FOnAfterPrint: TPrintReportEvent;
FOnBeforePrint: TPrintReportEvent;
FOnDBImageRead: TOnDBImageRead;
FDefaultCopies: Integer;
FMouseOverObject: TMouseOverObjectEvent;
FObjectClick: TObjectClickEvent;
FOnExportFilterSetup: TExportFilterSetup;
fOnFormPageBookmarks: TFormPageBookmarksEvent;
FPages: TfrPages;
FEMFPages: TfrEMFPages;
FRebuildPrinter: boolean;
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;
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 SetReportOptions(AValue: TfrReportOptions);
procedure SetScript(AValue: TfrScriptStrings);
procedure SetVars(Value: TStrings);
procedure ClearAttribs;
function FindObjectByName(AName:string):TfrObject;
procedure ExecScript;
procedure CheckFileExists(FName: string);
protected
function DoObjectClick(AObj:TfrView):boolean;
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 FormatValue(V: Variant; AFormat: Integer; const AFormatStr: String): String;
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;
function ExportTo(FilterClass: TfrExportFilterClass; aFileName: String):Boolean;
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;
property DetailReports:TlrDetailReports read FDetailReports;
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 SetReportOptions;
property Preview: TfrPreview read FPreview write FPreview;
property PreviewButtons: TfrPreviewButtons read FPreviewButtons write FPreviewButtons;
property RebuildPrinter: boolean read FRebuildPrinter write FRebuildPrinter default False;
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;
property OnBeforePrint: TPrintReportEvent read FOnBeforePrint write FOnBeforePrint;
property OnAfterPrint: TPrintReportEvent read FOnAfterPrint write FOnAfterPrint;
// 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;
property OnFormPageBookmarks: TFormPageBookmarksEvent read fOnFormPageBookmarks write fOnFormPageBookmarks;
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;
TlrObjEditorProc = function(lrObj: TfrView) : boolean;
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; EditorProc : TlrObjEditorProc = nil);
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);
function FindObjectProps(AObjStr:string; out frObj:TfrObject; out PropName:string;
out PropIndex:Integer):PPropInfo;
const
lrTemplatePath = 'LazReportTemplate/';
frCurrentVersion = 31;
// 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
// version 2.7: lazreport: added to binary stream FOnClick, FOnMouseEnter, FOnMouseLeave, FCursor property on TfrMemoView
// version 2.8: lazreport: added support for child bands
// version 2.9: lazreport: added support LineSpacing and GapX, GapY
// version 3.0: lazreport: decoupled flHideZeros and flBandPrintChildIfNotVisible
// version 3.1: lazreport: Save Restrictions to stream
frSpecCount = 9;
frSpecFuncs: Array[0..frSpecCount - 1] of String = ('PAGE#', '',
'DATE', 'TIME', 'LINE#', 'LINETHROUGH#', 'COLUMN#', 'CURRENT#', 'TOTALPAGES');
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;
EditorProc : TlrObjEditorProc;
end;
{ TExportFilterItem }
TExportFilterItem = class
private
FClassRef: TfrExportFilterClass;
FEnabled: boolean;
FFilterDesc: String;
FFilterExt: String;
public
constructor Create;
property ClassRef: TfrExportFilterClass read FClassRef;
property FilterDesc: String read FFilterDesc;
property FilterExt: String read FFilterExt;
property Enabled:boolean read FEnabled write FEnabled;
end;
{ TExportFilters }
TExportFilters = class
private
FList:TFPList;
function GetCount: integer;
procedure Clear;
function GetItems(AItem: Integer): TExportFilterItem;
public
constructor Create;
destructor Destroy; override;
procedure RegisterFilter(AClassRef: TfrExportFilterClass; const AFilterDesc, AFilterExt: String);
procedure DisableFilter(AFilterExt: String);
procedure EnableFilter(AFilterExt: String);
function FindFilter(AFilterExt: String):TExportFilterItem;
function FilterIndex(AClassRef: TfrExportFilterClass; AFilterExt:string): Integer;
property Count:integer read GetCount;
property Items[AItem:Integer]:TExportFilterItem read GetItems;default;
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;
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
LRE_OLDV28_FRF_READ: Boolean = False; // read frf v28 (lazarus 1.4.4) reports, bug 29966
// variables used through report building
TempBmp: TBitmap; // temporary bitmap used by TfrMemoView
function ExportFilters:TExportFilters;
implementation
uses
LR_Fmted, LR_Prntr, LR_Progr, LR_Utils
{$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
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;
FHyp: THyphen = nil;
PrevY, PrevBottomY, ColumnXAdjust: Integer;
AppendPage, WasPF: Boolean;
CompositeMode: Boolean;
MaxTitleSize: Integer = 0;
FExportFilters:TExportFilters = nil;
{-----------------------------------------------------------------------------}
const
PropCount = 6;
PropNames: Array[0..PropCount - 1] of String =
('Text','FontName', 'FontSize', 'FontStyle', 'FontColor', 'Adjust');
{$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
if View=nil then
result := 'View is nil'
else
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 IsCustomProp(const aPropName: string; out aIndex: Integer): boolean;
var
i: Integer;
begin
result := false;
aIndex := -1;
for i:=0 to High(PropNames) do
begin
if SameText(aPropName, PropNames[i]) then
begin
aIndex := i;
result := true;
break;
end;
end;
end;
function FindObjectProps(AObjStr:string; out frObj:TfrObject; out PropName:string;
out PropIndex: Integer):PPropInfo;
var
FPageName:string;
FObjName:string;
P:integer;
FPage:TfrPage;
begin
Result:=nil;
frObj:=nil;
PropName:='';
PropIndex:=-1;
P:=Pos('.', AObjStr);
if (P = 0) then
begin
if Assigned(CurView) then
begin
Result:=GetPropInfo(CurView, AObjStr); //Retreive property informations
if Assigned(Result) or IsCustomProp(aObjStr, PropIndex) then
begin
frObj:=CurView;
PropName:=AObjStr;
end;
end;
end
else
begin
FPageName:='';
FObjName:='';
FObjName:=Copy2SymbDel(AObjStr, '.');
P:=Pos('.', AObjStr);
if P <> 0 then
begin
FPageName:=FObjName;
FObjName:=Copy2SymbDel(AObjStr, '.');
end;
PropName:=AObjStr;
if FPageName<>'' then
begin
FPage:=CurReport.Pages.PageByName(FPageName);
if not Assigned(FPage) then
exit;
end
else
begin
FPage:=CurPage;
end;
if Assigned(FPage) then
frObj := FPage.FindRTObject(FObjName);
if not Assigned(frObj) then
frObj := CurReport.FindObject(FObjName);
if Assigned(frObj) then
begin
Result:=GetPropInfo(frObj, PropName); //Retreive property informations
if not Assigned(Result) then
IsCustomProp(PropName, PropIndex);
end;
end;
end;
function ExportFilters: TExportFilters;
begin
if not Assigned(FExportFilters) then
FExportFilters:=TExportFilters.Create;
Result:=FExportFilters;
end;
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[btChild] := sBand22;
frBandNames[btNone] := sBand23;
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 CompareText(frAddIns[i].ClassRef.ClassName, ClassName)=0 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;
EditorProc: TlrObjEditorProc = nil);
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;
frAddIns[frAddInsCount].EditorProc:= EditorProc;
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);
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;
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
ExportFilters.RegisterFilter(ClassRef, FilterDesc, FilterExt);
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 CurPage is TfrPageReport then
begin
FRDataset := nil;
if CurBand <> nil then
begin
case CurBand.Typ of
btMasterData, btReportSummary, btMasterFooter,
btGroupHeader, btGroupFooter:
if Assigned(CurPage.Bands[btMasterData]) then
FRDataset := CurPage.Bands[btMasterData].DataSet
else
FRDataset := nil;
btDetailData, btDetailFooter:
if Assigned(CurPage.Bands[btDetailData]) then
FRDataset := CurPage.Bands[btDetailData].DataSet
else
FRDataset := nil;
btSubDetailData, btSubDetailFooter:
if Assigned(CurPage.Bands[btSubDetailData]) then
FRDataset := CurPage.Bands[btSubDetailData].DataSet
else
FRDataset := nil;
btCrossData, btCrossFooter:
if Assigned(CurPage.Bands[btCrossData]) then
FRDataset := CurPage.Bands[btCrossData].DataSet
else
FRDataset := nil;
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;
{ TExportFilterItem }
constructor TExportFilterItem.Create;
begin
inherited Create;
FEnabled:=true;
end;
{ TExportFilters }
function TExportFilters.GetCount: integer;
begin
Result:=FList.Count;
end;
procedure TExportFilters.Clear;
var
i: Integer;
begin
for i:=0 to FList.Count-1 do
TExportFilterItem(FList[i]).Free;
FList.Clear;
end;
function TExportFilters.GetItems(AItem: Integer): TExportFilterItem;
begin
Result:=TExportFilterItem(FList[AItem]);
end;
constructor TExportFilters.Create;
begin
inherited Create;
FList:=TFPList.Create;
end;
destructor TExportFilters.Destroy;
begin
Clear;
FList.Free;
inherited Destroy;
end;
procedure TExportFilters.RegisterFilter(AClassRef: TfrExportFilterClass;
const AFilterDesc, AFilterExt: String);
var
F: TExportFilterItem;
begin
if FilterIndex(AClassRef, AFilterExt) > -1 then exit;
F:=TExportFilterItem.Create;
F.FClassRef:=AClassRef;
F.FFilterExt:=AFilterExt;
F.FFilterDesc:=AFilterDesc;
FList.Add(F);
end;
procedure TExportFilters.DisableFilter(AFilterExt: String);
var
F: TExportFilterItem;
begin
F:=FindFilter(AFilterExt);
if Assigned(F) then
F.FEnabled:=true;
end;
procedure TExportFilters.EnableFilter(AFilterExt: String);
var
F: TExportFilterItem;
begin
F:=FindFilter(AFilterExt);
if Assigned(F) then
F.FEnabled:=false;
end;
function TExportFilters.FindFilter(AFilterExt: String): TExportFilterItem;
var
i: Integer;
begin
Result:=nil;
AFilterExt:=UTF8UpperCase(AFilterExt);
for i:=0 to FList.Count-1 do
if UTF8UpperCase(TExportFilterItem(FList[i]).FFilterExt) = AFilterExt then
begin
Result:=TExportFilterItem(FList[i]);
exit;
end;
end;
function TExportFilters.FilterIndex(AClassRef: TfrExportFilterClass;
AFilterExt: string): Integer;
var
i: Integer;
begin
Result:=-1;
AFilterExt:=UTF8UpperCase(AFilterExt);
for i:=0 to FList.Count-1 do
if (TExportFilterItem(FList[i]).FClassRef = AClassRef) and
(UTF8UpperCase(TExportFilterItem(FList[i]).FilterExt) = AFilterExt) then
begin
Result:=i;
exit;
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 := UTF8Trim(Text, [u8tKeepStart]);
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;
}
{ TlrDetailReports }
function TlrDetailReports.GetItems(AReportName: string): TlrDetailReport;
var
i: Integer;
begin
Result:=nil;
if Trim(AReportName) = '' then exit;
for i:=0 to FList.Count - 1 do
if TlrDetailReport(FList[i]).FReportName = AReportName then
begin;
Result:=TlrDetailReport(FList[i]);
exit
end;
end;
function TlrDetailReports.GetCount: integer;
begin
Result:=FList.Count;
end;
function TlrDetailReports.Add(AReportName: string): TlrDetailReport;
begin
if AReportName <> '' then
Result:=GetItems(AReportName)
else
Result:=nil;
if not Assigned(Result) then
begin
Result:=TlrDetailReport.Create;
FList.Add(Result);
Result.FReportName:=AReportName;
end;
end;
procedure TlrDetailReports.Clear;
var
P:TlrDetailReport;
i: Integer;
begin
for i:=0 to FList.Count - 1 do
begin
P:=TlrDetailReport(FList[i]);
P.Free;
end;
FList.Clear;
end;
constructor TlrDetailReports.Create;
begin
inherited Create;
FList:=TFPList.Create;
end;
destructor TlrDetailReports.Destroy;
begin
Clear;
FreeAndNil(FList);
inherited Destroy;
end;
procedure TlrDetailReports.LoadFromStream(Stream: TStream);
var
Cnt, i: Integer;
P: TlrDetailReport;
begin
if Stream.Position = Stream.Size then exit;
Stream.Read(Cnt, SizeOf(Cnt));
for i:=0 to Cnt - 1 do
begin
P:=Add('');
P.LoadFromStream(Stream);
end;
end;
procedure TlrDetailReports.LoadFromXML(XML: TLrXMLConfig; const Path: String);
var
Cnt, i: Integer;
P:TlrDetailReport;
S:string;
begin
Cnt:=XML.GetValue(Path+'Count/Value', 0);
for i:=0 to Cnt - 1 do
begin
S:=XML.GetValue(Path+Format('Detail%d/', [i]) + 'ReportName/Value', '');
if S <> '' then
begin
P:=Add(S);
P.LoadFromXML(XML, Path + Format('Detail%d/', [i]));
end;
end;
end;
procedure TlrDetailReports.SaveToStream(Stream: TStream);
var
Cnt, i: Integer;
begin
Cnt:=Count;
Stream.Write(Cnt, SizeOf(Cnt));
for i:=0 to Cnt - 1 do
GetItem(i).SaveToStream(Stream);
end;
procedure TlrDetailReports.SaveToXML(XML: TLrXMLConfig; const Path: String);
var
i: Integer;
begin
XML.SetValue(Path+'Count/Value', Count);
for i:=0 to Count - 1 do
GetItem(i).SavetoXML(XML, Path+Format('Detail%d/', [i]));
end;
function TlrDetailReports.GetItem(AItem: integer): TlrDetailReport;
begin
Result:=TlrDetailReport(FList[AItem]);
end;
{ TlrDetailReport }
constructor TlrDetailReport.Create;
begin
inherited Create;
{$IF FPC_FULLVERSION >= 30101}
FReportBody:=TStringStream.CreateRaw('');
{$ELSE}
FReportBody:=TStringStream.Create('');
{$ENDIF}
end;
destructor TlrDetailReport.Destroy;
begin
FreeAndNil(FReportBody);
inherited Destroy;
end;
procedure TlrDetailReport.LoadFromXML(XML: TLrXMLConfig; const Path: String);
begin
FReportName:=XML.GetValue(Path+'ReportName/Value', '');
FReportDescription:=XML.GetValue(Path+'ReportDescription/Value', '');
FReportBody.Size:=0;
TStringStream(FReportBody).WriteString(XML.GetValue(Path+'ReportBody/Value', ''));
end;
procedure TlrDetailReport.SaveToXML(XML: TLrXMLConfig; const Path: String);
begin
XML.SetValue(Path+'ReportName/Value', FReportName);
XML.SetValue(Path+'ReportDescription/Value', FReportDescription);
XML.SetValue(Path+'ReportBody/Value', TStringStream(FReportBody).DataString);
end;
procedure TlrDetailReport.SaveToStream(Stream: TStream);
begin
frWriteString(Stream, FReportName);
frWriteString(Stream, FReportDescription);
frWriteString(Stream, TStringStream(FReportBody).DataString);
end;
procedure TlrDetailReport.LoadFromStream(Stream: TStream);
var
S: String;
begin
FReportName:=frReadString(Stream);
FReportDescription:=frReadString(Stream);
S:=frReadString(Stream);
TStringStream(FReportBody).Size:=0;
TStringStream(FReportBody).WriteString(S);
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 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(DefaultFormatSettings.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(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrView then
begin
fName := TfrView(Source).Name;
Typ := TfrView(Source).Typ;
Selected := TfrView(Source).Selected;
Flags := TfrView(Source).Flags;
fFrameWidth := TfrView(Source).FrameWidth;
fFrameColor := TfrView(Source).FrameColor;
fFrameStyle := TfrView(Source).FrameStyle;
FFillColor := TfrView(Source).FillColor;
fFormat := TfrView(Source).Format;
fFormatStr := TfrView(Source).FormatStr;
fVisible := TfrView(Source).Visible;
fFrames := TfrView(Source).Frames;
FTag := TfrView(Source).FTag;
FURLInfo := TfrView(Source).FURLInfo;
FRestrictions := TfrView(Source).FRestrictions;
FGapX:=TfrView(Source).FGapX;
FGapY:=TfrView(Source).FGapY;
end;
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;
InternalGapX := wx2 + 2 + FGapX;
InternalGapY := wy2 div 2 + 1 + FGapY;
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) then
if (FillColor = clNone) and (not FFindHighlight) then Exit;
if FFindHighlight then
fp := clSilver
else
begin
fp := FillColor;
if (DocMode = dmDesigning) and (fp = clNone) then
fp := clWhite;
end;
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);
InternalExecScript;
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 Stream.Position=%d',
[name,Ord(StreamMode),ClassName, Stream.Position]);
{$ENDIF}
with Stream do
begin
if (frVersion>27) or ((frVersion=27) and lrCanReadName(Stream)) or (StreamMode = smDesigning) then
begin
if frVersion >= 23 then
fName := 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;
if frVersion >= 29 then
begin
Stream.Read(FGapX, SizeOf(FGapX));
Stream.Read(FGapY, SizeOf(FGapX));
end;
if frVersion >= 30 then
begin
Stream.Read(FRestrictions, SizeOf(TlrRestrictions));
end;
end;
{$IFDEF DebugLR}
DebugLn('%s.TfrView.LoadFromStream end Position=%d',[name, Stream.Position]);
{$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)
else
Frames:=[];
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', '');
S:=XML.GetValue(Path+'Frames/Restrictions/Value','');
if S<>'' then
RestoreProperty('Restrictions',S);
FGapX:=XML.GetValue(Path+'Data/GapX/Value', 0);
FGapY:=XML.GetValue(Path+'Data/GapY/Value', 0);
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;
Stream.Write(FGapX, SizeOf(FGapX));
Stream.Write(FGapY, SizeOf(FGapX));
Stream.Write(FRestrictions, SizeOf(TlrRestrictions));
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);
if IsPublishedProp(self,'Restrictions') then
XML.SetValue(Path+'Frames/Restrictions/Value', GetSaveProperty('Restrictions'));
XML.SetValue(Path+'Data/GapX/Value', FGapX);
XML.SetValue(Path+'Data/GapY/Value', FGapY);
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.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;
procedure TfrView.SetDataField(AValue: string);
begin
if (AValue <> '') and (AValue[1]<>'[') then
AValue:='[' + AValue + ']';
if Memo.Count = 0 then
Memo.Add(AValue)
else
Memo[0]:=AValue;
end;
function TfrView.GetLeft: Double;
begin
if frDesigner<>nil then
result := frDesigner.PointsToUnits(x)
else
result := x;
end;
function TfrView.GetDataField: string;
begin
if Memo.Count>0 then
Result:=Memo[0]
else
Result:='';
if Result <> '' then
Result:=lrGetUnBrackedStr(Result);
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.PrepareObject;
begin
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 TfrCustomMemoView.Create(AOwnerPage: TfrPage);
begin
inherited Create(AOwnerPage);
fOnClick:=TfrScriptStrings.Create;
FCursor:=crDefault;
FDetailReport:='';
FOnMouseEnter:=TfrScriptStrings.Create;
FOnMouseLeave:=TfrScriptStrings.Create;
FFindHighlight:=false;
FParagraphGap:=0;
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 TfrCustomMemoView.Destroy;
begin
FFont.Free;
if FLastValue<>nil then
FLastValue.Free;
FreeAndNil(FOnMouseEnter);
FreeAndNil(FOnMouseLeave);
FreeAndNil(fOnClick);
inherited Destroy;
end;
procedure TfrCustomMemoView.SetFont(Value: TFont);
begin
BeforeChange;
fFont.Assign(Value);
AfterChange;
end;
procedure TfrCustomMemoView.SetHideDuplicates(const AValue: Boolean);
begin
if HideDuplicates<>AValue then
ModifyFlag(flHideDuplicates, AValue);
end;
procedure TfrCustomMemoView.SetHideZeroValues(AValue: Boolean);
begin
if WordBreak<>AValue then
ModifyFlag(flHideZeros, AValue);
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.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 TfrCustomMemoView.SetLayout(const AValue: TTextLayout);
begin
if Layout<>AValue then
begin
BeforeChange;
Adjust := (Adjust and %11100111) or (ord(AValue) shl 3);
AfterChange;
end;
end;
procedure TfrCustomMemoView.SetOnClick(AValue: TfrScriptStrings);
begin
BeforeChange;
fOnClick.Assign(AValue);
AfterChange;
end;
procedure TfrCustomMemoView.SetOnMouseEnter(AValue: TfrScriptStrings);
begin
BeforeChange;
FOnMouseEnter.Assign(AValue);
AfterChange;
end;
procedure TfrCustomMemoView.SetOnMouseLeave(AValue: TfrScriptStrings);
begin
BeforeChange;
FOnMouseLeave.Assign(AValue);
AfterChange;
end;
procedure TfrCustomMemoView.SetWordBreak(AValue: Boolean);
begin
if WordBreak<>AValue then
ModifyFlag(flWordBreak, AValue);
end;
procedure TfrCustomMemoView.SetWordWrap(const AValue: Boolean);
begin
if WordWrap<>AValue then
ModifyFlag(flWordWrap, AValue);
end;
procedure TfrCustomMemoView.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrCustomMemoView then
begin
FFont.Assign(TfrCustomMemoView(Source).Font);
Adjust := TfrCustomMemoView(Source).Adjust;
Highlight := TfrCustomMemoView(Source).Highlight;
HighlightStr := TfrCustomMemoView(Source).HighlightStr;
LineSpacing := TfrCustomMemoView(Source).LineSpacing;
FOnClick.Assign(TfrCustomMemoView(Source).FOnClick);
FOnMouseEnter.Assign(TfrCustomMemoView(Source).FOnMouseEnter);
FOnMouseLeave.Assign(TfrCustomMemoView(Source).FOnMouseLeave);
FDetailReport:=TfrCustomMemoView(Source).FDetailReport;
FCursor:=TfrCustomMemoView(Source).FCursor;
FParagraphGap:=TfrCustomMemoView(Source).FParagraphGap;
end;
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.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 TfrCustomMemoView.WrapMemo;
var
size, size1, maxwidth: Integer;
b: TWordBreaks;
WCanvas: TCanvas;
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);
if Angle=0 then
maxWidth := dx - InternalGapX - InternalGapX;
end;
procedure WrapLine(const s: String);
var
i, cur, beg, last, len: Integer;
WasBreak, CRLF, IsCR: Boolean;
ch: char;
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 := length(s);
while cur <= Len do
begin
Ch := s[cur];
// check for items with soft-breaks
IsCR := Ch=#13;
if IsCR then
begin
//handle composite newline
if (cur < length(s)) then
begin
ch := s[cur+1];
//dont increase char index if next char is LF (#10)
if s[cur+1]<>#10 then
Inc(Cur);
end;
end;
if Ch=#10 then
begin
OutLine(copy(s, beg, cur - beg) + #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(copy(s, beg, cur - beg + 1)) > 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 (ch in [' ', '.', ',', '-']) do
begin
Inc(i);
ch := s[i];
end;
// find word's break points using some simple hyphenator algorithm
// TODO: implement interface so users can use their own hyphenator
// algorithm
aWord := copy(s, last, i - last);
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(copy(s, beg, last - beg + Ord(b[i])) + '-') <= 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(copy(s, beg, last - beg) + '-');
end else
begin
// output the portion of word that fits maxwidth
OutLine(copy(s, beg, last - beg));
// if space was found, advance to next no space char
while (s[last] = ' ') and (last < Length(s)) do
Inc(last);
end;
beg := last;
end;
if Ch in [' ', '.', ',', '-'] then
last := cur;
Inc(cur);
end;
if beg <> cur then
OutLine(copy(s, beg, cur - beg + 1) + #1);
end;
end;
procedure OutMemo;
var
i: Integer;
begin
size := y + InternalGapY;
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
maxWidth := dx - InternalGapX - InternalGapX - FParagraphGap;
if (Flags and flWordWrap) <> 0 then
WrapLine(Memo1[i])
else
OutLine(Memo1[i] + #1);
end;
VHeight := size - y + InternalGapY;
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 + InternalGapX;
size1 := -WCanvas.Font.Height + LineSpacing;
maxwidth := dy - InternalGapY - InternalGapY;
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 + InternalGapX;
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 TfrCustomMemoView.ShowMemo;
var
DR : TRect;
SavX,SavY : Integer;
procedure OutMemo;
var
i: Integer;
curyf, thf, linespc: double;
FTmpFL:boolean;
function OutLine(st: String): Boolean;
var
{$IFDEF DebugLR}
aw: Integer;
{$ENDIF}
cond: boolean;
n, {nw, w, }curx, lasty: Integer;
lastyf: Double;
Ts: TTextStyle;
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]);
LastLine := true;
SetLength(St, n - 2);
if Length(St) > 0 then
begin
FTmpFL:=false;
if St[Length(St)] = #1 then
begin
FTmpFL:=true;
SetLength(St, Length(St) - 1);
end
else
LastLine := 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+InternalGapX;
Classes.taRightJustify: CurX :=x+dx-1-InternalGapX-Canvas.TextWidth(St);
Classes.taCenter : CurX :=x+InternalGapX+(dx-InternalGapX-InternalGapX-Canvas.TextWidth(St)) div 2;
end;
if not Exporting then
begin
if Justify and not LastLine then
begin
if FirstLine then
CanvasTextRectJustify(Canvas, DR, x+InternalGapX + FParagraphGap, x+dx-1-InternalGapX, round(CurYf), St, true)
else
CanvasTextRectJustify(Canvas, DR, x+InternalGapX, x+dx-1-InternalGapX, round(CurYf), St, true)
end
else
begin
if FirstLine then
Canvas.TextRect(DR, CurX + FParagraphGap, round(curYf), St)
else
Canvas.TextRect(DR, CurX, round(curYf), St);
end;
end
else
begin
if FirstLine then
CurReport.InternalOnExportText(X + FParagraphGap, round(curYf), St, Self)
else
CurReport.InternalOnExportText(X, round(curYf), St, Self);
end;
Inc(CurStrNo);
Result := False;
end
else
Result := True;
curyf := curyf + thf;
FirstLine:=FTmpFL;
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 + InternalGapY;
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;
FirstLine:=true;
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-InternalGapY;
Classes.taRightJustify: CurY :=y + InternalGapY + 1 + Canvas.TextWidth(str);
Classes.taCenter : CurY :=y + InternalGapY + (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 + InternalGapX;
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 TfrCustomMemoView.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 TfrCustomMemoView.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 TfrCustomMemoView.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
InternalExecScript;
//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 TfrCustomMemoView.ExportData;
begin
CurReport.InternalOnExportData(Self);
Exporting := True;
Draw(TempBmp.Canvas);
Exporting := False;
CurReport.InternalOnExported(Self);
end;
function TfrCustomMemoView.CalcHeight: Integer;
var
s: String;
CanExpandVar: Boolean;
OldFont: TFont;
OldFill: Integer;
begin
Result := 0;
DrawMode := drAfterCalcHeight;
BeginDraw(TempBmp.Canvas);
//frInterpretator.DoScript(Script);
InternalExecScript;
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 TfrCustomMemoView.MinHeight: Integer;
begin
Result := TextHeight;
end;
function TfrCustomMemoView.RemainHeight: Integer;
begin
Result := Memo1.Count * TextHeight;
end;
procedure TfrCustomMemoView.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 and (frVersion=25) 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;
if frVersion>26 then
begin
Stream.Read(FCursor, SizeOf(FCursor));
frReadMemo(Stream, FOnClick);
frReadMemo(Stream, FOnMouseEnter);
frReadMemo(Stream, FOnMouseLeave);
FDetailReport:=frReadString(Stream);
if LRE_OLDV28_FRF_READ and (frVersion=28) then
//
else
Stream.Read(FParagraphGap, SizeOf(FParagraphGap));
end;
if frVersion >= 29 then
begin
Stream.Read(FLineSpacing, SizeOf(FLineSpacing));
end;
end;
if frVersion = 21 then
Flags := Flags or flWordWrap;
end;
procedure TfrCustomMemoView.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', '0'), 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);
FCursor:=TCursor(XML.GetValue(Path+'Cursor/Value'{%H-}, crDefault));
FOnClick.Text:= XML.GetValue(Path+'Data/OnClick/Value', '');
FOnMouseEnter.Text:= XML.GetValue(Path+'Data/OnMouseEnter/Value', '');
FOnMouseLeave.Text:= XML.GetValue(Path+'Data/OnMouseLeave/Value', '');
FDetailReport:= XML.GetValue(Path+'Data/DetailReport/Value', '');
FParagraphGap:=XML.GetValue(Path+'Data/ParagraphGap/Value', 0);
FLineSpacing:=XML.GetValue(Path+'Data/LineSpacing/Value', 2);
end;
procedure TfrCustomMemoView.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));
Stream.Write(FCursor, SizeOf(FCursor));
frWriteMemo(Stream, FOnClick);
frWriteMemo(Stream, FOnMouseEnter);
frWriteMemo(Stream, FOnMouseLeave);
frWriteString(Stream, FDetailReport);
Stream.Write(FParagraphGap, SizeOf(FParagraphGap));
Stream.Write(FLineSpacing, SizeOf(FLineSpacing));
end;
end;
procedure TfrCustomMemoView.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);
XML.SetValue(Path+'Cursor/Value'{%H-}, FCursor);
XML.SetValue(Path+'Data/OnClick/Value', FOnClick.Text);
XML.SetValue(Path+'Data/OnMouseEnter/Value', FOnMouseEnter.Text);
XML.SetValue(Path+'Data/OnMouseLeave/Value', FOnMouseLeave.Text);
XML.SetValue(Path+'Data/DetailReport/Value', FDetailReport);
XML.SetValue(Path+'Data/ParagraphGap/Value', FParagraphGap);
XML.SetValue(Path+'Data/LineSpacing/Value', FLineSpacing);
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.FontChange(sender: TObject);
begin
AfterChange;
end;
procedure TfrCustomMemoView.ResetLastValue;
begin
IsLastValueSet := False;
end;
procedure TfrCustomMemoView.DoRunScript(AScript: TfrScriptStrings);
var
FSaveView:TfrView;
FSavePage:TfrPage;
CmdList, ErrorList:TStringList;
begin
FSaveView:=CurView;
FSavePage:=CurPage;
CmdList:=TStringList.Create;
ErrorList:=TStringList.Create;
try
CurView := Self;
CurPage:=OwnerPage;
frInterpretator.PrepareScript(AScript, CmdList, ErrorList);
frInterpretator.DoScript(CmdList);
finally
CurPage:=FSavePage;
CurView := FSaveView;
FreeAndNil(CmdList);
FreeAndNil(ErrorList);
end;
end;
procedure TfrCustomMemoView.DoOnClick;
var
FSaveRep:TfrReport;
FSaveView:TfrView;
FSavePage:TfrPage;
CmdList, ErrorList:TStringList;
FSaveGetPValue:TGetPValueEvent;
FSaveFunEvent:TFunctionEvent;
FDR:TlrDetailReport;
begin
if not Assigned(CurReport) then
exit;
if (FOnClick.Count>0) and (Trim(FOnClick.Text)<>'') then
DoRunScript(FOnClick);
FDR:=CurReport.DetailReports[FDetailReport];
if Assigned(FDR) and (FDR.ReportBody.Size>0) then
begin
FSaveView:=CurView;
FSavePage:=CurPage;
FSaveRep:=CurReport;
FSaveGetPValue:=frParser.OnGetValue;
FSaveFunEvent:=frParser.OnFunction;
FDR.ReportBody.Position:=0;
CurView := nil;
CurPage := nil;
CurReport:=TfrReport.Create(FSaveRep.Owner);
CurReport.OnBeginBand:=FSaveRep.OnBeginBand;
CurReport.OnBeginColumn:=FSaveRep.OnBeginColumn;
CurReport.OnBeginDoc:=FSaveRep.OnBeginDoc;
CurReport.OnBeginPage:=FSaveRep.OnBeginPage;
CurReport.OnDBImageRead:=FSaveRep.OnDBImageRead;
CurReport.OnEndBand:=FSaveRep.OnEndBand;
CurReport.OnEndDoc:=FSaveRep.OnEndDoc;
CurReport.OnEndPage:=FSaveRep.OnEndPage;
CurReport.OnEnterRect:=FSaveRep.OnEnterRect;
CurReport.OnExportFilterSetup:=FSaveRep.OnExportFilterSetup;
CurReport.OnGetValue:=FSaveRep.OnGetValue;
CurReport.OnManualBuild:=FSaveRep.OnManualBuild;
CurReport.OnMouseOverObject:=FSaveRep.OnMouseOverObject;
CurReport.OnObjectClick:=FSaveRep.OnObjectClick;
CurReport.OnPrintColumn:=FSaveRep.OnPrintColumn;
CurReport.OnProgress:=FSaveRep.OnProgress;
CurReport.OnUserFunction:=FSaveRep.OnUserFunction;
CmdList:=TStringList.Create;
ErrorList:=TStringList.Create;
try
CurReport.LoadFromXMLStream(FDR.ReportBody);
CurReport.ShowReport;
finally
FreeAndNil(CurReport);
CurReport:=FSaveRep;
CurPage:=FSavePage;
CurView := FSaveView;
frParser.OnGetValue:=FSaveGetPValue;
frParser.OnFunction:=FSaveFunEvent;
FreeAndNil(CmdList);
FreeAndNil(ErrorList);
end;
end;
end;
procedure TfrCustomMemoView.DoMouseEnter;
begin
if (FOnMouseEnter.Count>0) and (Trim(FOnMouseEnter.Text)<>'') and (Assigned(CurReport))then
DoRunScript(FOnMouseEnter);
end;
procedure TfrCustomMemoView.DoMouseLeave;
begin
if (FOnMouseLeave.Count>0) and (Trim(FOnMouseLeave.Text)<>'') and (Assigned(CurReport))then
DoRunScript(FOnMouseLeave);
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.MonitorFontChanges;
begin
FFont.OnChange:= @FontChange;
end;
procedure TfrCustomMemoView.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
TfrCustomMemoView(t).Format := EdFormat;
TfrCustomMemoView(t).FormatStr := EdFormatStr;
end;
end;
end;
end;
finally
frFmtForm.Free;
AfterChange
end;
end;
function TfrCustomMemoView.GetAutoSize: Boolean;
begin
Result:=((Flags and flAutoSize)<>0);
end;
function TfrCustomMemoView.GetHideDuplicates: Boolean;
begin
result:=((Flags and flHideDuplicates)<>0);
end;
function TfrCustomMemoView.GetHideZeroValues: Boolean;
begin
Result:=((Flags and flHideZeros)<>0);
end;
function TfrCustomMemoView.GetIsLastValueSet: boolean;
begin
result := FLastValue<>nil;
end;
function TfrCustomMemoView.GetJustify: boolean;
begin
result := (Adjust and %11) = %11;
end;
function TfrCustomMemoView.GetLayout: TTextLayout;
begin
result := TTextLayout((adjust shr 3) and %11);
end;
function TfrCustomMemoView.GetWordBreak: Boolean;
begin
Result := ((Flags and flWordBreak)<>0);
end;
function TfrCustomMemoView.GetAlignment: TAlignment;
begin
if (Adjust and %11) = %11 then
result := taLeftJustify
else
Result:=Classes.TAlignment(Adjust and %11);
end;
function TfrCustomMemoView.GetAngle: Byte;
begin
if Adjust and 4 <> 0 then
Result := 90
else
Result := 0
end;
function TfrCustomMemoView.GetWordWrap: Boolean;
begin
Result:=((Flags and flWordWrap)<>0);
end;
procedure TfrCustomMemoView.P2Click(Sender: TObject);
begin
MenuItemCheckFlag(Sender, flWordWrap);
end;
procedure TfrCustomMemoView.P3Click(Sender: TObject);
begin
MenuItemCheckFlag(Sender, flWordBreak);
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.P5Click(Sender: TObject);
begin
MenuItemCheckFlag(Sender, flAutoSize);
end;
procedure TfrCustomMemoView.P6Click(Sender: TObject);
begin
MenuItemCheckFlag(Sender, flHideZeros);
end;
procedure TfrCustomMemoView.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 TfrCustomMemoView.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 TfrCustomMemoView.SetAutoSize(const AValue: Boolean);
begin
if AutoSize<>AValue then
ModifyFlag(flAutoSize, AValue);
end;
procedure TfrCustomMemoView.SetCursor(AValue: TCursor);
begin
if FCursor=AValue then Exit;
BeforeChange;
FCursor:=AValue;
AfterChange;
end;
{----------------------------------------------------------------------------}
constructor TfrBandView.Create(AOwnerPage: TfrPage);
begin
inherited Create(AOwnerPage);
Typ := gtBand;
fFormat := 0;
BaseName := 'Band';
Flags := flBandOnFirstPage + flBandOnLastPage;
end;
procedure TfrBandView.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrBandView then
begin
BandType := TFrBandView(Source).BandType;
DataSet := TFrBandView(Source).DataSet;
GroupCondition:=TFrBandView(Source).GroupCondition;
Child := TFrBandView(Source).Child;
end;
end;
procedure TfrBandView.LoadFromStream(Stream: TStream);
begin
inherited LoadFromStream(Stream);
With Stream do
if frVersion>23 then begin
Read(fBandType,SizeOf(BandType));
if (frVersion<28) and (fBandType=btChild) then
fBandType := btNone; // btNone and btChild were swapped in version 29
fCondition :=ReadString(Stream);
fDataSetStr:=ReadString(Stream);
if frVersion>=28 then
fChild :=ReadString(Stream);
fixPrintChildIfNotVisible;
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
FChild := XML.GetValue(Path+'Child/Value', '');
FixPrintChildIfNotVisible;
end;
procedure TfrBandView.SaveToStream(Stream: TStream);
begin
inherited SaveToStream(Stream);
with Stream do
begin
Write(fBandType,SizeOf(fBandType));
frWriteString(Stream, fCondition);
frWriteString(Stream, fDataSetStr);
frWriteString(Stream, fChild);
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);
XML.SetValue(Path+'Child/Value', FChild);
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, btChild] 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;
if BandType <> btPageFooter then
begin
m := TMenuItem.Create(Popup);
m.Caption := sPrintChildIfNotVisible;
m.OnClick := @P7Click;
m.Checked := (Flags and flBandPrintChildIfNotVisible) <> 0;
Popup.Items.Add(m);
end;
if not (BandType in [btChild, btPageFooter]) then
begin
m := TMenuItem.Create(Popup);
m.Caption := sKeepChild;
m.OnClick := @P8Click;
m.Checked := (Flags and flBandKeepChild) <> 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;
procedure TfrBandView.P7Click(Sender: TObject);
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
Flags := (Flags and not flBandPrintChildIfNotVisible) + Word(Checked) * flBandPrintChildIfNotVisible;
end;
end;
procedure TfrBandView.P8Click(Sender: TObject);
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
Flags := (Flags and not flBandKeepChild) + Word(Checked) * flBandKeepChild;
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;
procedure TfrBandView.FixPrintChildIfNotVisible;
begin
if ((frVersion=28) or (frVersion=29)) and (flags and $80 <> 0) then
begin
flags := flags and not $80;
flags := flags or flBandPrintChildIfNotVisible;
end;
end;
procedure TfrBandView.SetHeight(const AValue: Double);
begin
inherited SetHeight(AValue);
if Assigned(Parent) then
Parent.dy := Round(Avalue);
end;
procedure TfrBandView.SetVisible(AValue: Boolean);
begin
inherited SetVisible(AValue);
if Assigned(Parent) then
Parent.Visible := Avalue;
end;
procedure TfrSubReportView.AfterLoad;
begin
inherited AfterLoad;
FSubPage:= CurReport.Pages[FSubPageIndex];
end;
{----------------------------------------------------------------------------}
constructor TfrSubReportView.Create(AOwnerPage: TfrPage);
begin
inherited Create(AOwnerPage);
Typ := gtSubReport;
BaseName := 'SubReport';
end;
procedure TfrSubReportView.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrSubReportView then
FSubPage := TfrSubReportView(Source).FSubPage;
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.PageIndex + 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(FSubPageIndex, 4);
end;
procedure TfrSubReportView.LoadFromXML(XML: TLrXMLConfig; const Path: String);
begin
inherited LoadFromXML(XML, Path);
FSubPageIndex := 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);
FSubPageIndex:=FSubPage.PageIndex;
XML.SetValue(Path+'SubPage/Value'{%H-}, FSubPageIndex);
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(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrPictureView then
begin
Picture.Assign(TfrPictureView(Source).Picture);
FSharedName := TFrPictureView(Source).SharedName;
end;
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]);
if t is TfrSubReportView then
begin
Page := (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;
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]);
if t is TfrSubReportView then
begin
Page := (t as TfrSubReportView).SubPage;
if Typ = btPageFooter then
begin
Parent.CurY := Parent.Bands[btPageFooter].y + t.y;
Parent.CurBottomY := Parent.Bands[btPageFooter].y +
Parent.Bands[btPageFooter].dy;
end;
Page.CurY := Parent.CurY;
Page.CurBottomY := Parent.CurBottomY;
end;
end;
EOFReached := True;
MaxY := Parent.CurY;
for i := SubIndex to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
if (t is TfrSubReportView) and (not EOFArr[i - SubIndex]) then
begin
Page := (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
if Typ <> btPageFooter then
Parent.NewPage;
end;
until EOFReached or MasterReport.Terminated;
for i := SubIndex to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
if t is TfrSubReportView then
begin
Page := (t as TfrSubReportView).SubPage;
Page.ClearRecList;
end;
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 (Parent.Bands[btColumnFooter] <> self) and
(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}
SetLength(PgArr,0);
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.InternalGapY;
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;
if (Flags and flBandKeepChild) <> 0 then
begin
b := Self.ChildBand;
while Assigned(b) do
begin
Result := Result + b.CalcHeight;
b := b.ChildBand;
end;
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 (ChildBand <> nil) then
ChildBand.Draw;
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
begin
if (ChildBand <> nil) and PrintChildIfNotVisible then
ChildBand.Draw;
if Typ in [btMasterData, btDetailData, btSubDetailData] then
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
btSubDetailFooter, btGroupFooter, btReportSummary]);
end;
// 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
{$ifdef DbgPrinter}
DebugLnEnter('TfrPage.Create INIT');
{$endif}
Self.Create(nil);
ChangePaper(ASize, AWidth, AHeight, AOr);
PrintToPrevPage := False;
UseMargins := True;
{$ifdef DbgPrinter}
DebugLnExit('TfrPage.Create END');
{$endif}
end;
constructor TfrPage.CreatePage;
begin
self.Create(nil);
end;
destructor TfrPage.Destroy;
begin
Clear;
Objects.Free;
RTObjects.Free;
List.Free;
fMargins.Free;
if Assigned(frDesigner) and (frDesigner.Page = Self) then
frDesigner.Page:=nil;
inherited Destroy;
end;
procedure TfrPage.ChangePaper(ASize, AWidth, AHeight: Integer;
AOr: TPrinterOrientation);
begin
{$ifdef DbgPrinter}
DebugLnEnter('TfrPage.ChangePaper INIT');
{$endif}
try
Prn.SetPrinterInfo(ASize, AWidth, AHeight, AOr);
Prn.FillPrnInfo(PrnInfo);
except
on E:exception do
begin
{$ifdef DbgPrinter}
Debugln(['Exception: selecting custom paper ']);
{$endif}
Prn.SetPrinterInfo($100, AWidth, AHeight, AOr);
Prn.FillPrnInfo(PrnInfo);
end;
end;
pgSize := Prn.PaperSize;
Width := Prn.PaperWidth;
Height := Prn.PaperHeight;
Orientation:= Prn.Orientation;
{$ifdef DbgPrinter}
DebugLnExit('TfrPage.ChangePaper END pgSize=%d Width=%d Height=%d Orientation=%d',
[pgSize,Width,Height,ord(Orientation)]);
{$endif}
end;
procedure TfrPage.Clear;
begin
while Objects.Count > 0 do
Delete(0);
end;
procedure TfrPage.Delete(Index: Integer);
begin
if not (doChildComponent in TfrView(Objects[Index]).FDesignOptions) then
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..lrMaxBandsInReport - 1] of TfrBand;
s: String;
begin
for i := 0 to Objects.Count - 1 do
begin
bt :=TfrView(Objects[i]);
if not (doChildComponent in bt.DesignOptions) then
begin
t := frCreateObject(bt.Typ, bt.ClassName, nil);
t.Assign(bt);
t.StreamMode := smPrinting;
T.OwnerPage:=Self;
RTObjects.Add(t);
if (t.Flags and flWantHook) <> 0 then
HookList.Add(t);
end;
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
(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 btChild do // fill other bands
if not (b in [btCrossHeader..btCrossFooter]) then
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;
PrintChildIfNotVisible := (Flags and flBandPrintChildIfNotVisible) <> 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;
for b := btReportTitle to btChild do
begin
Bnd := Bands[b];
while Bnd <> nil do
begin
if Bnd.View <> nil then
begin
s := TfrBandView(Bnd.View).Child;
for i := 0 to RTObjects.Count - 1 do
begin
bt :=TfrView(RTObjects[i]);
if (bt.Typ = gtBand) and (TfrBandView(bt).BandType=btChild) and (bt.Name=s) then
Bnd.ChildBand:=bt.Parent;
end;
end;
Bnd := Bnd.Next;
end;
end;
if ColCount = 0 then ColCount := 1;
ColWidth := (RightMargin - LeftMargin - (ColCount-1)*ColGap) 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;
T.PrepareObject;
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 (AppendPage 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);
AppendPage := False;
{$IFDEF DebugLR}
DebugLn('---- Start of new page ----');
{$ENDIF}
ColPos := 1;
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);
Inc(ColPos);
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 BackupBookmarks;
var
b: TfrBand;
i, n: Integer;
begin
SetLength(BooksBkUp, 0);
for i := 1 to MAXBNDS do
begin
b := Bands[Bnds[i, bpData]];
if BandExists(b) and (b.DataSet<>nil) then
begin
n := Length(BooksBkUp);
SetLength(BooksBkUp, n+1);
BooksBkUp[n].Dataset := b.Dataset;
BooksBkUp[n].Bookmark := b.Dataset.GetBookmark;
end;
end;
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);
end;
SetLength(BooksBkUp, 0);
end;
procedure DisableControls;
var
i: Integer;
b: TfrBand;
begin
if DetailCount=0 then
for i := 1 to MAXBNDS do
begin
b := Bands[Bnds[i, bpData]];
if BandExists(b) and (b.DataSet<>nil) then
b.DataSet.DisableControls;
end;
end;
procedure EnableControls;
var
i: Integer;
b: TfrBand;
begin
if DetailCount=0 then
for i := 1 to MAXBNDS do
begin
b := Bands[Bnds[i, bpData]];
if BandExists(b) and (b.Dataset<>nil) then
b.DataSet.EnableControls;
end;
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 AppendPage then
begin
if PrevY = PrevBottomY then
begin
AppendPage := False;
WasPF := False;
PageNo := MasterReport.EMFPages.Count;
end;
end;
if AppendPage 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 AppendPage 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}
if not (roPageHeaderBeforeReportTitle in MasterReport.Options) then
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 roPageHeaderBeforeReportTitle in MasterReport.Options then
ShowBand(Bands[btReportTitle]);
if not RowsLayout then
ShowBand(Bands[btColumnHeader]);
end;
end;
BndStackTop := 0;
DetailCount := 0;
for i := 1 to MAXBNDS do
if BandExists(Bands[Bnds[i, bpData]]) then begin
MaxLevel := i;
if Bands[Bnds[i, bpData]].Typ in [btDetailData,btSubDetailData] then
inc(DetailCount);
end;
if roSaveAndRestoreBookmarks in MasterReport.Options theN
begin
if Assigned(MasterReport.OnFormPageBookmarks) then
MasterReport.OnFormPageBookmarks(MasterReport, true)
else
BackupBookmarks;
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);
if roSaveAndRestoreBookmarks in MasterReport.Options then
begin
if Assigned(MasterReport.OnFormPageBookmarks) then
MasterReport.OnFormPageBookmarks(MasterReport, false)
else
RestoreBookmarks; // this also enablecontrols
end;
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;
function TfrPage.GetPageIndex: integer;
begin
Result:=CurReport.Pages.FPages.IndexOf(Self);
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.SetPageIndex(AValue: integer);
begin
if (AValue>-1) and (AValue < CurReport.Pages.Count) and (GetPageIndex <> AValue) then
CurReport.Pages.Move(GetPageIndex, AValue);
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;
function TfrPages.Add(const aClassName: string): TfrPage;
var
Rf : TFrPageClass;
begin
Result := nil;
Rf:=TFrPageClass(GetClass(aClassName));
if Assigned(Rf) then
begin
Result := Rf.CreatePage;
if Assigned(Result) then
begin
Result.CreateUniqueName;
FPages.Add(Result);
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.Move(OldIndex, NewIndex: Integer);
begin
FPages.Move(OldIndex, NewIndex);
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);
t :=frCreateObject(ot, clname, Pages[b]);
{ 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]);}
t:=frCreateObject(ot, clname, aPage);
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]);
if not (doChildComponent in T.FDesignOptions) then
begin
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;
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, C: 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);
C:=0;
for j:=0 to Pages[i].Objects.count - 1 do
begin
T := TfrView(Pages[i].Objects[j]);
if not (doChildComponent in T.FDesignOptions) then
begin
aSubPath := aPath + 'Object'+IntTostr(C + 1)+'/';
T.SaveToXML(XML, aSubPath);
Inc(C);
end;
end;
XML.SetValue(aPath+'ObjectCount/Value'{%H-}, C);
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;
oldRgn, pageRgn: HRGN;
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}
pageRgn := 0;
oldRgn := CreateRectRgn(0, 0, 0, 0);
LCLIntf.GetClipRgn(Canvas.Handle, oldRgn);
try
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;
pageRgn := CreateRectRgn(DrawRect.Left+1, DrawRect.Top+1, DrawRect.Right-1, DrawRect.Bottom-1);
LCLIntf.SelectClipRGN(Canvas.Handle, pageRgn);
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;
LCLIntf.DeleteObject(pageRgn);
pageRgn := 0;
end
{ else
begin
Page.Free;
Page := nil;
end;}
end;
finally
if pageRgn<>0 then
LCLIntf.DeleteObject(pageRgn);
LCLIntf.SelectClipRGN(Canvas.Handle, oldRgn);
LCLIntf.DeleteObject(oldRgn);
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, nil);
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);
try
t.StreamMode := smPrinting;
t.LoadFromStream(Stream);
t.StreamMode := smDesigning;
except
if frVersion in [25, 28] then
ShowMessage(format(sReportCorruptOldKnowVersion,[frVersion]))
else
ShowMessage(format(sReportCorruptUnknownVersion,[frVersion]));
break;
end;
// 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]);
if not (doChildComponent in T.DesignOptions) then
begin
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;
P^.pgOr:=P^.Page.Orientation;
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;
procedure TfrEMFPages.ResetFindData;
var
i: Integer;
j: Integer;
P: PfrPageInfo;
begin
for i:=0 to Count - 1 do
begin
P:=Pages[i];
if Assigned(P^.Page) then
for j:=0 to P^.Page.Objects.Count - 1 do
TfrView(P^.Page.Objects[j]).FindHighlight:=false;
end;
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
Result:=Parent.DoObjectClick(V);
if Result then
AInfo:=V.FURLInfo;
exit;
end;
end;
end;
function TfrEMFPages.DoMouseMove(Index: Integer; pt: TPoint;
var Cursor: TCursor; var AInfo: String): TfrView;
var
PgInf: PfrPageInfo;
V: TfrView;
i: Integer;
R1:TRect;
begin
Result := nil;
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
Result := V;
if Result is TfrMemoView then
Cursor:=TfrMemoView(Result).Cursor;
if Assigned(Parent.OnMouseOverObject) then
Parent.OnMouseOverObject(V, Cursor);
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
{$ifdef DebugLR}
DebugLnEnter('TfrEMFPages.LoadFromStream: INIT',[]);
{$endif}
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);
{$ifdef DebugLR}
DebugLnExit('TfrEMFPages.LoadFromStream: DONE',[]);
{$endif}
end;
procedure TfrEMFPages.AddPagesFromStream(AStream: TStream;
AReadHeader: boolean=true);
var
i, o, c: Integer;
b, compr: Byte;
p: PfrPageInfo;
s: TMemoryStream;
begin
{$ifdef DebugLR}
DebugLnEnter('TfrEMFPages.AddPagesFromStream: INIT',[]);
{$endif}
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;
{$ifdef DebugLR}
DebugLnExit('TfrEMFPages.AddPagesFromStream: DONE',[]);
{$endif}
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;
procedure TfrEMFPages.UpgradeToCurrentVersion;
var
i: Integer;
begin
for i:=0 to Count-1 do begin
ObjectsToPage(i);
PageToObjects(i);
end;
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);
FRebuildPrinter:=false;
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;
FDetailReports:=TlrDetailReports.Create;
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;
FDefaultCopies := 1;
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(FDetailReports);
FreeAndNil(FScript);
inherited Destroy;
end;
procedure TfrReport.Clear;
begin
Pages.Clear;
if frDataManager <> nil then
frDataManager.Clear;
DoublePass := False;
ClearAttribs;
FDetailReports.Clear;
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
{$IF FPC_FULLVERSION >= 30101}
st := TStringStream.CreateRaw('');
{$ELSE}
st := TStringStream.Create('');
{$ENDIF}
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;
Dummy: Extended;
IsNumeric: Boolean;
begin
if (TVarData(v).VType = varEmpty) {VarIsEmpty(v)} or VarIsNull(v) then
begin
Result := ' ';
Exit;
end;
c := DefaultFormatSettings.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
IsNumeric := VarIsNumeric(v) or TryStrToFloat(v, Dummy);
if not IsNumeric then
result := v
else begin
DefaultFormatSettings.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;
DefaultFormatSettings.DecimalSeparator := c;
end;
procedure TfrReport.GetVariableValue(const s: String; var aValue: Variant);
var
Value: TfrValue;
D: TfrTDataSet;
F: TfrTField;
s1, SE1: String;
aCursr: Longint;
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
else
if IdentToCursor(S, aCursr) then
begin
aValue:=aCursr;
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
begin
SE1:='';
if Assigned(CurView) then
SE1:=SE1 + 'Object : ' + CurView.Name + #13;
if Assigned(CurBand) then
SE1:=SE1 + 'Band : ' + CurBand.Name + #13;
if Assigned(CurPage) then
SE1:=SE1 + 'Page : ' + CurPage.Name + #13;
raise(EParserError.Create(SE1 + 'Undefined symbol: ' + SubValue));
end;
end;
end;
end;
end;
end;
end;
//check if CurView is TfrBandView to avoid clash with flBandPrintChildIfNotVisible. Issue 29313
if Assigned(CurView) and ((CurView.Flags and flHideZeros <> 0) and not (CurView is TfrBandView)) then
begin
if TVarData(aValue).VType in [varSmallInt, varInteger, varCurrency,
varDecimal, varShortInt, varByte, varWord, varLongWord, varInt64,
varQWord, varDouble, varSingle] then
begin
if aValue = 0 then
aValue:=Null;
end;
end;
end;
procedure TfrReport.OnGetParsFunction(const aName: String; p1, p2, p3: Variant;
var val: Variant);
function ProcessObjMethods(Method:string):boolean;
var
ObjName:string;
Obj:TfrObject;
Page:TfrPage;
i, j:integer;
begin
Result:=false;
Obj:=nil;
ObjName:=Copy2SymbDel(Method, '.');
for i:=0 to CurReport.Pages.Count - 1 do
begin
Page := CurReport.Pages[i];
if UpperCase(Page.Name) = ObjName then
begin
// PageName.ObjName.Method
Obj:=Page;
if Method<>'' then
begin
ObjName:=Copy2SymbDel(Method, '.');
for j:=0 to Page.Objects.Count - 1 do
begin
if UpperCase(TfrObject(Page.Objects[j]).Name) = ObjName then
begin
Obj:=TfrObject(Page.Objects[j]);
break;
end;
end;
end;
Break;
end
else
begin
for j:=0 to Page.Objects.Count - 1 do
begin
if UpperCase(TfrObject(Page.Objects[j]).Name) = ObjName then
begin
Obj:=TfrObject(Page.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;
if Stream.Read(frVersion, 1)<>1 then
raise ELazReportException.CreateFmt('%s: %s', [sInvalidFRFReport, sUnableToReadVersion]);
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);
if frVersion>26 then
FDetailReports.LoadFromStream(Stream);
except
on E:Exception do
begin
Pages.Clear;
Pages.Add;
MessageDlg(sInvalidFRFReport+^M+E.Message,mtError,[mbOk],0)
end;
end
else
raise ELazReportException.CreateFmt('%s: %s (%d)', [sInvalidFRFReport, sInvalidFRFVersion, frVersion]);
end;
procedure TfrReport.LoadFromXML(XML: TLrXMLConfig; const Path: String);
var
ATitle: string;
begin
ATitle := XML.GetValue(Path+'Version/Value', 'LR-ERROR');
if ATitle='LR-ERROR' then
raise ELazReportException.CreateFmt('%s: %s',[sReportLoadingError, sInvalidLRFReport]);
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);
FDetailReports.LoadFromXML(XML, Path+'DetailReports/');
end;
procedure TfrReport.SaveToStream(Stream: TStream);
begin
CurReport := Self;
frVersion := frCurrentVersion;
Stream.Write(frVersion, 1);
Pages.SaveToStream(Stream);
FDetailReports.SaveToStream(Stream);
end;
procedure TfrReport.LoadFromFile(const FName: String);
var
Stream: TFileStreamUtf8;
Ext : String;
begin
Ext:=ExtractFileExt(fName);
if SameText('.lrf',Ext) then
LoadFromXMLFile(fName)
else
begin
CheckFileExists(fName);
Stream := TFileStreamUtf8.Create(FName, fmOpenRead);
LoadFromStream(Stream);
Stream.Free;
FileName := FName;
end;
end;
procedure TfrReport.LoadFromXMLFile(const Fname: String);
var
XML: TLrXMLConfig;
begin
CheckFileExists(FName);
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: TFileStreamUtf8;
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 := TFileStreamUtf8.Create(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/');
FDetailReports.SaveToXML(XML, Path+'DetailReports/');
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: TFileStreamUtf8;
begin
Stream := TFileStreamUtf8.Create(FName, fmOpenRead);
EMFPages.LoadFromStream(Stream);
Stream.Free;
CanRebuild := False;
end;
procedure TfrReport.SavePreparedReport(const FName: String);
var
Stream: TFileStreamUtf8;
begin
Stream := TFileStreamUtf8.Create(FName, fmCreate);
if not CanRebuild and not (roDontUpgradePreparedReport in Options) then
EMFPages.UpgradeToCurrentVersion;
EMFPages.SaveToStream(Stream);
Stream.Free;
end;
procedure TfrReport.LoadTemplate(const fname: String; comm: TStrings;
Bmp: TBitmap; Load: Boolean);
var
Stream: TFileStreamUtf8;
b: Byte;
fb: TBitmap;
fm: TStringList;
pos: Integer;
begin
fb := TBitmap.Create;
fm := TStringList.Create;
Stream := TFileStreamUtf8.Create(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: TFileStreamUtf8;
b: Byte;
pos, lpos: Integer;
begin
Stream := TFileStreamUtf8.Create(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;
AppendPage := 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: TFileStreamUtf8;
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;
function TfrReport.ExportTo(FilterClass: TfrExportFilterClass; aFileName: String
): Boolean;
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 ExportFilters.Count - 1 do
if (ExportFilters[i].FClassRef.ClassName=fDefExportFilterClass) then
begin
FilterClass := ExportFilters[i].FClassRef;
break;
end;
end;
if (aFileName='') and (fDefExportFileName<>'') then
aFileName := fDefExportFileName;
if FilterClass=nil then
raise Exception.Create(sNoValidFilterClassWasSupplied);
if Trim(aFilename) = '' then
raise Exception.create(sNoValidExportFilenameWasSupplied);
ExportStream := TFileStreamUtf8.Create(aFileName, fmCreate);
FCurrentFilter := FilterClass.Create(ExportStream);
try
CurReport := Self;
MasterReport := Self;
FCurrentFilter.OnSetup:=CurReport.OnExportFilterSetup;
if FCurrentFilter.Setup then
begin
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;
Result:=true;
end
else
Result:=false;
finally
//is necessary to destroy the file stream before calling FCurrentFilter.AfterExport
//to ensure the exported file is properly written to the file system
ExportStream.Free;
end;
FCurrentFilter.Stream := nil;
if Result then
FCurrentFilter.AfterExport;
FreeAndNil(FCurrentFilter);
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];
CurPage := Pages[i];
if CurPage.Skip or (not CurPage.Visible) then
Continue;
CurPage.Mode := pmNormal;
if Assigned(FOnManualBuild) then
FOnManualBuild(CurPage)
else
CurPage.FormPage;
{$IFDEF DebugLR}
debugLn('p3');
{$ENDIF}
AppendPage := 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);
AppendPage := True;
end;
if not AppendPage 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
{$ifdef DebugLR}
DebugLnEnter('PrintPage: INIT ',[]);
{$endif}
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;
{$ifdef DebugLR}
DebugLnExit('PrintPage: DONE',[]);
{$endif}
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}
DebugLnEnter('TfrReport.DoPrintReport: INIT ',[]);
DebugPrnInfo('=== INIT');
{$endif}
if Prn.UseVirtualPrinter then
ChangePrinter(Prn.PrinterIndex, Printer.PrinterIndex);
if Assigned(FOnBeforePrint) then
OnBeforePrint(Self);
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;
if Assigned(FOnAfterPrint) then
OnAfterPrint(Self);
{$ifdef DebugLR}
DebugPrnInfo('=== END');
DebugLnExit('TfrReport.DoPrintReport: DONE',[]);
{$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 CurPrinter="%s"',[Prn.Printer.PrinterName]);
{$endif}
end;
procedure TfrReport.SetReportOptions(AValue: TfrReportOptions);
begin
if FReportOptions=AValue then Exit;
FReportOptions:=AValue;
if Assigned(frProgressForm) then
frProgressForm.Button1.Enabled:=not (roDisableCancelBuild in FReportOptions);
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;
SaveToXMLStream(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;
LoadFromXMLStream(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.CheckFileExists(FName: string);
begin
if not FileExistsUTF8(FName) then
raise ELazReportException.CreateFmt('%s: %s (%s)',
[sReportLoadingError, sFileNotFound, FName]);
end;
function TfrReport.DoObjectClick(AObj: TfrView): boolean;
begin
Result:=false;
if AObj is TfrMemoView then
TfrMemoView(AObj).DoOnClick;
Result:=Assigned(OnObjectClick);
if Assigned(OnObjectClick) then
OnObjectClick(AObj);
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
{$IF FPC_FULLVERSION >= 30101}
st := TStringStream.CreateRaw(FXMLReport);
{$ELSE}
st := TStringStream.Create(FXMLReport);
{$ENDIF}
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;
PropName: String;
PropInfo:PPropInfo;
St:string;
i:integer;
FColorVal:TColor;
begin
t := nil;
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;
PropInfo:=FindObjectProps(AName, t, PropName, i);
if Assigned(t) then
begin
//Retreive property informations
if Assigned(PropInfo) then
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,') Prop=',PropName, ' Kind=',InttoStr(Ord(PropInfo^.PropType^.Kind)));
{$ENDIF}
case PropInfo^.PropType^.Kind of
tkChar,tkAString,tkWString,
tkSString,tkLString :
begin
St:=GetStrProp(t, PropInfo);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
AValue:=St;
end;
tkBool,tkInt64,tkQWord,
tkInteger : AValue:=GetOrdProp(t, PropInfo);
tkSet : begin
St:=GetSetProp(t, PropInfo, false);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
AValue:=St;
end;
tkFloat : AValue:=GetFloatProp(t,PropInfo);
tkEnumeration : begin
St:=GetEnumProp(t,PropInfo);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
AValue:=St;
end;
end;
end
else
if not (t is TfrBandView) and (i>=0) then
begin
{$IFDEF DebugLR}
DbgOut('A CustomField was found ', PropName);
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;
end;
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,') No Propinfo for Prop=',PropName,' Value=',dbgs(AValue));
{$ENDIF}
end
else
begin
// it's not a property of t, try with known color names first
if IdentToColor(AName, FColorVal) then
AValue := FColorVal
else
if UpperCase(AName) = 'MROK' then //try std ModalResult values
AValue := mrOk
else
if UpperCase(AName) = 'MRCANCEL' then //try std ModalResult values
AValue := mrCancel
else
if (UpperCase(AName) = 'FINALPASS') and Assigned(CurReport) then
AValue := CurReport.FinalPass
else
if (UpperCase(AName) = 'CURY') and Assigned(CurPage) then
AValue := CurPage.CurY
else
if (UpperCase(AName) = 'PAGEHEIGHT') and Assigned(CurPage) then
AValue := CurPage.Height
else
if (UpperCase(AName) = 'PAGEWIDTH') and Assigned(CurPage) then
AValue := CurPage.Width;
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;
AppendPage := 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;
function TfrExportFilter.Setup: boolean;
begin
Result:=true;
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.AfterExport;
begin
// abstract method
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
i:=List.IndexOf(funName);
if i>=0 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}
if dk <> dkCount then begin
// p1 = field
// p2 = data band
// p3 = InvisibleToo
s1 := trim(string(p2));
if s1='' then
s1 := CurBand.View.Name;
s2 := Trim(string(p3))
end
else begin
// p1 = data band
// p2 = InvisibleToo
s1 := Trim(string(p1));
s2 := Trim(string(p2));
if s2<>'1' then
s2 := '0';
end;
// s1 = data band
// s2 = '1' o '0' (1 means process invisible records too)
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] + StringReplace(p1, '=', '_', [rfReplaceAll]);
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;
PropName : String;
PropInfo : PPropInfo;
S : String;
i : Integer;
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.SetValue(',Name,',',Value,')');
if VarIsNull(Value) or VarIsEmpty(Value) then
DebugLn('Value=NULL');
{$ENDIF}
PropInfo:=FindObjectProps(Name, t, PropName, i);
if Assigned(PropInfo) then
begin
S:=VarToStr(Value);
{$IFDEF DebugLR}
DebugLn('PropInfo for ',propName,' found, Setting Value=',S);
{$ENDIF}
Case PropInfo^.PropType^.Kind of
tkChar,tkAString,tkWString,
tkSString,tkLString : SetStrProp(t,PropInfo,S);
tkBool,tkInt64,tkQWord,
tkInteger : begin
if AnsiCompareText(PropInfo^.PropType^.Name,'TGraphicsColor')=0 then
SetOrdProp(t,PropInfo,StringToColor(S))
else
SetOrdProp(t,PropInfo,Value)
end;
tkSet : SetSetProp(t,PropInfo,S);
tkFloat : SetFloatProp(t,PropInfo, Value);
tkEnumeration : SetEnumProp(t,PropInfo, S);
end;
end
else
begin
if Assigned(t) and not (t is TfrBandView) then
begin
// try with customized properties not included directly in t
if i>=0 then begin
{$IFDEF DebugLR}
DbgOut('A CustomField was found ', PropName);
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( sInvalidVariableName, [Name]);
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;
if Assigned(FExportFilters) then
FreeAndNil(FExportFilters);
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;
procedure TfrObject.AfterCreate;
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.InternalExecScript;
begin
if Assigned(FOnExecScriptEvent) then
FOnExecScriptEvent(Self, Script)
else
frInterpretator.DoScript(Script);
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:=[];
if Assigned(OwnerPage) then
OwnerPage.Objects.Add(Self);
end;
destructor TfrObject.Destroy;
begin
fmemo.Free;
fScript.Free;
inherited Destroy;
end;
procedure TfrObject.AssignTo(Dest: TPersistent);
begin
//
end;
procedure TfrObject.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TfrObject then
begin
x := TfrObject(Source).x;
y := TfrObject(Source).y;
dx := TfrObject(Source).dx;
dy := TfrObject(Source).dy;
Memo.Assign(TfrObject(Source).Memo);
Script.Assign(TfrObject(Source).Script);
Visible:=TfrObject(Source).Visible;
FOnExecScriptEvent:=TfrObject(Source).FOnExecScriptEvent;
end;
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
{$ifdef DbgPrinter}
DebugLnEnter('TfrPageReport.LoadFromXML INIT');
{$endif}
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);
{$ifdef DbgPrinter}
DebugLnExit('TfrPageReport.LoadFromXML END');
{$endif}
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:=FCaption;
end;
procedure TfrPageDialog.SetCaption(AValue: string);
begin
FCaption:=AValue;
if Assigned(FForm) then
FForm.Caption:=AValue;
end;
procedure TfrPageDialog.UpdateControlPosition;
begin
if Assigned(FForm) then
begin
FForm.Left:=Left;
FForm.Top:=Top;
FForm.Width:=Width;
FForm.Height:=Height - 20;
FForm.Position:=poScreenCenter;
end;
end;
procedure TfrPageDialog.PrepareObjects;
begin
//Do nothing
end;
procedure TfrPageDialog.InitReport;
var
i:integer;
P:TfrControl;
S:string;
F:TComponent;
begin
if not fVisible then
exit;
fHasVisibleControls:=False;
FForm :=TfrDialogForm.CreateNew(Application);
FForm.OnDestroy:=@EditFormDestroy;
FForm.Caption:=FCaption;
FForm.ShowHint:=true;
S:=FName;
F:=Application.FindComponent(S);
if Assigned(F) and (F<>FForm) then
begin
i:=1;
while Assigned(Application.FindComponent(FName + IntToStr(i))) do inc(i);
S:=FName + IntToStr(i);
end;
FForm.Name:=S;
for i:=0 to Objects.Count - 1 do
begin
P:=TfrControl(Objects[i]);
P.AttachToParent;
if not (P is TfrNonVisualControl) then
begin
fHasVisibleControls:=true;
P.UpdateControlPosition;
end;
end;
ExecScript;
if fHasVisibleControls then
begin
UpdateControlPosition;
if FForm.ShowModal <> mrOk then
CurReport.Terminated:=true;
end;
end;
procedure TfrPageDialog.DoneReport;
begin
inherited DoneReport;
FreeAndNil(FForm);
end;
procedure TfrPageDialog.SetLeft(AValue: Integer);
begin
inherited SetLeft(AValue);
UpdateControlPosition;
end;
procedure TfrPageDialog.SetTop(AValue: Integer);
begin
inherited SetTop(AValue);
UpdateControlPosition;
end;
procedure TfrPageDialog.SetWidth(AValue: Integer);
begin
inherited SetWidth(AValue);
UpdateControlPosition;
end;
procedure TfrPageDialog.SetHeight(AValue: Integer);
begin
inherited SetHeight(AValue);
UpdateControlPosition;
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);
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.