lazarus/components/lazreport/source/lr_class.pas
2008-12-14 18:27:04 +00:00

9776 lines
252 KiB
ObjectPascal
Raw Blame History

{*****************************************}
{ }
{ FastReport v2.3 }
{ Report classes }
{ }
{ Copyright (c) 1998-99 by Tzyganenko A. }
{ }
{*****************************************}
unit LR_Class;
interface
{$I LR_Vers.inc}
uses
SysUtils, Classes, Controls, FileUtil,
Forms, StdCtrls, ComCtrls, Dialogs, Menus,
Variants, DB,Graphics,Printers,osPrinters,XMLConf,
LCLType,LCLIntf,TypInfo,LCLProc,
SysUtilsAdds,
LR_View, LR_Pars, LR_Intrp, LR_DSet, LR_DBSet, LR_DBRel,LR_Const;
const
// object flags
flStretched = 1;
flWordWrap = 2;
flWordBreak = 4;
flAutoSize = 8;
flBandNewPageAfter = 2;
flBandPrintifSubsetEmpty = 4;
flBandPageBreak = 8;
flBandOnFirstPage = $10;
flBandOnLastPage = $20;
flBandRepeatHeader = $40;
flPictCenter = 2;
flPictRatio = 4;
flWantHook = $8000;
// object types
gtMemo = 0;
gtPicture = 1;
gtBand = 2;
gtSubReport = 3;
gtLine = 4;
gtAddIn = 10;
//format type
fmtText = 0;
fmtNumber = 1;
fmtDate = 2;
fmtTime = 3;
fmtBoolean = 4;
type
TfrDrawMode = (drAll, drCalcHeight, drAfterCalcHeight, drPart);
TfrBandType = (btReportTitle, btReportSummary,
btPageHeader, btPageFooter,
btMasterHeader, btMasterData, btMasterFooter,
btDetailHeader, btDetailData, btDetailFooter,
btSubDetailHeader, btSubDetailData, btSubDetailFooter,
btOverlay, btColumnHeader, btColumnFooter,
btGroupHeader, btGroupFooter,
btCrossHeader, btCrossData, btCrossFooter, btNone);
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);
TfrView = class;
TfrBand = class;
TfrPage = class;
TfrReport = class;
TfrExportFilter = class;
TDetailEvent = procedure(const ParName: String; var ParValue: Variant) of object;
TEnterRectEvent = procedure(Memo: TStringList; View: TfrView) of object;
TBeginDocEvent = procedure of object;
TEndDocEvent = procedure of object;
TBeginPageEvent = procedure(pgNo: Integer) of object;
TEndPageEvent = procedure(pgNo: Integer) of object;
TBeginBandEvent = procedure(Band: TfrBand) of object;
TEndBandEvent = procedure(Band: TfrBand) of object;
TfrProgressEvent = procedure(n: Integer) of object;
TBeginColumnEvent = procedure(Band: TfrBand) of object;
TPrintColumnEvent = procedure(ColNo: Integer; var Width: Integer) of object;
TManualBuildEvent = procedure(Page: TfrPage) of object;
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
end;
PfrPageInfo = ^TfrPageInfo;
TfrPageInfo = packed record // pages of a preview
R : TRect;
pgSize : Word;
pgWidth : Integer;
pgHeight : Integer;
pgOr : TPrinterOrientation;
pgMargins : Boolean;
PrnInfo : TfrPrnInfo;
Visible : Boolean;
Stream : TMemoryStream;
Page : TfrPage;
end;
PfrBandRec = ^TfrBandRec;
TfrBandRec = packed record
Band : TfrBand;
Action : TfrBandRecType;
end;
TLayoutOrder = (loColumns, loRows);
TfrMemoStrings =Class(TStringList);
TfrScriptStrings=Class(TStringList);
TfrDialogForm = Class(TForm);
{ TLrXMLConfig }
TLrXMLConfig = class (TXMLConfig)
public
procedure 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 SetName(const AValue: string);
procedure SetScript(const AValue: TfrScriptStrings);
protected
BaseName : String;
function GetSaveProperty(Prop : String; aObj : TPersistent=nil) : string;
procedure RestoreProperty(Prop,aValue : String; aObj : TPersistent=nil);
public
x, y, dx, dy: Integer;
constructor Create; virtual;
destructor Destroy; override;
procedure Assign(From: TfrView); virtual; overload;
procedure BeginUpdate;
procedure EndUpdate;
procedure CreateUniqueName;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); virtual;
procedure SaveToXML(XML: TLrXMLConfig; Path: String); virtual;
property Memo : TfrMemoStrings read fMemo write SetMemo;
property Script : TfrScriptStrings read fScript write SetScript;
property Left : Integer read x write x;
property Top : Integer read y write y;
property Width : Integer read dx write dx;
property Height : Integer read dy write dy;
published
property Name : string read fName write SetName;
property Visible: Boolean read fVisible write fVisible;
end;
{ TfrView }
TfrView = class(TfrObject)
private
fFillColor : TColor;
fCanvas : TCanvas;
fFrameColor: TColor;
fFrames : TfrFrameBorders;
fFrameStyle: TfrFrameStyle;
fFrameWidth: Double;
fStretched : Boolean;
fStreamMode: TfrStreamMode;
fFormat : Integer;
fFormatStr : string;
function GetHeight: Double;
function GetLeft: Double;
function GetTop: Double;
function GetWidth: Double;
procedure P1Click(Sender: TObject);
procedure SetFillColor(const AValue: TColor);
procedure SetFormat(const AValue: Integer);
procedure SetFormatStr(const AValue: String);
procedure SetFrameColor(const AValue: TColor);
procedure SetFrames(const AValue: TfrFrameBorders);
procedure SetFrameStyle(const AValue: TfrFrameStyle);
procedure SetFrameWidth(const AValue: Double);
procedure SetHeight(const AValue: Double);
procedure SetLeft(const AValue: Double);
procedure SetStretched(const AValue: Boolean);
procedure SetTop(const AValue: Double);
procedure SetWidth(const AValue: Double);
protected
SaveX, SaveY, SaveDX, SaveDY: Integer;
SaveFW: Double;
gapx, gapy: Integer;
Memo1: TStringList;
FDataSet: TfrTDataSet;
FField: String;
olddy: 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;
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;
constructor Create; override;
destructor Destroy; override;
procedure Assign(From: TfrView); override;
procedure CalcGaps; virtual;
procedure RestoreCoord; virtual;
procedure Draw(aCanvas: TCanvas); virtual; abstract;
procedure Print(Stream: TStream); virtual;
procedure ExportData; virtual;
procedure LoadFromStream(Stream: TStream); virtual;
procedure SaveToStream(Stream: TStream); virtual;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SaveToXML(XML: TLrXMLConfig; 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 fStretched write SetStretched;
property Frames : TfrFrameBorders read fFrames write SetFrames;
property FrameColor : TColor read fFrameColor write SetFrameColor;
property FrameStyle : TfrFrameStyle read fFrameStyle write SetFrameStyle;
property FrameWidth : Double read fFrameWidth write SetFrameWidth;
property Format : Integer read fFormat write SetFormat;
property FormatStr : String read fFormatStr write SetFormatStr;
property StreamMode: TfrStreamMode read fStreamMode write fStreamMode;
published
property Left: double read GetLeft write SetLeft;
property Top: double read GetTop write SetTop;
property 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;
{ TfrMemoView }
TfrMemoView = class(TfrStretcheable)
private
fAngle : Byte;
fFont : TFont;
function GetAlignment: TAlignment;
function GetAutoSize: Boolean;
function GetLayout: TTextLayout;
function GetWordWrap: Boolean;
procedure P1Click(Sender: TObject);
procedure P2Click(Sender: TObject);
procedure P3Click(Sender: TObject);
procedure P4Click(Sender: TObject);
procedure P5Click(Sender: TObject);
procedure SetAlignment(const AValue: TAlignment);
procedure SetAutoSize(const AValue: Boolean);
procedure SetFont(Value: TFont);
procedure SetLayout(const AValue: TTextLayout);
procedure SetWordWrap(const AValue: Boolean);
protected
Streaming: Boolean;
TextHeight: Integer;
CurStrNo: Integer;
Exporting: Boolean;
procedure ExpandVariables;
procedure AssignFont(aCanvas: TCanvas);
procedure WrapMemo;
procedure ShowMemo;
function CalcWidth(aMemo: TStringList): Integer;
function CalcHeight: Integer; override;
function MinHeight: Integer; override;
function RemainHeight: Integer; override;
procedure GetBlob(b: TfrTField); override;
procedure FontChange(sender: TObject);
public
Adjust: Integer; // bit format xxxLLRAA: LL=Layout, R=Rotated, AA=Alignment
Highlight: TfrHighlightAttr;
HighlightStr: String;
LineSpacing, CharacterSpacing: Integer;
constructor Create; override;
destructor Destroy; override;
procedure Assign(From: TfrView); override;
procedure Draw(aCanvas: TCanvas); override;
procedure Print(Stream: TStream); override;
procedure ExportData; override;
procedure LoadFromStream(Stream: TStream); override;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SaveToStream(Stream: TStream); override;
procedure SaveToXML(XML: TLrXMLConfig; Path: String); override;
procedure DefinePopupMenu(Popup: TPopupMenu); override;
procedure MonitorFontChanges;
published
property Font : TFont read fFont write SetFont;
property Alignment : TAlignment read GetAlignment write SetAlignment;
property Layout : TTextLayout read GetLayout write SetLayout;
property Angle : Byte read fAngle write fAngle;
property WordWrap : Boolean read GetWordWrap write SetWordWrap;
property AutoSize : Boolean read GetAutoSize write SetAutoSize;
property FillColor;
property Memo;
property Script;
property Frames;
property FrameColor;
property FrameStyle;
property FrameWidth;
property Format;
property FormatStr;
end;
{ TfrBandView }
TfrBandView = class(TfrView)
private
fDataSetStr : String;
fBandType : TfrBandType;
fCondition : String;
procedure P1Click(Sender: TObject);
procedure P2Click(Sender: TObject);
procedure P3Click(Sender: TObject);
procedure P4Click(Sender: TObject);
procedure P5Click(Sender: TObject);
procedure P6Click(Sender: TObject);
public
constructor Create; override;
procedure Assign(From: TfrView); override;
procedure LoadFromStream(Stream: TStream); override;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SaveToStream(Stream: TStream); override;
procedure SaveToXML(XML: TLrXMLConfig; Path: String); override;
procedure Draw(aCanvas: TCanvas); override;
procedure DefinePopupMenu(Popup: TPopupMenu); override;
function GetClipRgn(rt: TfrRgnType): HRGN; override;
function PointInView(aX,aY : Integer) : Boolean; override;
published
property DataSet: String read fDataSetStr write fDataSetStr;
property GroupCondition: String read fCondition write fCondition;
property BandType: TfrBandType read fBandType write fBandType;
property Script;
end;
{ TfrSubReportView }
TfrSubReportView = class(TfrView)
public
SubPage: Integer;
constructor Create; override;
procedure Assign(From: TfrView); override;
procedure Draw(aCanvas: TCanvas); override;
procedure LoadFromStream(Stream: TStream); override;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SaveToStream(Stream: TStream); override;
procedure SaveToXML(XML: TLrXMLConfig; Path: String); override;
procedure DefinePopupMenu(Popup: TPopupMenu); override;
end;
{ TfrPictureView }
TfrPictureView = class(TfrView)
private
fPicture: TPicture;
procedure P1Click(Sender: TObject);
procedure P2Click(Sender: TObject);
function GetPictureType: byte;
function PictureTypeToGraphic(b: Byte): TGraphic;
procedure SetPicture(const AValue: TPicture);
protected
procedure GetBlob(b: TfrTField); override;
public
constructor Create; override;
destructor Destroy; override;
procedure Assign(From: TfrView); override;
procedure Draw(aCanvas: TCanvas); override;
procedure LoadFromStream(Stream: TStream); override;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SaveToStream(Stream: TStream); override;
procedure SaveToXML(XML: TLrXMLConfig; Path: String); override;
procedure DefinePopupMenu(Popup: TPopupMenu); override;
class function GetFilter: string;
published
property Picture : TPicture read fPicture write SetPicture;
property Memo;
property Script;
property Frames;
property FrameColor;
property FrameStyle;
property FrameWidth;
property Stretched;
end;
TfrLineView = class(TfrView)
public
constructor Create; override;
procedure Draw(aCanvas: TCanvas); override;
procedure DefinePopupMenu(Popup: TPopupMenu); override;
function GetClipRgn(rt: TfrRgnType): HRGN; override;
published
property FrameColor;
property FrameStyle;
property FrameWidth;
end;
TfrRect = Class(TPersistent)
private
fBottom: Integer;
fLeft: Integer;
fRight: Integer;
fTop: Integer;
function GetRect: TRect;
procedure SetRect(const AValue: TRect);
public
property AsRect : TRect read GetRect write SetRect;
published
property Left : Integer read fLeft write fLeft;
property Top : Integer read fTop write fTop;
property Right: Integer read fRight write fRight;
property Bottom : Integer read fBottom write fBottom;
end;
TfrBand = class(TfrObject)
private
Parent: TfrPage;
View: TfrView;
Flags: Word;
Next, Prev: TfrBand;
SubIndex, MaxY: Integer;
EOFReached: Boolean;
EOFArr: Array[0..31] of Boolean;
Positions: Array[TfrDatasetPosition] of Integer;
LastGroupValue: Variant;
HeaderBand, FooterBand, LastBand: TfrBand;
Values: TStringList;
Count: Integer;
DisableInit: Boolean;
CalculatedHeight: Integer;
procedure InitDataSet(Desc: String);
procedure DoError;
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;
public
maxdy: Integer;
Typ: TfrBandType;
PrintIfSubsetEmpty, NewPageAfter, Stretched, PageBreak: Boolean;
Objects: TList;
DataSet: TfrDataSet;
IsVirtualDS: Boolean;
VCDataSet: TfrDataSet;
IsVirtualVCDS: Boolean;
GroupCondition: String;
ForceNewPage, ForceNewColumn: Boolean;
constructor Create(ATyp: TfrBandType; AParent: TfrPage); overload;
destructor Destroy; override;
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; Path: String);
procedure WriteBinaryData(Stream: TStream);
procedure WriteBinaryDataToXML(XML: TLrXMLConfig; Path: String);
procedure Clear;
property Items: TStringList read FItems write FItems;
property Objects[Index: Integer]: TfrValue read GetValue;
end;
{ TfrPage }
TfrPage = class(TfrObject)
private
Bands : Array[TfrBandType] of TfrBand;
fColCount : Integer;
fColGap : Integer;
fColWidth : Integer;
fMargins : TfrRect;
fOrientation : TPrinterOrientation;
fPrintToPrevPage : Boolean;
fUseMargins : Boolean;
Skip : Boolean;
InitFlag : Boolean;
CurColumn : Integer;
LastStaticColumnY : Integer;
XAdjust : Integer;
List : TList;
Mode : TfrPageMode;
PlayFrom : Integer;
LastBand : TfrBand;
ColPos : Integer;
CurPos : Integer;
PageType : TfrPageType;
fLayoutOrder : TLayoutOrder;
procedure DoAggregate(a: Array of TfrBandType);
procedure AddRecord(b: TfrBand; rt: TfrBandRecType);
procedure ClearRecList;
function PlayRecList: Boolean;
procedure DrawPageFooters;
function BandExists(b: TfrBand): Boolean;
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
procedure ShowBand(b: TfrBand);
protected
procedure InitReport; virtual;
procedure DoneReport; virtual;
procedure TossObjects; virtual;
procedure PrepareObjects; virtual;
procedure FormPage; virtual;
procedure AfterPrint; virtual;
public
pgSize : Integer;
PrnInfo : TfrPrnInfo;
Objects : TList;
RTObjects : TList;
CurY : Integer;
CurBottomY: Integer;
constructor Create; override;
destructor Destroy; override;
constructor Create(ASize, AWidth, AHeight: Integer; AOr: TPrinterOrientation);
constructor CreatePage; virtual;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SavetoXML(XML: TLrXMLConfig; 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(aName: String): TfrObject;
procedure ChangePaper(ASize, AWidth, AHeight: Integer; AOr: TPrinterOrientation);
procedure ShowBandByName(s: String);
procedure ShowBandByType(bt: TfrBandType);
procedure NewPage;
procedure NewColumn(Band: TfrBand);
procedure NextColumn(Band: TFrBand);
function RowsLayout: 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;
published
property Script;
property Height;
property Width;
end;
TFrPageClass = Class of TfrPage;
{ TfrPageReport }
TfrPageReport = Class(TfrPage)
public
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SavetoXML(XML: TLrXMLConfig; 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;
protected
procedure PrepareObjects; override;
procedure InitReport; override;
public
constructor Create; override;
procedure LoadFromXML(XML: TLrXMLConfig; Path: String); override;
procedure SavetoXML(XML: TLrXMLConfig; Path: String); override;
published
property Caption : string read fCaption write fCaption;
end;
{ TfrPages }
TfrPages = class(TObject)
private
FPages: TList;
Parent: TfrReport;
function GetCount: Integer;
function GetPages(Index: Integer): TfrPage;
public
constructor Create(AParent: TfrReport);
destructor Destroy; override;
procedure Clear;
procedure Add(aClassName : string='TfrPageReport');
procedure Delete(Index: Integer);
procedure LoadFromStream(Stream: TStream);
procedure LoadFromXML(XML: TLrXMLConfig; Path: String);
procedure SaveToStream(Stream: TStream);
procedure SavetoXML(XML: TLrXMLConfig; Path: String);
property Pages[Index: Integer]: TfrPage read GetPages; default;
property Count: Integer read GetCount;
end;
{ TfrEMFPages }
TfrEMFPages = class(TObject)
private
FPages: TList;
Parent: TfrReport;
function GetCount: Integer;
function GetPages(Index: Integer): PfrPageInfo;
procedure ExportData(Index: Integer);
procedure PageToObjects(Index: Integer);
procedure ObjectsToPage(Index: Integer);
public
constructor Create(AParent: TfrReport);
destructor Destroy; override;
procedure Clear;
procedure Draw(Index: Integer; Canvas: TCanvas; DrawRect: TRect);
procedure Add(APage: TfrPage);
procedure Insert(Index: Integer; APage: TfrPage);
procedure Delete(Index: Integer);
procedure LoadFromStream(AStream: TStream);
procedure LoadFromXML(XML: TLrXMLConfig; Path: String);
procedure SaveToStream(AStream: TStream);
procedure SaveToXML(XML: TLrXMLConfig; Path: String);
property Pages[Index: Integer]: PfrPageInfo read GetPages; default;
property Count: Integer read GetCount;
end;
TfrDataType = (dtDataSet,dtDataSource);
{ TfrReport }
TfrReport = class(TComponent)
private
FDataType: TfrDataType;
FPages: TfrPages;
FEMFPages: TfrEMFPages;
FReportAutor: string;
FReportCreateDate: TDateTime;
FReportLastChange: TDateTime;
FReportVersionBuild: string;
FReportVersionMajor: string;
FReportVersionMinor: string;
FReportVersionRelease: string;
FVars: TStrings;
FVal: TfrValues;
FDataset: TfrDataset;
FGrayedButtons: Boolean;
FReportType: TfrReportType;
FShowProgress: Boolean;
FModalPreview: Boolean;
FModifyPrepared: Boolean;
FStoreInDFM: 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;
function FormatValue(V: Variant; AFormat: Integer; const AFormatStr: String): String;
// function GetLRTitle: String;
procedure OnGetParsFunction(const aName: String; p1, p2, p3: Variant;
var val: Variant);
procedure PrepareDataSets;
procedure BuildBeforeModal(Sender: TObject);
procedure ExportBeforeModal(Sender: TObject);
procedure PrintBeforeModal(Sender: TObject);
function DoPrepareReport: Boolean;
procedure DoBuildReport; virtual;
procedure DoPrintReport(PageNumbers: String; Copies: Integer);
procedure SetComments(const AValue: TStringList);
procedure SetDataset(const AValue: TfrDataset);
procedure SetPrinterTo(PrnName: String);
procedure SetReportAutor(const AValue: string);
procedure SetReportCreateDate(const AValue: TDateTime);
procedure SetReportLastChange(const AValue: TDateTime);
procedure SetReportVersionBuild(const AValue: string);
procedure SetReportVersionMajor(const AValue: string);
procedure SetReportVersionMinor(const AValue: string);
procedure SetReportVersionRelease(const AValue: string);
procedure SetVars(Value: TStrings);
procedure ClearAttribs;
protected
procedure DefineProperties(Filer: TFiler); override;
procedure ReadBinaryData(Stream: TStream);
procedure WriteBinaryData(Stream: TStream);
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
CanRebuild : Boolean; // true, if report can be rebuilded
Terminated : Boolean;
PrintToDefault, DoublePass: WordBool;
FinalPass : Boolean;
FileName : String;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear;
// service methods
function FindVariable(Variable: String): Integer;
procedure GetVariableValue(const s: String; var aValue: Variant);
procedure GetVarList(CatNo: Integer; List: TStrings);
procedure GetCategoryList(List: TStrings);
function FindObject(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 InternalOnGetValue(ParName: String; var ParValue: String);
procedure InternalOnProgress(Percent: Integer);
procedure InternalOnBeginColumn(Band: TfrBand);
procedure InternalOnPrintColumn(ColNo: Integer; var ColWidth: Integer);
procedure FillQueryParams;
// load/save methods
procedure LoadFromStream(Stream: TStream);
procedure LoadFromXML(XML: TLrXMLConfig; Path: String);
procedure SaveToStream(Stream: TStream);
procedure LoadFromFile(FName: String);
procedure LoadFromXMLFile(Fname: String);
procedure SaveToFile(FName: String);
procedure SavetoXML(XML: TLrXMLConfig; Path: String);
procedure SaveToXMLFile(FName: String);
procedure LoadFromDB(Table: TDataSet; DocN: Integer);
procedure SaveToDB(Table: TDataSet; DocN: Integer);
procedure LoadTemplate(fname: String; comm: TStrings;
Bmp: TBitmap; Load: Boolean);
procedure SaveTemplate(fname: String; comm: TStrings; Bmp: TBitmap);
procedure LoadPreparedReport(FName: String);
procedure SavePreparedReport(FName: String);
// report manipulation methods
procedure DesignReport;
function PrepareReport: Boolean;
procedure ExportTo(Filter: TClass; aFileName: String);
procedure ShowReport;
procedure ShowPreparedReport;
procedure PrintPreparedReport(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 SetReportAutor;
property ReportVersionMajor : string read FReportVersionMajor write SetReportVersionMajor;
property ReportVersionMinor : string read FReportVersionMinor write SetReportVersionMinor;
property ReportVersionRelease : string read FReportVersionRelease write SetReportVersionRelease;
property ReportVersionBuild : string read FReportVersionBuild write SetReportVersionBuild;
property ReportCreateDate : TDateTime read FReportCreateDate write SetReportCreateDate;
property ReportLastChange : TDateTime read FReportLastChange write SetReportLastChange;
//
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;
published
property Dataset: TfrDataset read FDataset write SetDataset;
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 Preview: TfrPreview read FPreview write FPreview;
property PreviewButtons: TfrPreviewButtons read FPreviewButtons write FPreviewButtons;
property ReportType: TfrReportType read FReportType write FReportType default rtSimple;
property ShowProgress: Boolean read FShowProgress write FShowProgress default True;
property StoreInDFM: Boolean read FStoreInDFM write FStoreInDFM 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;
end;
TfrCompositeReport = class(TfrReport)
private
procedure DoBuildReport; override;
public
Reports: TList;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
TfrReportDesigner = class(TForm)
public
Page: TfrPage;
Modified: Boolean;
procedure RegisterObject(ButtonBmp: TBitmap; const ButtonHint: String;
ButtonTag: Integer); virtual; abstract;
procedure RegisterTool(MenuCaption: String; ButtonBmp: TBitmap;
NotifyOnClick: TNotifyEvent); virtual; abstract;
procedure BeforeChange; virtual; abstract;
procedure AfterChange; virtual; abstract;
procedure RedrawPage; virtual; abstract;
//
function PointsToUnits(x: Integer): Double; virtual; abstract;
function UnitsToPoints(x: Double): Integer; virtual; abstract;
end;
TfrDataManager = class(TObject)
public
procedure Clear; virtual; abstract;
procedure LoadFromStream(Stream: TStream); virtual; abstract;
procedure LoadFromXML(XML:TLrXMLConfig; Path: String); virtual; abstract;
procedure SaveToStream(Stream: TStream); virtual; abstract;
procedure SaveToXML(XML:TLrXMLConfig; 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(t: TfrView); virtual;
end;
TfrExportFilter = class(TObject)
protected
Stream: TStream;
Lines: TList;
procedure ClearLines;
public
constructor Create(AStream: TStream); virtual;
destructor Destroy; override;
procedure OnBeginDoc; virtual;
procedure OnEndDoc; virtual;
procedure OnBeginPage; virtual;
procedure OnEndPage; virtual;
procedure OnData(x, y: Integer; View: TfrView); virtual;
procedure OnText(x, y: Integer; const text: String; View: TfrView); virtual;
end;
TfrFunctionDescription = class(TObject)
funName:string;
funGroup:string;
funDescription:string;
end;
{ TfrFunctionLibrary }
TfrFunctionLibrary = class(TObject)
public
List: TStringList;
constructor Create; virtual;
destructor Destroy; override;
function OnFunction(const FName: String; p1, p2, p3: Variant;
var val: Variant): Boolean;
procedure DoFunction(FNo: Integer; p1, p2, p3: Variant; var val: Variant);
virtual; abstract;
procedure AddFunctionDesc(funName, funGroup, funDescription:string);
end;
TfrCompressor = class(TObject)
public
Enabled: Boolean;
procedure Compress(StreamIn, StreamOut: TStream); virtual;
procedure DeCompress(StreamIn, StreamOut: TStream); virtual;
end;
function frCreateObject(Typ: Byte; const ClassName: String): TfrView;
procedure frRegisterObject(ClassRef: TFRViewClass; ButtonBmp: TBitmap;
const ButtonHint: String; EditorForm: TfrObjEditorForm);
procedure frRegisterExportFilter(ClassRef: TClass;
const FilterDesc, FilterExt: String);
procedure frRegisterFunctionLibrary(ClassRef: TClass);
procedure frRegisterTool(MenuCaption: String; ButtonBmp: TBitmap; OnClick: TNotifyEvent);
function GetDefaultDataSet: TfrTDataSet;
procedure SetBit(var w: Word; e: Boolean; m: Integer);
const
frCurrentVersion = 24; // this is current version (2.4)
frSpecCount = 9;
frSpecFuncs: Array[0..frSpecCount - 1] of String = ('PAGE#', '',
'DATE', 'TIME', 'LINE#', 'LINETHROUGH#', 'COLUMN#', 'CURRENT#', 'TOTALPAGES');
frColors: Array[0..15] of TColor =
(clWhite, clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal,
clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua);
frAllFrames=[frbLeft, frbTop, frbRight, frbBottom];
frUnwrapRead: boolean = false; // TODO: remove this for 0.9.28
type
PfrTextRec = ^TfrTextRec;
TfrTextRec = record
Next: PfrTextRec;
X: Integer;
Text: String[255];
FontName: String[32];
FontSize, FontStyle, FontColor, FontCharset, FillColor: Integer;
end;
TfrAddInObjectInfo = record
ClassRef: TfrViewClass;
EditorForm: TfrObjEditorForm;
ButtonBmp: TBitmap;
ButtonHint: String;
end;
TfrExportFilterInfo = record
ClassRef: TClass;
FilterDesc, FilterExt: String;
end;
TfrFunctionInfo = record
FunctionLibrary: TfrFunctionLibrary;
end;
TfrToolsInfo = record
Caption: String;
ButtonBmp: TBitmap;
OnClick: TNotifyEvent;
end;
var
frDesigner: TfrReportDesigner; // designer reference
frDataManager: TfrDataManager; // data manager reference
frParser: TfrParser; // parser reference
frInterpretator: TfrInterpretator; // interpretator reference
frVariables: TfrVariables; // report variables reference
frCompressor: TfrCompressor; // compressor reference
CurReport: TfrReport; // currently proceeded report
MasterReport: TfrReport; // reference to main composite report
CurView: TfrView; // currently proceeded view
CurBand: TfrBand; // currently proceeded band
CurPage: TfrPage; // currently proceeded page
DocMode: (dmDesigning, dmPrinting); // current mode
DisableDrawing: Boolean;
frAddIns: Array[0..31] of TfrAddInObjectInfo; // add-in objects
frAddInsCount: Integer;
frFilters: Array[0..31] of TfrExportFilterInfo; // export filters
frFiltersCount: Integer;
frFunctions: Array[0..31] of TfrFunctionInfo; // function libraries
frFunctionsCount: Integer;
frTools: Array[0..31] of TfrToolsInfo; // tools
frToolsCount: Integer;
PageNo: Integer; // current page number in Building mode
frCharset: 0..255;
frBandNames: Array[btReportTitle..btNone] of String;
frSpecArr: Array[0..frSpecCount - 1] of String;
frDateFormats, frTimeFormats: Array[0..3] of String;
frVersion: Byte; // version of currently loaded report
SMemo: TStringList; // temporary memo used during TfrView drawing
ShowBandTitles: Boolean = True;
ProcedureInitDesigner : Procedure = nil;
(*
FRE_COMPATIBLEREAD variable added for migrating from older versions
of FreeReport and will be removed in next releases as soon as possible.
*)
{$IFDEF FREEREP2217READ}
FRE_COMPATIBLE_READ: Boolean = False;
{$ENDIF}
implementation
uses
LR_Fmted, LR_Prntr, LR_Progr, LR_Utils, DateUtils
{$IFDEF JPEG}, JPEG {$ENDIF};
type
TfrStdFunctionLibrary = class(TfrFunctionLibrary)
public
constructor Create; override;
procedure DoFunction(FNo: Integer; p1, p2, p3: Variant; var val: Variant); override;
end;
TInterpretator = class(TfrInterpretator)
public
procedure GetValue(const Name: String; var Value: Variant); override;
procedure SetValue(const Name: String; Value: Variant); override;
procedure DoFunction(const name: String; p1, p2, p3: Variant;
var val: Variant); override;
end;
var
VHeight: Integer; // used for height calculation of TfrMemoView
SBmp: TBitmap; // small bitmap used by TfrBandView drawing
TempBmp: TBitmap; // temporary bitmap used by TfrMemoView
CurDate, CurTime: TDateTime; // date/time of report starting
CurValue: Variant; // used for highlighting
AggrBand: TfrBand; // 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: TList;
FRInitialized: Boolean = False;
// variables used through report building
PrevY, PrevBottomY, ColumnXAdjust: Integer;
Append, WasPF: Boolean;
CompositeMode: Boolean;
{$IFDEF DebugLR}
var
nspc: integer = 0;
sspc: string = '';
procedure IncSpc(aInc:Integer);
begin
nspc := nspc + aInc;
if nspc<0 then
nspc := 0;
//WriteLn('[',nspc,']');
SetLength(sspc, nspc*2);
if aInc>0 then
fillchar(sspc[1], nspc*2, ' ');
end;
function typ2str(typ: TfrBandType): string;
begin
case typ of
btReportTitle: result := 'btReportTitle';
btReportSummary: result := 'btReportSummary';
btPageHeader: result := 'btPageHeader';
btPageFooter: result := 'btPageFooter';
btMasterHeader: result := 'btMasterHeader';
btMasterData: result := 'btMasterData';
btMasterFooter: result := 'btMasterFooter';
btDetailHeader: result := 'btDetailHeader';
btDetailData: result := 'btDetailData';
btDetailFooter: result := 'btDetailFooter';
btSubDetailHeader: result := 'btSubDetailHeader';
btSubDetailData: result := 'btSubDetailData';
btSubDetailFooter: result := 'btSubDetailFooter';
btOverlay: result := 'btOverlay';
btColumnHeader: result := 'btColumnHeader';
btColumnFooter: result := 'btColumnFooter';
btGroupHeader: result := 'btGroupHeader';
btGroupFooter: result := 'btGroupFooter';
btCrossHeader: result := 'btCrossHeader';
btCrossData: result := 'btCrossData';
btCrossFooter: result := 'btCrossFooter';
btNone: result:='btNone';
end;
end;
{$ENDIF}
{----------------------------------------------------------------------------}
function frCreateObject(Typ: Byte; const ClassName: String): TfrView;
var
i: Integer;
begin
Result := nil;
case Typ of
gtMemo: Result := TfrMemoView.Create;
gtPicture: Result := TfrPictureView.Create;
gtBand: Result := TfrBandView.Create;
gtSubReport: Result := TfrSubReportView.Create;
gtLine: Result := TfrLineView.Create;
gtAddIn:
begin
for i := 0 to frAddInsCount - 1 do
begin
{$IFDEF DebugLR}
DebugLn(format('frCreateObject classname compare %s=%s',[frAddIns[i].ClassRef.ClassName,ClassName]));
{$ENDIF}
if frAddIns[i].ClassRef.ClassName = ClassName then
begin
Result := frAddIns[i].ClassRef.Create;
// 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(format('frCreateObject instance classname=%s',[ClassName]));
{$ENDIF}
Result.ID := ObjID;
Inc(ObjID);
end;
end;
procedure frRegisterObject(ClassRef: TfrViewClass; ButtonBmp: TBitmap;
const ButtonHint: String; EditorForm: TfrObjEditorForm);
begin
frAddIns[frAddInsCount].ClassRef := ClassRef;
frAddIns[frAddInsCount].EditorForm := EditorForm;
frAddIns[frAddInsCount].ButtonBmp := ButtonBmp;
frAddIns[frAddInsCount].ButtonHint := ButtonHint;
if frDesigner <> nil then
frDesigner.RegisterObject(ButtonBmp, ButtonHint,
Integer(gtAddIn) + frAddInsCount);
Inc(frAddInsCount);
end;
procedure frRegisterExportFilter(ClassRef: TClass;
const FilterDesc, FilterExt: String);
begin
frFilters[frFiltersCount].ClassRef := ClassRef;
frFilters[frFiltersCount].FilterDesc := FilterDesc;
frFilters[frFiltersCount].FilterExt := FilterExt;
Inc(frFiltersCount);
end;
procedure frRegisterFunctionLibrary(ClassRef: TClass);
begin
frFunctions[frFunctionsCount].FunctionLibrary :=
TfrFunctionLibrary(ClassRef.NewInstance);
frFunctions[frFunctionsCount].FunctionLibrary.Create;
Inc(frFunctionsCount);
end;
procedure frRegisterTool(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
Res: TfrDataset;
begin
Result := nil; Res := nil;
if CurBand <> nil then
case CurBand.Typ of
btMasterData, btReportSummary, btMasterFooter,
btGroupHeader, btGroupFooter:
Res := CurPage.Bands[btMasterData].DataSet;
btDetailData, btDetailFooter:
Res := CurPage.Bands[btDetailData].DataSet;
btSubDetailData, btSubDetailFooter:
Res := CurPage.Bands[btSubDetailData].DataSet;
btCrossData, btCrossFooter:
Res := CurPage.Bands[btCrossData].DataSet;
end;
if (Res <> nil) and (Res is TfrDBDataset) then
Result := TfrDBDataSet(Res).GetDataSet;
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(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(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;
{----------------------------------------------------------------------------}
constructor TfrView.Create;
begin
inherited Create;
Parent := nil;
Memo1 := TStringList.Create;
fFrameWidth := 1;
fFrameColor := clBlack;
fFillColor := clNone;
fFormat := 2*256 + Ord(DecimalSeparator);
BaseName := 'View';
Visible := True;
StreamMode := smDesigning;
ScaleX := 1;
ScaleY := 1;
OffsX := 0;
OffsY := 0;
Flags := flStretched;
fStretched:=True;
fFrames:=[]; //No frame
end;
destructor TfrView.Destroy;
begin
Memo1.Free;
inherited Destroy;
end;
procedure TfrView.Assign(From: TfrView);
begin
Inherited Assign(From);
Name := From.Name;
Typ := From.Typ;
Selected := From.Selected;
Flags := From.Flags;
fFrameWidth := From.FrameWidth;
fFrameColor := From.FrameColor;
fFrameStyle := From.FrameStyle;
fFillColor := From.FillColor;
fFormat := From.Format;
fFormatStr := From.FormatStr;
fVisible := From.Visible;
fFrames:=From.Frames;
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);
{$IFDEF DebugLR}
DebugLn('CalcGaps: dx=',dbgs(dx),' ScaleX=',dbgs(ScaleX));
{$ENDIF}
fFrameWidth := FrameWidth * ScaleX;
gapx := wx2 + 2;
gapy := wy2 div 2 + 1;
bx := x;
by := y;
bx1 := Round((SaveX + SaveDX) * ScaleX + OffsX);
by1 := Round((SaveY + SaveDY) * ScaleY + OffsY);
if frbTop in Frames then Dec(bx1, wx2);
if frbLeft in Frames then Dec(by1, wy2);
if frbBottom in Frames then Inc(bx, wx1);
if frbRight in Frames then Inc(by, wy1);
DRect := Rect(bx, by, bx1 + 1, by1 + 1);
end;
procedure TfrView.RestoreCoord;
begin
x := SaveX;
y := SaveY;
dx := SaveDX;
dy := SaveDY;
fFrameWidth := SaveFW;
end;
procedure TfrView.ShowBackground;
var
fp: TColor;
begin
if DisableDrawing then Exit;
if (DocMode = dmPrinting) and (FillColor = clNone) then Exit;
fp := FillColor;
if (DocMode = dmDesigning) and (fp = clNone) then
fp := clWhite;
Canvas.Brush.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);
begin
{$IFDEF DebugLR}
DebugLn('%s%s.TfrView.Print()',[sspc,name]);
{$ENDIF}
BeginDraw(Canvas);
Memo1.Assign(Memo);
CurReport.InternalOnEnterRect(Memo1, Self);
frInterpretator.DoScript(Script);
if not Visible then Exit;
Stream.Write(Typ, 1);
if Typ = gtAddIn then
frWriteString(Stream, ClassName);
SaveToStream(Stream);
{$IFDEF DebugLR}
DebugLn('%s%s.TfrView.Print() end',[sspc,name]);
{$ENDIF}
end;
procedure TfrView.ExportData;
begin
CurReport.InternalOnExportData(Self);
end;
procedure TfrView.LoadFromStream(Stream: TStream);
var
wb : Word;
S : Single;
begin
{$IFDEF DebugLR}
DebugLn('%s%s.TfrView.LoadFromStream begin StreamMode=%d ClassName=%s',
[sspc,name,Ord(StreamMode),ClassName]);
{$ENDIF}
with Stream do
begin
if StreamMode = smDesigning then
begin
if frVersion >= 23 then
Name := ReadString(Stream)
else
CreateUniqueName;
end;
//Read(x, 18); // this is equal to, but much faster:
Read(x, 4);
Read(y, 4);
Read(dx, 4);
Read(dy, 4);
Read(Flags, 2);
Read(S, SizeOf(S)); fFrameWidth := S;
Read(fFrameColor, SizeOf(fFrameColor));
Read(fFrames,SizeOf(fFrames));
Read(fFrameStyle, SizeOf(fFrameStyle));
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);
Read(wb,2);
Visible:=(Wb<>0);
end;
end;
{$IFDEF DebugLR}
DebugLn('%s%s.TfrView.LoadFromStream end',[sspc,name]);
{$ENDIF}
end;
procedure TfrView.LoadFromXML(XML: TLrXMLConfig; Path: String);
var
S:string;
begin
inherited LoadFromXML(XML,Path);
StreamMode := TfrStreamMode(XML.GetValue(Path+'StreamMode/Value', 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', 0);
y := XML.GetValue(Path + 'Size/Top/Value', 0);
dx := XML.GetValue(Path + 'Size/Width/Value', 100);
dy := XML.GetValue(Path + 'Size/Height/Value', 100);
Flags := Word(XML.GetValue(Path + 'Flags/Value', 0)); // TODO Check default
FFrameWidth := StringToFloatDef(XML.GetValue(Path+'Frames/FrameWidth/Value', ''), 1.0);
FFramecolor := StringToColor(XML.GetValue(Path+'Frames/FrameColor/Value', 'clBlack')); // TODO Check default
S:=XML.GetValue(Path+'Frames/FrameBorders/Value','');
if S<>'' then
RestoreProperty('Frames',S);
S:=XML.GetValue(Path+'Frames/FrameStyle/Value','');
if S<>'' then
RestoreProperty('FrameStyle',S);
FFillColor := StringToColor(XML.GetValue(Path+'FillColor/Value', 'clWindow')); // TODO Check default
if StreamMode = smDesigning then
begin
fFormat := XML.GetValue(Path+'Data/Format/Value', 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
end;
procedure TfrView.SaveToStream(Stream: TStream);
var
S: Single;
begin
{$IFDEF DebugLR}
DebugLn('%s%s.SaveToStream begin',[sspc,name]);
{$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);
end;
{$IFDEF DebugLR}
Debugln('%s%s.SaveToStream end',[sspc,name]);
{$ENDIF}
end;
procedure TfrView.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
inherited SaveToXML(XML,Path);
XML.SetValue(Path+'Typ/Value', frTypeObjectToStr(Typ));
XML.SetValue(Path+'StreamMode/Value', Ord(StreamMode)); //todo: use symbolic valuess
XML.SetValue(Path+'Size/Left/Value', x);
XML.SetValue(Path+'Size/Top/Value', y);
XML.SetValue(Path+'Size/Width/Value', dx);
XML.SetValue(Path+'Size/Height/Value', dy);
XML.SetValue(Path+'Flags/Value', 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', 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);
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) then
frDesigner.BeforeChange;
end;
procedure TfrView.AfterChange;
begin
if (frDesigner<>nil) and (fUpdate=0) then
frDesigner.AfterChange;
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 := (Flags and flStretched) <> 0;
Popup.Items.Add(m);
end;
procedure TfrView.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 flStretched) + Word(Checked);
end;
end;
frDesigner.AfterChange;
end;
function TfrView.GetLeft: Double;
begin
if frDesigner<>nil then
result := frDesigner.PointsToUnits(x)
else
result := x;
end;
function TfrView.GetHeight: Double;
begin
if frDesigner<>nil then
result := frDesigner.PointsToUnits(dy)
else
result := dy;
end;
function TfrView.GetTop: Double;
begin
if frDesigner<>nil then
result := frDesigner.PointsToUnits(y)
else
result := y;
end;
function TfrView.GetWidth: Double;
begin
if frDesigner<>nil then
result := frDesigner.PointsToUnits(dx)
else
result := dx;
end;
procedure TfrView.SetFillColor(const AValue: TColor);
begin
if (aValue<>fFillColor) and (fUpdate=0) 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) and (fUpdate=0) 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 fStretched<>AValue then
begin
BeforeChange;
fStretched := AValue;
AfterChange;
end;
end;
procedure TfrView.SetTop(const AValue: Double);
begin
if frDesigner<>nil then begin
BeforeChange;
y := frDesigner.UnitsToPoints(AValue);
AfterChange;
end else
y := round(AValue);
end;
procedure TfrView.SetWidth(const AValue: Double);
begin
if frDesigner<>nil then begin
BeforeChange;
dx := frDesigner.UnitsToPoints(AValue);
AfterChange;
end else
dx := round(AValue);
end;
{----------------------------------------------------------------------------}
constructor TfrMemoView.Create;
begin
inherited Create;
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;
fAngle :=0;
end;
destructor TfrMemoView.Destroy;
begin
FFont.Free;
inherited Destroy;
end;
procedure TfrMemoView.SetFont(Value: TFont);
begin
BeforeChange;
fFont.Assign(Value);
AfterChange;
end;
procedure TfrMemoView.SetLayout(const AValue: TTextLayout);
begin
if Layout<>AValue then
begin
BeforeChange;
Adjust := (Adjust and %11100111) or (ord(AValue) shl 3);
AfterChange;
end;
end;
procedure TfrMemoView.SetWordWrap(const AValue: Boolean);
begin
if WordWrap<>AValue then
begin
BeforeChange;
SetBit(Flags, AValue, flWordWrap);
AfterChange;
end;
end;
procedure TfrMemoView.Assign(From: TfrView);
begin
inherited Assign(From);
FFont.Assign(TfrMemoView(From).Font);
Adjust := TfrMemoView(From).Adjust;
Highlight := TfrMemoView(From).Highlight;
HighlightStr := TfrMemoView(From).HighlightStr;
LineSpacing := TfrMemoView(From).LineSpacing;
end;
procedure TfrMemoView.ExpandVariables;
var
i: Integer;
procedure GetData(var s: String);
var
i, j: Integer;
s1, s2: String;
begin
i := 1;
repeat
while (i < Length(s)) and (s[i] <> '[') do Inc(i);
s1 := GetBrackedVariable(s, i, j);
if i <> j then
begin
Delete(s, i, j - i + 1);
s2 := '';
CurReport.InternalOnGetValue(s1, s2);
Insert(s2, s, i);
Inc(i, Length(s2));
j := 0;
end;
until i = j;
end;
var
s: string;
begin
Memo1.Clear;
for i := 0 to Memo.Count - 1 do
begin
s := Memo[i];
if Length(s) > 0 then
begin
GetData(s);
// WORKAROUND: FPC BUG, setting Memo1.Text=char doesn't work
if (Length(s)=1)and(Length(Memo1.Text)=0) then
Memo1.Add(s)
else
Memo1.Text := Memo1.Text + s;
end
else
Memo1.Add('');
end;
end;
procedure TfrMemoView.AssignFont(aCanvas: TCanvas);
begin
with aCanvas do
begin
{$IFDEF DebugLR}
DebugLn('AssignFont('+self.Font.Name+')');
{$ENDIF}
//** Brush.Style := bsClear;
Font.Assign(Self.Font);
//Font := Self.Font;
if not IsPrinting and (ScaleY<>0) then
Font.Height := -Round(Font.Size * 96 / 72 * ScaleY);
end;
end;
type
TWordBreaks = string;
const
gl: set of Char = ['<27>', '<27>', '<27>', '<27>', '<27>', '<27>', '<27>', '<27>', '<27>', '<27>'];
r_sogl: set of Char = ['<27>', '<27>'];
spaces: set of Char = [' ', '.', ',', '-'];
function BreakWord(s: String): TWordBreaks;
var
i: Integer;
CanBreak: Boolean;
begin
Result := '';
s := AnsiUpperCase(s);
if Length(s) > 4 then
begin
i := 2;
repeat
CanBreak := False;
if s[i] in gl then
begin
if (s[i + 1] in gl) or (s[i + 2] in gl) then CanBreak := True;
end
else
begin
if not (s[i + 1] in gl) and not (s[i + 1] in r_sogl) and
(s[i + 2] in gl) then
CanBreak := True;
end;
if CanBreak then
Result := Result + Chr(i);
Inc(i);
until i > Length(s) - 2;
end;
{$IFDEF DebugLR}
debugLn(' breakword: s=',dbgstr(s),' result=',dbgstr(result));
{$ENDIF}
end;
procedure TfrMemoView.WrapMemo;
var
size, size1, maxwidth: Integer;
b: TWordBreaks;
WCanvas: TCanvas;
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}
debugLn(' Outline: str="',dbgstr(str),'" w/=',dbgs(w div 256),' w%=',dbgs(w mod 256));
{$ENDIF}
SMemo.Add(str + Chr(w div 256) + Chr(w mod 256));
Inc(size, size1);
end;
procedure WrapLine(const s: String);
var
i, cur, beg, last: Integer;
WasBreak, CRLF: Boolean;
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;
{$IFDEF DebugLR}
debugLn(' WrapLine: init "',dbgstr(s),'" wcanvas.txtw=',dbgs(WCanvas.TextWidth(s)),
' maxwidth=',dbgs(maxwidth),' crlf=',dbgs(crlf));
{$ENDIF}
if not CRLF and ((Length(s) <= 1) or (WCanvas.TextWidth(s) <= maxwidth)) then
begin
{$IFDEF DebugLR}
debugLn(' WrapLine: fast crlf=',dbgs(crlf),' wcanvas.txtw=',dbgs(Wcanvas.TextWidth(s)));
{$ENDIF}
OutLine(s + #1)
end else
begin
cur := 1;
while cur <= Length(s) do
begin
if s[cur] in [#10, #13] then
begin
{$IFDEF DebugLR}
debugLn(' Wrapline: crlf beg=',dbgs(beg),' cur=',dbgs(cur));
{$ENDIF}
OutLine(Copy(s, beg, cur - beg) + #1);
while (cur < Length(s)) and (s[cur] in [#10, #13]) do Inc(cur);
beg := cur; last := beg;
if s[cur] in [#13, #10] then begin
{$IFDEF DebugLR}
debugln(' Wrapline: Exiting as cur is in crlf cur=',dbgs(cur));
{$ENDIF}
Exit;
end else
continue;
end;
if s[cur] <> ' ' then
if WCanvas.TextWidth(Copy(s, beg, cur - beg + 1)) > maxwidth then
begin
WasBreak := False;
if (Flags and flWordBreak) <> 0 then
begin
i := cur;
while (i <= Length(s)) and not (s[i] in spaces) do
Inc(i);
{$IFDEF DebugLR}
debugln(' wrapline: to BreakWord: ini=',dbgs(last+1),' fin=',dbgs(i-last-1));
{$ENDIF}
b := BreakWord(Copy(s, last + 1, i - last - 1));
if Length(b) > 0 then
begin
i := 1;
cur := last;
while (i <= Length(b)) and
(WCanvas.TextWidth(Copy(s, beg, last - beg + 1 + Ord(b[i])) + '-') <= maxwidth) do
begin
WasBreak := True;
cur := last + Ord(b[i]);
Inc(i);
end;
last := cur;
end;
end
else
if last = beg then last := cur;
if WasBreak then begin
{$IFDEF DebugLR}
debugln(' wrapline: wasbreak=true, beg=',dbgs(beg),' fin=',dbgs(last-beg+1));
{$ENDIF}
OutLine(Copy(s, beg, last - beg + 1) + '-');
end else if s[last] = ' ' then begin
{$IFDEF DebugLR}
debugln(' wrapline: s[last]=" ", beg=',dbgs(beg),' fin=',dbgs(last-beg));
{$ENDIF}
OutLine(Copy(s, beg, last - beg))
end else begin
{$IFDEF DebugLR}
debugln(' wrapline: s[last]<>" ", beg=',dbgs(beg),' fin=',dbgs(last-beg));
{$ENDIF}
OutLine(Copy(s, beg, last - beg + 1));
end;
if ((Flags and flWordBreak) <> 0) and not WasBreak and (last = cur) then
begin
beg := cur + 1;
cur := Length(s);
break;
end;
if (Flags and flWordBreak) = 0 then
begin
if last = cur then
begin
beg := cur;
break;
end;
end;
beg := last + 1; last := beg;
end;
if s[cur] in spaces then last := cur;
Inc(cur);
end;
if beg <> cur then begin
{$IFDEF DebugLR}
debugln(' wrapline: beg<>cur, beg=',dbgs(beg),' fin=',dbgs(cur-beg+1));
{$ENDIF}
OutLine(Copy(s, beg, cur - beg + 1) + #1);
end;
end;
end;
procedure OutMemo;
var
i: Integer;
begin
size := y + gapy;
size1 := -WCanvas.Font.Height + LineSpacing;
maxWidth := dx - gapx - gapx;
{$IFDEF DebugLR}
DebugLn(' OutMemo: Size=',dbgs(Size),' Size1=',dbgs(Size1),
' MaxWidth=',dbgs(MaxWidth),' dx=',dbgs(dx),' gapx=',dbgs(gapx));
{$ENDIF}
for i := 0 to Memo1.Count - 1 do
begin
if (Flags and flWordWrap) <> 0 then
WrapLine(Memo1[i])
else
OutLine(Memo1[i] + #1);
end;
VHeight := size - y + gapy;
TextHeight := size1;
end;
procedure OutMemo90;
var
i: Integer;
h, oldh: HFont;
begin
h := Create90Font(WCanvas.Font);
oldh := SelectObject(WCanvas.Handle, h);
size := x + gapx;
size1 := -WCanvas.Font.Height + LineSpacing;
maxwidth := dy - gapy - gapy;
for i := 0 to Memo1.Count - 1 do
begin
if (Flags and flWordWrap) <> 0 then
WrapLine(Memo1[i])
else
OutLine(Memo1[i]);
end;
SelectObject(WCanvas.Handle, oldh);
DeleteObject(h);
VHeight := size - x + gapx;
TextHeight := size1;
end;
begin
WCanvas := TempBmp.Canvas;
WCanvas.Font.Assign(Font);
WCanvas.Font.Height := -Round(Font.Size * 96 / 72);
{$IFDEF DebugLR}
DebugLn(' TfrMemoView.WrapMemo:',
' Font.PPI=', dbgs(Font.PixelsPerInch),
' Font.Size=', dbgs(Font.Size),
' Canvas.Font.PPI=',dbgs(Canvas.Font.PixelsPerInch),
' WCanvas.Font.Size=',dbgs(WCanvas.Font.Size));
{$ENDIF}
SetTextCharacterExtra(WCanvas.Handle, CharacterSpacing);
SMemo.Clear;
if Angle<>0 then
OutMemo90
else
OutMemo;
end;
var
DxArray: Array[0..2047] of Integer;
procedure TfrMemoView.ShowMemo;
var
DR : TRect;
SavX,SavY : Integer;
procedure OutMemo;
var
i, cury, th: Integer;
function OutLine(st: String): Boolean;
var
{$IFDEF DebugLR}
aw: Integer;
{$ENDIF}
n, nw, w, curx: Integer;
ParaEnd: Boolean;
Ts: TTextStyle;
begin
if not Streaming and (cury < DR.Bottom) then
begin
n := Length(St);
w := Ord(St[n - 1]) * 256 + Ord(St[n]);
SetLength(St, n - 2);
ParaEnd := True;
if Length(St) > 0 then
begin
if St[Length(St)] = #1 then
SetLength(St, Length(St) - 1)
else
ParaEnd := False;
end;
// handle any alignment with same code
AssignFont(Canvas);
Ts := Canvas.TextStyle;
Ts.Layout :=tlTop;
Ts.Alignment :=self.Alignment;
Ts.Wordbreak :=false;
Ts.SingleLine:=True;
Ts.Clipping :=True;
Canvas.TextStyle := Ts;
nw := Round(w * ScaleX); // needed width
{$IFDEF DebugLR}
DebugLn('2 Canvas.Font.Size=%d TextWidth=%d',[Canvas.Font.Size,Canvas.TextWidth(St)]);
{$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;
th := -Canvas.Font.Height+Round(LineSpacing * ScaleY);
{$IFDEF DebugLR}
DebugLn('Th=%d Canvas.TextHeight(H)=%d',[Th,Canvas.TextHeight('H')]);
Debugln('2 Canvas.Font.Size=%d TextWidth=%d',[Canvas.Font.Size,Canvas.TextWidth(St)]);
aw := Canvas.TextWidth(St); // actual width
DebugLn('nw=%d aw=%d',[nw,aw]);
{$ENDIF}
case Alignment of
Classes.taLeftJustify : CurX :=x+gapx;
Classes.taRightJustify: CurX :=x+dx-1-gapx-nw;
Classes.taCenter : CurX :=x+gapx+(dx-gapx-gapx-nw) div 2;
end;
if not Exporting then
Canvas.TextRect(DR, CurX, CurY, St)
else
CurReport.InternalOnExportText(curx, cury, St, Self);
Inc(CurStrNo);
Result := False;
end
else Result := True;
cury := cury + th;
end;
begin {OutMemo}
cury := y + gapy;
th := -Canvas.Font.Height+Round(LineSpacing * ScaleY);
{$IFDEF DebugLR}
DebugLn('Th=',IntToStr(Th),' Canvas.TextHeight(H)=',InttoStr(Canvas.TextHeight('H')), 'DR=',dbgs(DR));
{$ENDIF}
CurStrNo := 0;
for i := 0 to Memo1.Count - 1 do
if OutLine(Memo1[i]) then
break;
end;
procedure OutMemo90;
var
i, th, curx: Integer;
h, oldh: HFont;
procedure OutLine(str: String);
var
i, n, cury: Integer;
ParaEnd: Boolean;
begin
SetLength(str, Length(str) - 2);
if str[Length(str)] = #1 then
begin
ParaEnd := True;
SetLength(str, Length(str) - 1);
end
else
ParaEnd := False;
cury := 0;
if Adjust = 4 then
cury:=y + dy-gapy
else if Adjust = 5 then
cury := y + gapy + Canvas.TextWidth(str)
else if Adjust = 6 then
cury := y + dy - 1 - gapy - (dy - gapy - gapy - Canvas.TextWidth(str)) div 2
else if not Exporting then
begin
cury := y + dy - gapy;
n := 0;
for i := 1 to Length(str) do
if str[i] = ' ' then Inc(n);
//**
{if (n <> 0) and not ParaEnd then
SetTextJustification(Canvas.Handle,
dy - gapy - gapy - Canvas.TextWidth(str), n);}
end;
if not Exporting then
begin
//**
{ ExtTextOut(Canvas.Handle, curx, cury, ETO_CLIPPED, @DR,
PChar(str), Length(str), nil);
if Adjust <> 7 then
SetTextJustification(Canvas.Handle, 0, 0);
}
end;
if Exporting then
CurReport.InternalOnExportText(curx, cury, str, Self);
Inc(CurStrNo);
curx := curx + th;
end;
begin {OutMemo90}
h := Create90Font(Canvas.Font);
oldh := SelectObject(Canvas.Handle,h);
curx := x + gapx;
th := -Canvas.Font.Height + Round(LineSpacing * ScaleY);
CurStrNo := 0;
for i := 0 to Memo1.Count - 1 do
OutLine(Memo1[i]);
SelectObject(Canvas.Handle, oldh);
DeleteObject(h);
end;
begin
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 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;
OutMemo;
finally
X:=SavX;
Y:=SavY;
end;
(*
if (Adjust and $18) <> 0 then
begin
ad := Adjust;
ox := x;
oy := y;
Adjust := Adjust and $7;
if (ad and $4) <> 0 then
begin
if (ad and $18) = $8 then
x := x + (dx - VHeight) div 2
else if (ad and $18) = $10 then
x := x + dx - VHeight;
OutMemo90;
end
else
begin
if (ad and $18) = $8 then
y := y + (dy - VHeight) div 2
else if (ad and $18) = $10 then
y := y + dy - VHeight;
OutMemo;
end;
Adjust := ad;
x := ox; y := oy;
end
else if (Adjust and $4) <> 0 then
OutMemo90
else
OutMemo;
*)
end;
function TfrMemoView.CalcWidth(aMemo: TStringList): Integer;
var
CalcRect: TRect;
s: String;
n: Integer;
begin
{$IFDEF DebugLR}
DbgOut('TfrMemoView.CalcWidth: text=',dbgstr(aMemo.Text),
' Font.PPI=', dbgs(Font.PixelsPerInch),
' Font.Size=', dbgs(Font.Size),' dx=',dbgs(Dx),' dy=',dbgs(dy));
{$ENDIF}
CalcRect := Rect(0, 0, dx, dy);
Canvas.Font.Assign(Font);
Canvas.Font.Height := -Round(Font.Size * 96 / 72);
{$IFDEF DebugLR}
DbgOut(' Canvas.Font.PPI=',dbgs(Canvas.Font.PixelsPerInch),
' Canvas.Font.Size=',dbgs(Canvas.Font.Size));
{$ENDIF}
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, DT_CALCRECT);
Result := CalcRect.Right + Round(2 * FrameWidth) + 2;
{$IFDEF DebugLR}
DebugLn('RR Width=', dbgs(Result),' Rect=', dbgs(CalcRect));
{$ENDIF}
end;
procedure TfrMemoView.Draw(aCanvas: TCanvas);
var
NeedWrap: Boolean;
newdx: Integer;
OldScaleX, OldScaleY: Double;
begin
BeginDraw(aCanvas);
{$IFDEF DebugLR}
if IsPrinting then begin
DebugLn('');
Debugln('TfrMemoView.Draw: Name=',Name,
' Printing=', dbgs(IsPrinting),
' Canvas.Font.PPI=',dbgs(Canvas.Font.PixelsPerInch));
end;
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=',dbgs(NewDx),' Dx=',dbgs(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=',dbgs(Memo1.Count),' Text=',dbgstr(Memo1.text),
' NeedWrap=',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 not Exporting then ShowBackground;
if not Exporting then ShowFrame;
if Memo1.Count > 0 then
ShowMemo;
RestoreCoord;
end;
procedure TfrMemoView.Print(Stream: TStream);
var
St: String;
CanExpandVar: Boolean;
OldFont: TFont;
OldFill: Integer;
i: Integer;
begin
{$IFDEF DebugLR}
DebugLn('%sTfrMemoView.Print %s',[sspc,Name]);
{$ENDIF}
BeginDraw(TempBmp.Canvas);
Streaming := True;
if DrawMode = drAll then
frInterpretator.DoScript(Script);
CanExpandVar := True;
if (DrawMode = drAll) and (Assigned(CurReport.OnEnterRect) or
((FDataSet <> nil) and frIsBlob(TfrTField(FDataSet.FindField(FField))))) then
begin
Memo1.Assign(Memo);
St:=Memo1.Text;
CurReport.InternalOnEnterRect(Memo1, Self);
if St<>Memo1.Text then
CanExpandVar:= False;
end
else if DrawMode = drAfterCalcHeight then
CanExpandVar := False;
if DrawMode <> drPart then
if CanExpandVar then ExpandVariables;
if not Visible then
begin
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 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;
end;
procedure TfrMemoView.ExportData;
begin
inherited;
Exporting := True;
Draw(TempBmp.Canvas);
Exporting := False;
end;
function TfrMemoView.CalcHeight: Integer;
var
s: String;
CanExpandVar: Boolean;
OldFont: TFont;
OldFill: Integer;
begin
Result := 0;
DrawMode := drAfterCalcHeight;
BeginDraw(TempBmp.Canvas);
frInterpretator.DoScript(Script);
if not Visible then Exit;
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;
end;
Font.Assign(OldFont);
OldFont.Free;
fFillColor := OldFill;
end;
function TfrMemoView.MinHeight: Integer;
begin
Result := TextHeight;
end;
function TfrMemoView.RemainHeight: Integer;
begin
Result := Memo1.Count * TextHeight;
end;
procedure TfrMemoView.LoadFromStream(Stream: TStream);
var
w: Word;
i: Integer;
TmpAlign: TAlignment;
TmpLayout: TTextLayout;
begin
{$IFDEF DebugLR}
DebugLn('Stream.Position=',IntToStr(Stream.Position),' Stream.Size=',InttoStr(Stream.Size));
{$ENDIF}
inherited LoadFromStream(Stream);
Font.Name := ReadString(Stream);
with Stream do
begin
Read(i, 4);
Font.Size := i;
Read(w, 2);
Font.Style := frSetFontStyle(w);
Read(i, 4);
Font.Color := i;
Read(w, 2);
if frVersion < 23 then
w := frCharset;
Font.Charset := w;
if StreamMode = smDesigning then
begin
Read(Highlight, 10);
HighlightStr := ReadString(Stream);
end;
Read(TmpAlign,SizeOf(TmpAlign));
Read(TmpLayout,SizeOf(TmpLayout));
Read(fAngle,SizeOf(fAngle));
BeginUpdate;
Alignment := tmpAlign;
Layout := tmpLayout;
EndUpdate;
end;
if frVersion = 21 then
Flags := Flags or flWordWrap;
end;
procedure TfrMemoView.LoadFromXML(XML: TLrXMLConfig; 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', 10); // todo chk
RestoreProperty('CharSet',XML.GetValue(Path+'Font/Charset/Value',''),Font);
RestoreProperty('Style',XML.GetValue(Path+'Font/Style/Value',''),Font);
Font.Color := StringToColor(XML.GetValue(Path+'Font/Color/Value','clBlack')); // todo chk
if StreamMode = smDesigning then begin
Highlight.FontStyle := XML.GetValue(Path+'Highlight/FontStyle/Value', 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',''));
fAngle := XML.GetValue(Path+'Angle/Value', 0);
end;
procedure TfrMemoView.SaveToStream(Stream: TStream);
var
i: Integer;
w: Word;
tmpAlign: TAlignment;
tmpLayout: TTextLayout;
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;
if (Adjust and %11 = %11) then
tmpAlign := taLeftJustify
else
tmpAlign := Alignment;
tmpLayout := Layout;
Write(tmpAlign,SizeOf(tmpAlign));
Write(tmpLayout,SizeOf(tmpLayout));
Write(fAngle,SizeOf(fAngle));
end;
end;
procedure TfrMemoView.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
inherited SaveToXML(XML, Path);
XML.SetValue(Path+'Font/Name/Value', Font.name);
XML.SetValue(Path+'Font/Size/Value', 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', 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', FAngle);
end;
procedure TfrMemoView.GetBlob(b: TfrTField);
var
M: TMemoryStream;
begin
// todo: TBLobField.AssignTo is not implemented yet
// even if I supply a patch for 2.0.4 it will
// not be integrated because it's in RC1 now
// (I guess)
//
//Memo1.Assign(b);
M := TMemoryStream.Create;
try
TBlobField(B).SaveToStream(M);
M.Position := 0;
Memo1.LoadFromStream(M);
finally
M.Free;
end;
end;
procedure TfrMemoView.FontChange(sender: TObject);
begin
AfterChange;
end;
procedure TfrMemoView.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 := (Flags and flWordWrap) <> 0;
Popup.Items.Add(m);
m := TMenuItem.Create(Popup);
m.Caption := sWordBreak;
m.OnClick := @P3Click;
m.Enabled := (Flags and flWordWrap) <> 0;
if m.Enabled then
m.Checked := (Flags and flWordBreak) <> 0;
Popup.Items.Add(m);
m := TMenuItem.Create(Popup);
m.Caption := sAutoSize;
m.OnClick := @P5Click;
m.Checked := (Flags and flAutoSize) <> 0;
Popup.Items.Add(m);
end;
procedure TfrMemoView.MonitorFontChanges;
begin
FFont.OnChange:= @FontChange;
end;
procedure TfrMemoView.P1Click(Sender: TObject);
var
t: TfrView;
i: Integer;
begin
BeforeChange;
frFmtForm := TfrFmtForm.Create(nil);
try
with frFmtForm do
begin
EdFormat := Self.Format;
EdFormatStr := Self.FormatStr;
if ShowModal = mrOk then
begin
for i := 0 to frDesigner.Page.Objects.Count - 1 do
begin
t := TfrView(frDesigner.Page.Objects[i]);
if t.Selected then
begin
(t as TfrMemoView).Format := EdFormat;
(t as TfrMemoView).FormatStr := EdFormatStr;
end;
end;
end;
end;
finally
frFmtForm.Free;
AfterChange
end;
end;
function TfrMemoView.GetAutoSize: Boolean;
begin
Result:=((Flags and flAutoSize)<>0);
end;
function TfrMemoView.GetLayout: TTextLayout;
begin
result := TTextLayout((adjust shr 3) and %11);
end;
function TfrMemoView.GetAlignment: TAlignment;
begin
Result:=Classes.TAlignment(Adjust and %11);
end;
function TfrMemoView.GetWordWrap: Boolean;
begin
Result:=((Flags and flWordWrap)<>0);
end;
procedure TfrMemoView.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
SetBit(t.Flags, Checked, flWordWrap);
end;
end;
frDesigner.AfterChange;
end;
procedure TfrMemoView.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 flWordBreak) + Word(Checked) * flWordBreak;
end;
end;
frDesigner.AfterChange;
end;
procedure TfrMemoView.P4Click(Sender: TObject);
var
t: TfrView;
i: Integer;
fd: TFontDialog;
begin
frDesigner.BeforeChange;
fd := TFontDialog.Create(nil);
with fd do
begin
Font.Assign(Self.Font);
if Execute then
for i := 0 to frDesigner.Page.Objects.Count - 1 do
begin
t :=TfrView(frDesigner.Page.Objects[i]);
if t.Selected then
begin
if Font.Name <> Self.Font.Name then
TfrMemoView(t).Font.Name := Font.Name;
if Font.Size <> Self.Font.Size then
TfrMemoView(t).Font.Size := Font.Size;
if Font.Color <> Self.Font.Color then
TfrMemoView(t).Font.Color := Font.Color;
if Font.Style <> Self.Font.Style then
TfrMemoView(t).Font.Style := Font.Style;
if Font.Charset <> Self.Font.Charset then
TfrMemoView(t).Font.Charset := Font.Charset;
end;
end;
end;
fd.Free;
frDesigner.AfterChange;
end;
procedure TfrMemoView.P5Click(Sender: TObject);
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 flAutoSize) + Word(Checked) * flAutoSize;
end;
end;
frDesigner.AfterChange;
end;
procedure TfrMemoView.SetAlignment(const AValue: TAlignment);
begin
if Alignment<>AValue then
begin
BeforeChange;
Adjust := (Adjust and not 3) or ord(AValue);
AfterChange;
end;
end;
procedure TfrMemoView.SetAutoSize(const AValue: Boolean);
begin
Flags:=Flags+flAutoSize;
end;
{----------------------------------------------------------------------------}
constructor TfrBandView.Create;
begin
inherited Create;
Typ := gtBand;
fFormat := 0;
BaseName := 'Band';
Flags := flBandOnFirstPage + flBandOnLastPage;
end;
procedure TfrBandView.Assign(From: TfrView);
begin
inherited Assign(From);
if From is TfrBandView then
begin
BandType := TFrBandView(From).BandType;
DataSet := TFrBandView(From).DataSet;
GroupCondition:=TFrBandView(From).GroupCondition;
end;
end;
procedure TfrBandView.LoadFromStream(Stream: TStream);
begin
inherited LoadFromStream(Stream);
With Stream do
begin
Read(fBandType,SizeOf(BandType));
fCondition :=ReadString(Stream);
fDataSetStr:=ReadString(Stream);
end;
end;
procedure TfrBandView.LoadFromXML(XML: TLrXMLConfig; Path: String);
begin
inherited LoadFromXML(XML, Path);
RestoreProperty('BandType',XML.GetValue(Path+'BandType/Value','')); // todo chk
FCondition := XML.GetValue(Path+'Condition/Value', ''); // todo chk
FDatasetStr := XML.GetValue(Path+'DatasetStr/Value', ''); // todo chk
end;
procedure TfrBandView.SaveToStream(Stream: TStream);
begin
inherited SaveToStream(Stream);
with Stream do
begin
Write(fBandType,SizeOf(fBandType));
frWriteString(Stream, fCondition);
frWriteString(Stream, fDataSetStr);
end;
end;
procedure TfrBandView.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
inherited SaveToXML(XML, Path);
XML.SetValue(Path+'BandType/Value', GetSaveProperty('BandType')); //Ord(FBandType)); // todo: use symbolic values
XML.SetValue(Path+'Condition/Value', FCondition);
XML.SetValue(Path+'DatasetStr/Value', FDatasetStr);
end;
procedure TfrBandView.Draw(aCanvas: TCanvas);
var
h, oldh: HFont;
St : String;
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.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;
if ShowBandTitles then
begin
if BandType in [btCrossHeader..btCrossFooter] then
begin
FillRect(Rect(x - 18, y, x, y + 100));
Pen.Color := clBtnShadow;
MoveTo(x - 18, y + 98); LineTo(x, y + 98);
Pen.Color := clBlack;
MoveTo(x - 18, y + 99); LineTo(x, y + 99);
Pen.Color := clBtnHighlight;
MoveTo(x - 18, y + 99); LineTo(x - 18, y);
h := Create90Font(Font);
oldh := SelectObject(Handle, h);
Brush.Color:=clBtnFace;
TextOut(x - 15, y + 94, frBandNames[BandType]);
SelectObject(Handle, oldh);
DeleteObject(h);
end
else
begin
FillRect(Rect(x, y - 18, x + 100, y));
Pen.Color := clBtnShadow;
MoveTo(x + 98, y - 18);
LineTo(x + 98, y);
Pen.Color := clBlack;
MoveTo(x + 99, y - 18);
LineTo(x + 99, y);
st:=frBandNames[BandType];
Brush.Color:=clBtnFace;
TextOut(x+4,y-17, frBandNames[BandType]);
end;
end
else
begin
Brush.Style := bsClear;
if BandType in [btCrossHeader..btCrossFooter] then
begin
h := Create90Font(Font);
oldh := SelectObject(Handle, h);
Brush.Color:=clBtnFace;
TextOut(x + 2, y + 94, frBandNames[BandType]);
SelectObject(Handle, oldh);
DeleteObject(h);
end
else
begin
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;
RR : LongInt;
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);
if BandType in [btCrossHeader..btCrossFooter] then
R := CreateRectRgn(x - 18, y, x, y + 100)
else
R := CreateRectRgn(x, y - 18, x + 100, y);
R2:=CreateRectRgn(0,0,0,0);
RR:=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}
DbgOut('(',IntToStr(aX),'>',InttoStr(Rc.Left),') and (',InttoStr(aX),'<',InttoStr(Rc.Right));
DebugLn(') and (',InttoStr(aY),'>',InttoStr(Rc.Top),') and (',InttoStR(aY),
'<',InttoStr(Rc.Bottom),')=',BoolToStr(Result));
{$ENDIF}
if not Result and ShowBandTitles then
begin
if BandType in [btCrossHeader..btCrossFooter] then
Rc:=Bounds(x-18,y, 18,100)
else
Rc:=Bounds(x,y-18,100, 18);
Result:=((aX>Rc.Left) and (aX<Rc.Right) and (aY>Rc.Top) and (aY<Rc.Bottom));
{$IFDEF DebugLR}
DbgOut('(',InttoStr(aX),'>',InttoStr(Rc.Left),') and (',InttoStr(aX),'<',
IntToStr(Rc.Right),') and (',IntToStr(aY),'>');
DebugLn(IntToStr(Rc.Top),') and (',InttoStr(aY),'<',IntToStr(Rc.Bottom),')=',BoolToStr(Result));
{$ENDIF}
end;
end;
procedure TfrBandView.DefinePopupMenu(Popup: TPopupMenu);
var
m: TMenuItem;
begin
if BandType in [btReportTitle, btReportSummary, btPageHeader, btCrossHeader,
btMasterHeader..btSubDetailFooter, btGroupHeader, btGroupFooter] then
inherited DefinePopupMenu(Popup);
if BandType in [btReportTitle, btReportSummary, btMasterData, btDetailData,
btSubDetailData, btMasterFooter, btDetailFooter,
btSubDetailFooter, btGroupHeader] then
begin
m := TMenuItem.Create(Popup);
m.Caption := sFormNewPage;
m.OnClick := @P1Click;
m.Checked := (Flags and flBandNewPageAfter) <> 0;
Popup.Items.Add(m);
end;
if BandType in [btMasterData, btDetailData] then
begin
m := TMenuItem.Create(Popup);
m.Caption := sPrintIfSubsetEmpty;
m.OnClick := @P2Click;
m.Checked := (Flags and flBandPrintIfSubsetEmpty) <> 0;
Popup.Items.Add(m);
end;
if BandType in [btReportTitle, btReportSummary, btMasterHeader..btSubDetailFooter,
btGroupHeader, btGroupFooter] then
begin
m := TMenuItem.Create(Popup);
m.Caption := sBreaked;
m.OnClick := @P3Click;
m.Checked := (Flags and flBandPageBreak) <> 0;
Popup.Items.Add(m);
end;
if BandType in [btPageHeader, btPageFooter] then
begin
m := TMenuItem.Create(Popup);
m.Caption := sOnFirstPage;
m.OnClick := @P4Click;
m.Checked := (Flags and flBandOnFirstPage) <> 0;
Popup.Items.Add(m);
end;
if BandType = btPageFooter then
begin
m := TMenuItem.Create(Popup);
m.Caption := sOnLastPage;
m.OnClick := @P5Click;
m.Checked := (Flags and flBandOnLastPage) <> 0;
Popup.Items.Add(m);
end;
if BandType in [btMasterHeader, btDetailHeader, btSubDetailHeader,
btCrossHeader, btGroupHeader] then
begin
m := TMenuItem.Create(Popup);
m.Caption := sRepeatHeader;
m.OnClick := @P6Click;
m.Checked := (Flags and flBandRepeatHeader) <> 0;
Popup.Items.Add(m);
end;
end;
procedure TfrBandView.P1Click(Sender: TObject);
var
i: Integer;
t: TfrView;
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
for i := 0 to frDesigner.Page.Objects.Count - 1 do
begin
t :=TfrView(frDesigner.Page.Objects[i]);
if t.Selected then
t.Flags := (t.Flags and not flBandNewPageAfter) +
Word(Checked) * flBandNewPageAfter;
end;
end;
end;
procedure TfrBandView.P2Click(Sender: TObject);
var
i: Integer;
t: TfrView;
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
for i := 0 to frDesigner.Page.Objects.Count - 1 do
begin
t :=TfrView(frDesigner.Page.Objects[i]);
if t.Selected then
t.Flags := (t.Flags and not flBandPrintifSubsetEmpty) +
Word(Checked) * flBandPrintifSubsetEmpty;
end;
end;
end;
procedure TfrBandView.P3Click(Sender: TObject);
var
i: Integer;
t: TfrView;
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
for i := 0 to frDesigner.Page.Objects.Count - 1 do
begin
t :=TfrView(frDesigner.Page.Objects[i]);
if t.Selected then
t.Flags := (t.Flags and not flBandPageBreak) + Word(Checked) * flBandPageBreak;
end;
end;
end;
procedure TfrBandView.P4Click(Sender: TObject);
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
Flags := (Flags and not flBandOnFirstPage) + Word(Checked) * flBandOnFirstPage;
end;
end;
procedure TfrBandView.P5Click(Sender: TObject);
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
Flags := (Flags and not flBandOnLastPage) + Word(Checked) * flBandOnLastPage;
end;
end;
procedure TfrBandView.P6Click(Sender: TObject);
begin
frDesigner.BeforeChange;
with Sender as TMenuItem do
begin
Checked := not Checked;
Flags := (Flags and not flBandRepeatHeader) + Word(Checked) * flBandRepeatHeader;
end;
end;
{----------------------------------------------------------------------------}
constructor TfrSubReportView.Create;
begin
inherited Create;
Typ := gtSubReport;
BaseName := 'SubReport';
end;
procedure TfrSubReportView.Assign(From: TfrView);
begin
inherited Assign(From);
SubPage := (From as TfrSubReportView).SubPage;
end;
procedure TfrSubReportView.Draw(aCanvas: TCanvas);
begin
BeginDraw(aCanvas);
fFrameWidth := 1;
CalcGaps;
with aCanvas do
begin
Font.Name := 'Arial';
Font.Style := [];
Font.Size := 8;
Font.Color := clBlack;
Font.Charset := frCharset;
Pen.Width := 1;
Pen.Color := clBlack;
Pen.Style := psSolid;
Brush.Color := clWhite;
Rectangle(x, y, x + dx + 1, y + dy + 1);
Brush.Style := bsClear;
TextRect(DRect, x + 2, y + 2, sSubReportOnPage + ' ' +
IntToStr(SubPage + 1));
end;
RestoreCoord;
end;
procedure TfrSubReportView.DefinePopupMenu(Popup: TPopupMenu);
begin
// no specific items in popup menu
end;
procedure TfrSubReportView.LoadFromStream(Stream: TStream);
begin
inherited LoadFromStream(Stream);
Stream.Read(SubPage, 4);
end;
procedure TfrSubReportView.LoadFromXML(XML: TLrXMLConfig; Path: String);
begin
inherited LoadFromXML(XML, Path);
SubPage := XML.GetValue(Path+'SubPage/Value', 0); // todo chk
end;
procedure TfrSubReportView.SaveToStream(Stream: TStream);
begin
inherited SaveToStream(Stream);
Stream.Write(SubPage, 4);
end;
procedure TfrSubReportView.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
inherited SaveToXML(XML, Path);
XML.SetValue(Path+'SubPage/Value', SubPage);
end;
{----------------------------------------------------------------------------}
constructor TfrPictureView.Create;
begin
inherited Create;
Typ := gtPicture;
fPicture := TPicture.Create;
Flags := flStretched + flPictRatio;
BaseName := 'Picture';
end;
destructor TfrPictureView.Destroy;
begin
Picture.Free;
inherited Destroy;
end;
procedure TfrPictureView.Assign(From: TfrView);
begin
inherited Assign(From);
Picture.Assign(TfrPictureView(From).Picture);
end;
procedure TfrPictureView.Draw(aCanvas: TCanvas);
var
r: TRect;
kx, ky: Double;
w, h, w1, h1: Integer;
procedure PrintBitmap(DestRect: TRect; Bitmap: TBitmap);
var
BitmapHeader: pBitmapInfo;
BitmapImage: Pointer;
HeaderSize: DWord;
ImageSize: DWord;
begin
aCanvas.StretchDraw(DestRect, Bitmap);
//**
{GetDIBSizes(Bitmap.Handle, HeaderSize, ImageSize);
GetMem(BitmapHeader, HeaderSize);
GetMem(BitmapImage, ImageSize);
try
GetDIB(Bitmap.Handle, Bitmap.Palette, BitmapHeader^, BitmapImage^);
StretchDIBits(
aCanvas.Handle,
DestRect.Left, DestRect.Top, // Destination Origin
DestRect.Right - DestRect.Left, // Destination Width
DestRect.Bottom - DestRect.Top, // Destination Height
0, 0, // Source Origin
Bitmap.Width, Bitmap.Height, // Source Width & Height
BitmapImage,
TBitmapInfo(BitmapHeader^),
DIB_RGB_COLORS,
SRCCOPY)
finally
FreeMem(BitmapHeader);
FreeMem(BitmapImage)
end;
}
end;
begin
BeginDraw(aCanvas);
CalcGaps;
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
if (Flags and flStretched) <> 0 then
begin
r := DRect;
if (Flags and flPictRatio) <> 0 then
begin
kx := dx / Picture.Width;
ky := dy / Picture.Height;
if kx < ky then
r := Rect(DRect.Left, DRect.Top,
DRect.Right, DRect.Top + Round(Picture.Height * kx))
else
r := Rect(DRect.Left, DRect.Top,
DRect.Left + Round(Picture.Width * ky), DRect.Bottom);
w := DRect.Right - DRect.Left;
h := DRect.Bottom - DRect.Top;
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;
if IsPrinting and (Picture.Graphic is TBitmap) then
PrintBitmap(r, Picture.Bitmap)
else
StretchDraw(r, Picture.Graphic);
end
else
begin
r := DRect;
if (Flags and flPictCenter) <> 0 then
begin
w := DRect.Right - DRect.Left;
h := DRect.Bottom - DRect.Top;
OffsetRect(r, (w - Picture.Width) div 2, (h - Picture.Height) div 2);
end;
Draw(r.Left, r.Top, Picture.Graphic)
end;
end;
ShowFrame;
end;
RestoreCoord;
end;
const
pkNone = 0;
pkBitmap = 1;
//** pkMetafile = 2;
pkIcon = 3;
pkJPEG = 4;
pkPNG = 5;
procedure StreamToXML(XML: TLrXMLConfig; Path: String; Stream: TStream);
var
Buf: Array[0..1023] of byte;
S: String;
i: integer;
procedure WriteBuf(Count: Integer);
var
j: Integer;
begin
for j:=0 to Count-1 do
S := S + IntToHex(Buf[j], 2);
end;
begin
XML.SetValue(Path+'Size/Value', Stream.Size);
S := '';
for i:=1 to Stream.Size div SizeOf(Buf) do begin
Stream.Read(Buf, 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,cd: integer;
B: Byte;
begin
Size := XML.GetValue(Path+'Size/Value', 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);
Stream.Read(b, 1);
Stream.Read(n, 4);
Graphic := PictureTypeToGraphic(b);
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; Path: String);
var
b: Byte;
m: TMemoryStream;
Graphic: TGraphic;
begin
inherited LoadFromXML(XML, Path);
b := XML.GetValue(Path+'Picture/Type/Value', pkNone);
Graphic := PictureTypeToGraphic(b);
Picture.Graphic := Graphic;
if Graphic <> nil then
begin
Graphic.Free;
M := TMemoryStream.Create;
try
XMLToStream(XML, Path+'Picture/', M);
M.Position := 0;
Picture.Graphic.LoadFromStream(M);
finally
M.Free;
end;
end;
end;
procedure TfrPictureView.SaveToStream(Stream: TStream);
var
b: Byte;
n, o: Integer;
begin
inherited SaveToStream(Stream);
b := GetPictureType;
Stream.Write(b, 1);
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; Path: String);
var
b: Byte;
n, o: Integer;
m: TMemoryStream;
begin
inherited SaveToXML(XML, Path);
b := GetPictureType;
XML.SetValue(Path+'Picture/Type/Value', b);
if b <> pkNone then
begin
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;
begin
if b.IsNull then
Picture.Assign(nil)
else begin
// todo: TBlobField.AssignTo is not implemented yet
s := TDataset(FDataset).CreateBlobStream(TField(b),bmRead);
if s.Size = 0 then
Picture.Clear
else
begin
try
GraphExt := s.ReadAnsiString;
gc := GetGraphicClassForFileExtension(GraphExt);
if assigned(gc) then
begin
AGraphic := gc.Create;
AGraphic.LoadFromStream(s);
Picture.Assign(AGraphic);
end;
finally
if assigned(AGraphic) then
AGraphic.Free;
s.Free;
end
end;
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 := (Flags and flPictCenter) <> 0;
Popup.Items.Add(m);
m := TMenuItem.Create(Popup);
m.Caption := sKeepAspectRatio;
m.OnClick := @P2Click;
m.Enabled := (Flags and flStretched) <> 0;
if m.Enabled then
m.Checked := (Flags and flPictRatio) <> 0;
Popup.Items.Add(m);
end;
procedure TfrPictureView.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 flPictCenter) + Word(Checked) * flPictCenter;
end;
end;
frDesigner.AfterChange;
end;
procedure TfrPictureView.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 flPictRatio) + Word(Checked) * flPictRatio;
end;
end;
frDesigner.AfterChange;
end;
function TfrPictureView.GetPictureType: byte;
begin
result := pkNone;
if Picture.Graphic <> nil then
if Picture.Graphic is TPortableNetworkGraphic then
result := pkPNG
else if Picture.Graphic is TJPEGImage then
result := pkJPEG
else if Picture.Graphic is TIcon then
result := pkIcon
else if Picture.Graphic is TBitmap then
result := pkBitmap;
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;
procedure TfrPictureView.SetPicture(const AValue: TPicture);
begin
BeforeChange;
fPicture := AValue;
AfterChange;
end;
class function TfrPictureView.GetFilter: string;
procedure AddFilter(G:TGraphicClass);
var
S: string;
begin
if result<>'' then
Result := Result + ';';
Result := Result + '*.' + StringReplace(G.GetFileExtensions, ';', ';*.',
[rfReplaceAll]);
end;
begin
Result := '';
AddFilter(TBitmap);
AddFilter(TIcon);
AddFilter(TJpegImage);
AddFilter(TPortableNetworkGraphic);
Result := '(' + Result + ')|'+Result;
end;
{----------------------------------------------------------------------------}
constructor TfrLineView.Create;
begin
inherited Create;
Typ := gtLine;
fFrames:=[frbLeft];
BaseName := 'Line';
end;
procedure TfrLineView.Draw(aCanvas: TCanvas);
begin
BeginDraw(aCanvas);
if dx > dy then
begin
dy := 0;
fFrames:=[frbTop];
end
else
begin
dx := 0;
fFrames:=[frbLeft];
end;
CalcGaps;
ShowFrame;
RestoreCoord;
end;
procedure TfrLineView.DefinePopupMenu(Popup: TPopupMenu);
begin
// no specific items in popup menu
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;
{----------------------------------------------------------------------------}
constructor TfrBand.Create(ATyp: TfrBandType; AParent: TfrPage);
begin
inherited Create;
Typ := ATyp;
Parent := AParent;
Objects := TList.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;
procedure TfrBand.InitDataSet(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;
var
i: Integer;
begin
ErrorFlag := True;
ErrorStr := sErrorOccured;
for i := 0 to CurView.Memo.Count - 1 do
ErrorStr := ErrorStr + #13 + CurView.Memo[i];
ErrorStr := ErrorStr + #13 + sDoc + ' ' + CurReport.Name +
#13 + sBand; // + ' ' + frBandNames[Integer(CurView.Parent.Typ)];
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: 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
h := TfrStretcheable(t).CalcHeight + t.y;
if h > Result then
Result := h;
if CheckAll then
TfrStretcheable(t).DrawMode := drAll;
end
end;
end;
begin
Result := dy;
if HasCross and (Typ <> btPageFooter) then
begin
Parent.ColPos := 1;
CurReport.InternalOnBeginColumn(Self);
if Parent.BandExists(Parent.Bands[btCrossData]) then
begin
Bnd := Parent.Bands[btCrossData];
if Bnd.DataSet <> nil then
DS := Bnd.DataSet
else
DS := VCDataSet;
BM:=DS.GetBookMark;
DS.DisableControls;
try
DS.First;
while not DS.Eof do
begin
ddx := 0;
CurReport.InternalOnPrintColumn(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
else
Result := SubDoCalcHeight(False);
CalculatedHeight := Result;
end;
procedure TfrBand.StretchObjects(MaxHeight: Integer);
var
i: Integer;
t: TfrView;
begin
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
t.dy := MaxHeight - t.y;
end;
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;
end;
end;
procedure TfrBand.DrawObject(t: TfrView);
var
ox,oy: Integer;
begin
{$IFDEF DebugLR}
DebugLn('%sTfrBand.DrawObject INI t=%s:%s',[sspc,dbgsname(t),t.name]);
IncSpc(1);
{$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 exception do DoError;
end;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrBand.DrawObject DONE t=%s:%s',[sspc,dbgsname(t),t.name]);
{$ENDIF}
end;
procedure TfrBand.PrepareSubReports;
var
i: Integer;
t: TfrView;
Page: TfrPage;
begin
for i := SubIndex to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
Page.Mode := pmBuildList;
Page.FormPage;
Page.CurY := y + t.y;
Page.CurBottomY := Parent.CurBottomY;
Page.XAdjust := Parent.XAdjust + t.x;
Page.ColCount := 1;
Page.PlayFrom := 0;
EOFArr[i - SubIndex] := False;
end;
Parent.LastBand := nil;
end;
procedure TfrBand.DoSubReports;
var
i: Integer;
t: TfrView;
Page: TfrPage;
begin
repeat
if not EOFReached then
for i := SubIndex to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
Page.CurY := Parent.CurY;
Page.CurBottomY := Parent.CurBottomY;
end;
EOFReached := True;
MaxY := Parent.CurY;
for i := SubIndex to Objects.Count - 1 do
begin
if not EOFArr[i - SubIndex] then
begin
t :=TfrView(Objects[i]);
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
if Page.PlayRecList then
EOFReached := False
else
begin
EOFArr[i - SubIndex] := True;
if Page.CurY > MaxY then MaxY := Page.CurY;
end;
end;
end;
if not EOFReached then
begin
if Parent.Skip then
begin
Parent.LastBand := Self;
Exit;
end
else
Parent.NewPage;
end;
until EOFReached or MasterReport.Terminated;
for i := SubIndex to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
Page := CurReport.Pages[(t as TfrSubReportView).SubPage];
Page.ClearRecList;
end;
Parent.CurY := MaxY;
Parent.LastBand := nil;
end;
function TfrBand.DrawObjects: Boolean;
var
i: Integer;
t: TfrView;
begin
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;
DrawObject(t);
if MasterReport.Terminated then break;
end;
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);
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.InternalOnBeginColumn(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.InternalOnPrintColumn(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}
DebugLn('%sTfrBand.CheckPageBreak INI ay=%d ady=%d Pbreak=%d',
[sspc,ay,ady,ord(pbreak)]);
IncSpc(1);
{$ENDIF}
Result := False;
with Parent do begin
{$IFDEF DebugLR}
DebugLn('%say+dy+ady=%d CurBottomY=%d',
[sspc, ay+Bands[btColumnFooter].dy+ady,CurBottomY]);
{$ENDIF}
if not RowsLayout then begin
if ay + Bands[btColumnFooter].dy + ady > CurBottomY then
begin
if not PBreak then
NewColumn(Self);
Result := True;
end;
end;
end;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrBand.CheckPageBreak END ay=%d ady=%d Result=%d',
[sspc,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('%sTfrBand.CheckNextColumn INI CurY=%d BHeight=%d CurY+BH=%d CurBottomY=%d',
[sspc,CurY,BandHeight,CurY+BandHeight,CurBottomY]);
{$ENDIF}
// check left height space when on last column
if CurY + BandHeight>CurBottomY then
NewPage;
{$IFDEF DebugLR}
DebugLn('%sTfrBand.CheckNextColumn END CurY=%d BHeight=%d CurY+BH=%d CurBottomY=%d',
[sspc,CurY,BandHeight,CurY+BandHeight,CurBottomY]);
{$ENDIF}
end;
end;
end;
procedure TfrBand.DrawPageBreak;
var
i: Integer;
newDy, oldy, olddy, aMaxy: Integer;
t: TfrView;
Flag: Boolean;
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}
DebugLn('%sDrawPageBreak INI y=%d Maxdy',[sspc,y,maxdy]);
IncSpc(1);
{$ENDIF}
for i := 0 to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
t.Selected := True;
t.OriginalRect := Rect(t.x, t.y, t.dx, t.dy);
end;
if not CheckPageBreak(y, maxdy, True) then
DrawObjects
else
begin
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
TfrMemoView(t).CalcHeight; // wraps a memo onto separate lines
t.Memo1.Assign(SMemo);
end;
end;
repeat
newDy := Parent.CurBottomY - Parent.Bands[btColumnFooter].dy - y - 2;
aMaxy := 0;
for i := 0 to Objects.Count - 1 do
begin
t :=TfrView(Objects[i]);
if t.Selected then
if (t.y >= 0) and (t.y < newdy) then
if (t.y + t.dy < newdy) then
begin
if aMaxy < t.y + t.dy then
aMaxy := t.y + t.dy;
DrawObject(t);
t.Selected := False;
end
else
begin
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
else if t is TfrStretcheable then
if (t.y < 0) and (t.y + t.dy >= 0) then
if t.y + t.dy < dy then
begin
oldy := t.y; olddy := t.dy;
t.dy := t.y + t.dy;
t.y := 0;
if t.dy > TfrStretcheable(t).MinHeight div 2 then
begin
t.dy := TfrStretcheable(t).RemainHeight + t.gapy * 2 + 1;
Inc(TfrStretcheable(t).ActualHeight, t.dy - 1);
if aMaxy < t.y + t.dy then
aMaxy := t.y + t.dy;
TfrStretcheable(t).DrawMode := drPart;
DrawObject(t);
end;
t.y := oldy; t.dy := olddy;
CorrY(t, TfrStretcheable(t).ActualHeight - t.dy);
t.Selected := False;
end
else
begin
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;
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;
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);
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sDrawPageBreak END Parent.CurY=%d',[sspc,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}
DebugLn('%sTfrBand.DoDraw INI sfy=%d y=%d dy=%d XAdjust=%d CurY=%d Stretch=%d PageBreak=%d',
[sspc, sfy, y, dy, Parent.XAdjust, parent.cury, Ord(Stretched), Ord(PageBreak)]);
IncSpc(1);
{$ENDIF}
if Stretched then
begin
sh := CalculatedHeight;
// sh := CalcHeight;
if sh > dy then
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;
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;
// maxdy := CalcHeight;
DrawPageBreak;
end
else
begin
WasSub := DrawObjects;
if HasCross then
DrawCross;
if UseY and not WasSub then begin
if (not Parent.RowsLayout) or (Parent.CurColumn=Parent.ColCount-1) 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}
IncSpc(-1);
DebugLn('%sTfrBand.DoDraw END sfy=%d y=%d dy=%d xadjust=%d CurY=%d',
[sspc, sfy, y, dy, parent.xadjust, parent.cury]);
{$ENDIF}
end;
function TfrBand.DoCalcHeight: Integer;
var
b: TfrBand;
begin
if (Typ in [btMasterData, btDetailData, btSubDetailData]) and
(Next <> nil) and (Next.Dataset = nil) then
begin
b := Self;
Result := 0;
repeat
Result := Result + b.CalcHeight;
b := b.Next;
until b = nil;
end
else
begin
Result := dy;
CalculatedHeight := dy;
if Stretched then Result := CalcHeight;
end;
end;
function TfrBand.Draw: Boolean;
var
b: TfrBand;
begin
{$IFDEF debugLr}
DebugLn('%sTFrBand.Draw INI %s:%s y=%d vis=%s',[sspc, Name, ClassName,y,BoolToStr(Visible,true)]);
IncSpc(1);
{$endif}
Result := False;
CurView := View;
CurBand := Self;
AggrBand := Self;
CalculatedHeight := -1;
ForceNewPage := False;
ForceNewColumn := False;
if Assigned(CurReport.FOnBeginBand) then
CurReport.FOnBeginBand(Self);
frInterpretator.DoScript(Script);
if Parent.RowsLayout 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
// new page was requested in script
if ForceNewPage then
begin
Parent.CurColumn := Parent.ColCount - 1;
Parent.NewColumn(Self);
end;
if ForceNewColumn then
Parent.NewColumn(Self);
if Visible then
begin
if Typ = btColumnHeader then
Parent.LastStaticColumnY := Parent.CurY;
if Typ = btPageFooter then
y := Parent.CurBottomY;
if Objects.Count > 0 then
begin
if not (Typ in [btPageFooter, btOverlay, btNone]) then
if (Parent.CurY + DoCalcHeight > Parent.CurBottomY) and not PageBreak then
begin
Result := True;
if Parent.Skip then
Exit
else
CheckPageBreak(0, 10000, False);
end;
EOFReached := True;
// dealing with multiple bands
if (Typ in [btMasterData, btDetailData, btSubDetailData]) and
(Next <> nil) and (Next.Dataset = nil) and (DataSet <> nil) then
begin
b := Self;
repeat
b.DoDraw;
b := b.Next;
until b = nil;
end
else
begin
DoDraw;
if not (Typ in [btMasterData, btDetailData, btSubDetailData, btGroupHeader]) and
NewPageAfter then
Parent.NewPage;
end;
if not EOFReached then Result := True;
end;
end
// if band is not visible, just performing aggregate calculations
// relative to it
else
if Typ in [btMasterData, btDetailData, btSubDetailData] then
Parent.DoAggregate([btPageFooter, btMasterFooter, btDetailFooter,
btSubDetailFooter, btGroupFooter, btReportSummary]);
// check if multiple pagefooters (in cross-tab report) - resets last of them
if not DisableInit then
if (Typ <> btPageFooter) or (PageNo = MasterReport.EMFPages.Count - 1) then
InitValues;
end;
if Assigned(CurReport.FOnEndBand) then
CurReport.FOnEndBand(Self);
{$IFDEF debugLr}
IncSpc(-1);
DebugLn('%sTFrBand.Draw END %s y=%d PageNo=%d',[sspc, 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;
procedure TfrBand.DoAggregate;
var
i: Integer;
t: TfrView;
s: String;
v: Boolean;
begin
for i := 0 to Values.Count - 1 do
begin
s := Values[i];
Values[i] := Copy(s, 1, Pos('=', s) - 1) + '=0' + Copy(s, Pos('=', s) + 2, 255);
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);
end;
{----------------------------------------------------------------------------}
type
TfrBandParts = (bpHeader, bpData, bpFooter);
const
MAXBNDS = 3;
Bnds: Array[1..MAXBNDS, TfrBandParts] of TfrBandType =
((btMasterHeader, btMasterData, btMasterFooter),
(btDetailHeader, btDetailData, btDetailFooter),
(btSubDetailHeader, btSubDetailData, btSubDetailFooter));
constructor TfrPage.Create(ASize, AWidth, AHeight: Integer;
AOr: TPrinterOrientation);
begin
Self.Create;
ChangePaper(ASize, AWidth, AHeight, AOr);
PrintToPrevPage := False;
UseMargins := True;
end;
constructor TfrPage.CreatePage;
begin
self.Create;
end;
destructor TfrPage.Destroy;
begin
Clear;
Objects.Free;
RTObjects.Free;
List.Free;
fMargins.Free;
inherited Destroy;
end;
procedure TfrPage.ChangePaper(ASize, AWidth, AHeight: Integer;
AOr: TPrinterOrientation);
begin
try
Prn.SetPrinterInfo(ASize, AWidth, AHeight, AOr);
Prn.FillPrnInfo(PrnInfo);
except
on E:exception do
begin
Prn.SetPrinterInfo($100, AWidth, AHeight, AOr);
Prn.FillPrnInfo(PrnInfo);
end;
end;
pgSize := Prn.PaperSize;
Width := Prn.PaperWidth;
Height := Prn.PaperHeight;
Orientation:= Prn.Orientation;
end;
procedure TfrPage.Clear;
begin
while Objects.Count > 0 do
Delete(0);
end;
procedure TfrPage.Delete(Index: Integer);
begin
TfrView(Objects[Index]).Free;
Objects.Delete(Index);
end;
function TfrPage.FindObjectByID(ID: Integer): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Objects.Count - 1 do
begin
if TfrView(Objects[i]).ID = ID then
begin
Result := i;
break;
end;
end;
end;
function TfrPage.FindObject(aName: String): TfrObject;
var
i: Integer;
begin
Result := nil;
if AnsiCompareText(Self.Name, aName) = 0 then
Result:=Self
else
begin
for i := 0 to Objects.Count - 1 do
begin
if AnsiCompareText(TfrObject(Objects[i]).Name, aName) = 0 then
begin
Result :=TfrObject(Objects[i]);
Exit;
end;
end;
end;
end;
function TfrPage.FindRTObject(aName: String): TfrObject;
var
i: Integer;
begin
Result := nil;
if AnsiCompareText(Self.Name, aName) = 0 then
Result:=Self
else
for i := 0 to RTObjects.Count - 1 do
begin
if AnsiCompareText(TfrObject(RTObjects[i]).Name, aName) = 0 then
begin
Result :=TfrObject(RTObjects[i]);
Exit;
end;
end;
end;
procedure TfrPage.InitReport;
var
b: TfrBandType;
begin
for b := btReportTitle to btNone do
Bands[b] := TfrBand.Create(b, Self);
while RTObjects.Count > 0 do
begin
TfrView(RTObjects[0]).Free;
RTObjects.Delete(0);
end;
TossObjects;
InitFlag := True;
CurPos := 1; ColPos := 1;
end;
procedure TfrPage.DoneReport;
var
b: TfrBandType;
begin
if InitFlag then
begin
for b := btReportTitle to btNone do
Bands[b].Free;
while RTObjects.Count > 0 do
begin
TfrView(RTObjects[0]).Free;
RTObjects.Delete(0);
end;
end;
InitFlag := False;
end;
function TfrPage.TopMargin: Integer;
begin
if UseMargins then
begin
if Margins.Top = 0 then
Result := PrnInfo.Ofy
else
Result := Margins.Top;
end
else Result := 0;
end;
function TfrPage.BottomMargin: Integer;
begin
with PrnInfo do
if UseMargins then
if Margins.Bottom = 0 then
Result:=Ofy+Ph
else
Result:=Pgh-Margins.Bottom
else
Result:=Pgh;
if (DocMode <> dmDesigning) and BandExists(Bands[btPageFooter]) then
Result := Result - Bands[btPageFooter].dy;
end;
function TfrPage.LeftMargin: Integer;
begin
if UseMargins then
begin
if Margins.Left = 0 then
Result := PrnInfo.Ofx
else
Result := Margins.Left;
end
else Result := 0;
end;
function TfrPage.RightMargin: Integer;
begin
with PrnInfo do
begin
if UseMargins then
begin
if Margins.Right = 0 then
Result := Ofx + Pw
else
Result := Pgw - Margins.Right;
end
else Result := Pgw;
end;
end;
procedure TfrPage.TossObjects;
var
i, j, n, last, miny: Integer;
b: TfrBandType;
bt, t: TfrView;
Bnd, Bnd1: TfrBand;
FirstBand, Flag: Boolean;
BArr: Array[0..31] of TfrBand;
s: String;
begin
for i := 0 to Objects.Count - 1 do
begin
bt :=TfrView(Objects[i]);
t := frCreateObject(bt.Typ, bt.ClassName);
t.Assign(bt);
t.StreamMode := smPrinting;
RTObjects.Add(t);
if (t.Flags and flWantHook) <> 0 then
HookList.Add(t);
end;
for i := 0 to RTObjects.Count - 1 do // select all objects exclude bands
begin
t :=TfrView(RTObjects[i]);
t.Selected := t.Typ <> gtBand;
t.Parent := nil;
frInterpretator.PrepareScript(t.Script, t.Script, SMemo);
if t.Typ = gtSubReport then
CurReport.Pages[(t as TfrSubReportView).SubPage].Skip := True;
end;
Flag := False;
for i := 0 to RTObjects.Count - 1 do // search for btCrossXXX bands
begin
bt :=TfrView(RTObjects[i]);
if (bt.Typ = gtBand) and
(TfrBandView(bt).BandType in [btCrossHeader..btCrossFooter]) then
with Bands[TfrBandView(bt).BandType] do
begin
Memo.Assign(bt.Memo);
Script.Assign(bt.Script);
x := bt.x; dx := bt.dx;
InitDataSet(TfrBandView(bt).DataSet);
View := bt;
Flags := bt.Flags;
Visible := bt.Visible;
bt.Parent := Bands[TfrBandView(bt).BandType];
Flag := True;
end;
end;
if Flag then // fill a ColumnXXX bands at first
for b := btCrossHeader to btCrossFooter do
begin
Bnd := Bands[b];
for i := 0 to RTObjects.Count - 1 do
begin
t :=TfrView(RTObjects[i]);
if t.Selected then
if (t.x >= Bnd.x) and (t.x + t.dx <= Bnd.x + Bnd.dx) then
begin
t.x := t.x - Bnd.x;
t.Parent := Bnd;
Bnd.Objects.Add(t);
end;
end;
end;
for b := btReportTitle to btGroupFooter do // fill other bands
begin
FirstBand := True;
Bnd := Bands[b];
BArr[0] := Bnd;
Last := 1;
for i := 0 to RTObjects.Count - 1 do // search for specified band
begin
bt :=TfrView(RTObjects[i]);
if (bt.Typ = gtBand) and (TfrBandView(bt).BandType=b) then
begin
if not FirstBand then
begin
Bnd.Next := TfrBand.Create(b,Self);
Bnd := Bnd.Next;
BArr[Last] := Bnd;
Inc(Last);
end;
FirstBand := False;
Bnd.Memo.Assign(bt.Memo);
Bnd.Script.Assign(bt.Script);
Bnd.y := bt.y;
Bnd.dy := bt.dy;
Bnd.View := bt;
Bnd.Flags := bt.Flags;
Bnd.Visible := bt.Visible;
bt.Parent := Bnd;
with bt as TfrBandView, Bnd do
begin
if Typ = btGroupHeader then
InitDataSet(TfrBandView(Bt).fCondition)
else
InitDataSet(TfrBandView(Bt).DataSet);
Stretched := (Flags and flStretched) <> 0;
PrintIfSubsetEmpty := (Flags and flBandPrintIfSubsetEmpty) <> 0;
if Skip then
begin
NewPageAfter := False;
PageBreak := False;
end
else
begin
NewPageAfter := (Flags and flBandNewPageAfter) <> 0;
PageBreak := (Flags and flBandPageBreak) <> 0;
end;
end;
for j := 0 to RTObjects.Count - 1 do // placing objects over band
begin
t :=TfrView(RTObjects[j]);
if (t.Parent = nil) and (t.Typ <> gtSubReport) then
if t.Selected then
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
begin
t.Parent := Bnd;
t.y := t.y - Bnd.y;
t.Selected := False;
Bnd.Objects.Add(t);
end;
end;
for j := 0 to RTObjects.Count - 1 do // placing ColumnXXX objects over band
begin
t :=TfrView(RTObjects[j]);
if t.Parent <> nil then
if t.Selected then
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
begin
t.y := t.y - Bnd.y;
t.Selected := False;
Bnd.Objects.Add(t);
end;
end;
for j := 0 to RTObjects.Count - 1 do // placing subreports over band
begin
t :=TfrView(RTObjects[j]);
if (t.Parent = nil) and (t.Typ = gtSubReport) then
if t.Selected then
if (t.y >= Bnd.y) and (t.y <= Bnd.y + Bnd.dy) then
begin
t.Parent := Bnd;
t.y := t.y - Bnd.y;
t.Selected := False;
Bnd.Objects.Add(t);
end;
end;
end;
end;
for i := 0 to Last - 1 do // sorting bands
begin
miny := BArr[i].y; n := i;
for j := i + 1 to Last - 1 do
if BArr[j].y < miny then
begin
miny := BArr[j].y;
n := j;
end;
Bnd := BArr[i]; BArr[i] := BArr[n]; BArr[n] := Bnd;
end;
Bnd := BArr[0]; Bands[b] := Bnd;
Bnd.Prev := nil;
for i := 1 to Last - 1 do // finally ordering
begin
Bnd.Next := BArr[i];
Bnd := Bnd.Next;
Bnd.Prev := BArr[i - 1];
end;
Bnd.Next := nil;
Bands[b].LastBand := Bnd;
end;
for i := 0 to RTObjects.Count - 1 do // place other objects on btNone band
begin
t :=TfrView(RTObjects[i]);
if t.Selected then
begin
t.Parent := Bands[btNone];
Bands[btNone].y := 0;
Bands[btNone].Objects.Add(t);
end;
end;
for i := 1 to MAXBNDS do // connect header & footer to each data-band
begin
Bnd := Bands[Bnds[i, bpHeader]];
while Bnd <> nil do
begin
Bnd1 := Bands[Bnds[i, bpData]];
while Bnd1 <> nil do
begin
if Bnd1.y > Bnd.y + Bnd.dy then break;
Bnd1 := Bnd1.Next;
end;
if (Bnd1 <> nil) and (Bnd1.HeaderBand = nil) then
Bnd1.HeaderBand := Bnd;
Bnd := Bnd.Next;
end;
Bnd := Bands[Bnds[i, bpFooter]];
while Bnd <> nil do
begin
Bnd1 := Bands[Bnds[i, bpData]];
while Bnd1 <> nil do
begin
if Bnd1.y + Bnd1.dy > Bnd.y then
begin
Bnd1 := Bnd1.Prev;
break;
end;
if Bnd1.Next = nil then break;
Bnd1 := Bnd1.Next;
end;
if (Bnd1 <> nil) and (Bnd1.FooterBand = nil) then
Bnd1.FooterBand := Bnd;
Bnd := Bnd.Next;
end;
end;
Bnd := Bands[btGroupHeader].LastBand;
Bnd1 := Bands[btGroupFooter];
repeat
Bnd.FooterBand := Bnd1;
Bnd := Bnd.Prev;
Bnd1 := Bnd1.Next;
until (Bnd = nil) or (Bnd1 = nil);
if BandExists(Bands[btCrossData]) and (Pos(';', TfrBandView(Bands[btCrossData].View).DataSet) <> 0) then
begin
s := TfrBandView(Bands[btCrossData].View).DataSet;
i := 1;
while i < Length(s) do
begin
j := i;
while s[j] <> '=' do Inc(j);
n := j;
while s[n] <> ';' do Inc(n);
for b := btMasterHeader to btGroupFooter do
begin
Bnd := Bands[b];
while Bnd <> nil do
begin
if Bnd.View <> nil then
if AnsiCompareText(Bnd.View.Name, Copy(s, i, j - i)) = 0 then
CreateDS(Copy(s, j + 1, n - j - 1), Bnd.VCDataSet, Bnd.IsVirtualVCDS);
Bnd := Bnd.Next;
end;
end;
i := n + 1;
end;
end;
if ColCount = 0 then ColCount := 1;
ColWidth := (RightMargin - LeftMargin) div ColCount;
end;
procedure TfrPage.PrepareObjects;
var
i, j: Integer;
t: TfrView;
Value: TfrValue;
s: String;
DSet: TfrTDataSet;
Field: TfrTField;
begin
if (MasterReport.DoublePass and MasterReport.FinalPass) then Exit;
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
t.FDataSet := DSet;
t.FField := Field.FieldName;
end;
end
else if Value.Typ = vtDBField then
if Value.DSet <> nil then
begin
t.FDataSet := Value.DSet;
t.FField := Value.Field;
end;
end;
end;
end;
procedure TfrPage.ShowBand(b: TfrBand);
begin
if b <> nil then
begin
{$IFDEF DebugLR}
DebugLn('%sTfrPage.ShowBand INI b=%s:%s',[sspc,dbgsname(b),typ2str(b.typ)]);
IncSpc(1);
{$ENDIF}
if Mode = pmBuildList then
AddRecord(b, rtShowBand) else
b.Draw;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrPage.ShowBand END b=%s:%s',[sspc,dbgsname(b),typ2str(b.typ)]);
{$ENDIF}
end;
end;
constructor TfrPage.Create;
begin
inherited Create;
fMargins:=TfrRect.Create;
BaseName:='Page';
List := TList.Create;
Objects := TList.Create;
RTObjects := TList.Create;
PageType:=ptReport;
end;
procedure TfrPage.ShowBandByName(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('%sTFrPage.DrawPageFootersPage INI PageNo=%d XAdjust=%d CurColumn=%d',
[sspc,PageNo, XAdjust, CurColumn]);
{$ENDIF}
CurColumn := 0;
XAdjust := LeftMargin;
if (PageNo <> 0) or ((Bands[btPageFooter].Flags and flBandOnFirstPage) <> 0) then
while PageNo < MasterReport.EMFPages.Count do
begin
if not (Append and WasPF) then
begin
if (CurReport <> nil) and Assigned(CurReport.FOnEndPage) then
CurReport.FOnEndPage(PageNo);
if (MasterReport <> CurReport) and (MasterReport <> nil) and
Assigned(MasterReport.FOnEndPage) then
MasterReport.FOnEndPage(PageNo);
if not RowsLayout then
ShowBand(Bands[btPageFooter]);
end;
Inc(PageNo);
end;
PageNo := MasterReport.EMFPages.Count;
{$IFDEF DebugLR}
DebugLn('%sTFrPage.DrawPageFootersPage FIN PageNo=%d XAdjust=%d CurColumn=%d',
[sspc, PageNo, XAdjust, CurColumn]);
{$ENDIF}
end;
procedure TfrPage.NewPage;
begin
{$IFDEF DebugLR}
DebugLn('%sTFrPage.NewPage INI PageNo=%d CurBottomY=%d CurY=%d XAdjust=%d',
[sspc,PageNo, CurBottomY, CurY, XAdjust]);
IncSpc(1);
{$ENDIF}
CurReport.InternalOnProgress(PageNo + 1);
if not RowsLayout then
ShowBand(Bands[btColumnFooter]);
DrawPageFooters;
CurBottomY := BottomMargin;
MasterReport.EMFPages.Add(Self);
Append := False;
ShowBand(Bands[btOverlay]);
CurY := TopMargin;
ShowBand(Bands[btPageHeader]);
if not RowsLayout then
ShowBand(Bands[btColumnHeader]);
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTFrPage.NewPage END PageNo=%d CurBottomY=%d CurY=%d XAdjust=%d',
[sspc,PageNo, CurBottomY, CurY, XAdjust]);
{$ENDIF}
end;
procedure TfrPage.NewColumn(Band: TfrBand);
var
b: TfrBand;
begin
{$IFDEF DebugLR}
DebugLn('%sTfrPage.NewColumn INI CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
[sspc,CurColumn, ColCount, CurY, XAdjust]);
IncSpc(1);
{$ENDIF}
if CurColumn < ColCount - 1 then
begin
ShowBand(Bands[btColumnFooter]);
Inc(CurColumn);
Inc(XAdjust, ColWidth + ColGap);
CurY := LastStaticColumnY;
ShowBand(Bands[btColumnHeader]);
end
else
NewPage;
b := Bands[btGroupHeader];
if b <> nil then
while (b <> nil) and (b <> Band) do
begin
b.DisableInit := True;
if (b.Flags and flBandRepeatHeader) <> 0 then
ShowBand(b);
b.DisableInit := False;
b := b.Next;
end;
if Band.Typ in [btMasterData, btDetailData, btSubDetailData] then
if (Band.HeaderBand <> nil) and
((Band.HeaderBand.Flags and flBandRepeatHeader) <> 0) then
ShowBand(Band.HeaderBand);
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrPage.NewColumn END CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
[sspc,CurColumn, ColCount, CurY, XAdjust]);
{$ENDIF}
end;
procedure TfrPage.NextColumn(Band: TFrBand);
begin
{$IFDEF DebugLR}
DebugLn('%sTfrPage.NextColumn INI CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
[sspc,CurColumn, ColCount, CurY, XAdjust]);
IncSpc(1);
{$ENDIF}
if CurColumn < ColCount - 1 then
begin
Inc(CurColumn);
Inc(XAdjust, ColWidth + ColGap);
Inc(ColPos);
end
else
begin
CurColumn := 0;
ColPos:=1;
XAdjust := LeftMargin;
end;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrPage.NextColumn END CurColumn=%d ColCount=%d CurY=%d XAdjust=%d',
[sspc,CurColumn, ColCount, CurY, XAdjust]);
{$ENDIF}
end;
function TfrPage.RowsLayout: boolean;
begin
// esta funcion debe leerse de las opciones de la pagina
result := (ColCount>1) and (LayoutOrder=loRows)
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;
procedure AddToStack(b: TfrBand);
begin
if b <> nil then
begin
Inc(BndStackTop);
BndStack[BndStackTop] := b;
end;
end;
procedure BackupBookmark(b: TfrBand);
var
n: Integer;
begin
n := Length(BooksBkUp);
SetLength(BooksBkUp, n+1);
BooksBkUp[n].Dataset := b.Dataset;
BooksBkUp[n].Bookmark := b.Dataset.GetBookmark;
if b.Typ in [btDetailData,btSubDetailData] then
inc(DetailCount);
end;
procedure RestoreBookmarks;
var
n: Integer;
begin
for n:=0 to Length(BooksBkUp)-1 do
with BooksBkUp[n] do begin
Dataset.GotoBookMark(Bookmark);
Dataset.FreeBookMark(Bookmark);
if DetailCount=0 then
Dataset.EnableControls;
end;
SetLength(BooksBkUp, 0);
end;
procedure DisableControls;
var
n: Integer;
begin
if DetailCount=0 then
for n:=0 to Length(BooksBkUp)-1 do
BooksBkUp[n].Dataset.DisableControls;
end;
procedure ShowStack;
var
i: Integer;
begin
{$IFDEF DebugLR}
DebugLn('%sShowStack INI',[sspc]);
{$ENDIF}
for i := 1 to BndStackTop do
if BandExists(BndStack[i]) then
ShowBand(BndStack[i]);
BndStackTop := 0;
{$IFDEF DebugLR}
DebugLn('%sShowStack END',[sspc]);
{$ENDIF}
end;
procedure DoLoop(Level: Integer);
var
WasPrinted: Boolean;
b, b1, b2: TfrBand;
BM : Pointer;
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
{$IFDEF DebugLR}
DebugLn('%sDoop(Level=%d) INI',[sspc,Level]);
IncSpc(1);
{$ENDIF}
b := Bands[Bnds[Level, bpData]];
while (b <> nil) and (b.Dataset <> nil) do
begin
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;
b.DataSet.Next;
if (Level = 1) and HasGroups then
begin
b1 := Bands[btGroupHeader];
while b1 <> nil do
begin
if (frParser.Calc(b1.GroupCondition) <> b1.LastGroupValue) or
b.Dataset.Eof then
begin
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);
if not b.DataSet.Eof then
begin
if b1.NewPageAfter then NewPage;
InitGroups(b1);
ShowBand(b.HeaderBand);
b.Positions[psLocal] := 0;
end;
break;
end;
b1 := b1.Next;
end;
end;
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
NewPage;
end;
if MasterReport.Terminated then
break;
end;
if BndStackTop = 0 then
ShowBand(b.FooterBand) else
Dec(BndStackTop);
end;
finally
end;
b := b.Next;
end;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sDoop(Level=%d) END',[sspc,Level]);
{$ENDIF}
end;
begin
{$IFDEF DebugLR}
DebugLn('%sTfrPage.FormPage INI Mode=%d',[sspc,ord(mode)]);
IncSpc(1);
{$ENDIF}
if Mode = pmNormal then
begin
if Append then
begin
if PrevY = PrevBottomY then
begin
Append := False;
WasPF := False;
PageNo := MasterReport.EMFPages.Count;
end;
end;
if Append and WasPF then
CurBottomY := PrevBottomY
else
CurBottomY := BottomMargin;
CurColumn := 0;
XAdjust := LeftMargin;
{$IFDEF DebugLR}
DebugLn('%sXAdjust=%d CurBottomY=%d PrevY=%d',[sspc,XAdjust,CurBottomY,PrevY]);
{$ENDIF}
if not Append then
begin
MasterReport.EMFPages.Add(Self);
CurY := TopMargin;
ShowBand(Bands[btOverlay]);
ShowBand(Bands[btNone]);
end
else
CurY := PrevY;
sfPage := PageNo;
{$IFDEF DebugLR}
DebugLn('%sXAdjust=%d CurY=%d sfPage=%d',[sspc,XAdjust,CurY,sfpage]);
{$ENDIF}
ShowBand(Bands[btReportTitle]);
if PageNo = sfPage then // check if new page was formed
begin
if BandExists(Bands[btPageHeader]) and
((Bands[btPageHeader].Flags and flBandOnFirstPage) <> 0) then
ShowBand(Bands[btPageHeader]);
if not RowsLayout then
ShowBand(Bands[btColumnHeader]);
end;
end;
BndStackTop := 0;
SetLength(BooksBkUp, 0);
DetailCount := 0;
for i := 1 to MAXBNDS do
begin
if BandExists(Bands[Bnds[i, bpData]]) then
begin
MaxLevel := i;
BackupBookmark(Bands[Bnds[i, bpData]]);
end;
end;
HasGroups := Bands[btGroupHeader].Objects.Count > 0;
{$IFDEF DebugLR}
DebugLn('%sMaxLevel=%d doing DoLoop(1)',[sspc,MaxLevel]);
{$ENDIF}
DisableControls;
DoLoop(1);
RestoreBookmarks; // this also enablecontrols
if Mode = pmNormal then
begin
if not RowsLayout then
ShowBand(Bands[btColumnFooter]);
ShowBand(Bands[btReportSummary]);
PrevY := CurY;
PrevBottomY := CurBottomY;
if CurColumn > 0 then
PrevY := BottomMargin;
CurColumn := 0;
XAdjust := LeftMargin;
sfPage := PageNo;
WasPF := False;
if (Bands[btPageFooter].Flags and flBandOnLastPage) <> 0 then
begin
WasPF := BandExists(Bands[btPageFooter]);
if WasPF then
DrawPageFooters;
end;
PageNo := sfPage + 1;
end;
{$IFDEF DebugLR}
IncSpc(-1);
DebugLn('%sTfrPage.FormPage END PrevY=%d PrevBottomY=%d PageNo=%d XAdjust=%d',
[sspc,PrevY,PrevBottomY,PageNo,XAdjust]);
{$ENDIF}
end;
function TfrPage.BandExists(b: TfrBand): Boolean;
begin
Result := b.Objects.Count > 0;
end;
procedure TfrPage.AfterPrint;
var
i: Integer;
begin
for i := 0 to HookList.Count - 1 do
TfrView(HookList[i]).OnHook(CurView);
end;
procedure TfrPage.LoadFromStream(Stream: TStream);
var
b: Byte;
s: String[6];
Bool : WordBool;
Rc : TRect;
begin
with Stream do
begin
Read(pgSize, 4);
Read(dx, 4); //Width
Read(dy, 4); //Height
Read(Rc, Sizeof(Rc));
Margins.AsRect:=Rc;
Read(b, 1);
Orientation:=TPrinterOrientation(b);
if frVersion < 23 then
Read(s[1], 6);
Read(Bool, 2);
PrintToPrevPage:=Bool;
Read(Bool, 2);
UseMargins:=Bool;
Read(fColCount, 4);
Read(fColGap, 4);
if frVersion>23 then
Read(ord(PageType), SizeOf(TfrPageType));
Read(fLayoutOrder, 4);
end;
ChangePaper(pgSize, Width, Height, Orientation);
end;
procedure TfrPage.LoadFromXML(XML: TLrXMLConfig; Path: String);
var
b:byte;
begin
inherited LoadFromXML(XML,Path);
dx := XML.GetValue(Path+'Width/Value', 0); // TODO chk
dy := XML.GetValue(Path+'Height/Value', 0); // TODO chk
b := XML.GetValue(Path+'Height/PageType', ord(PageType));
PageType:=TfrPageType(b);
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);
Write(ord(PageType), SizeOf(TfrPageType));
Write(LayoutOrder, 4);
end;
end;
procedure TfrPage.SavetoXML(XML: TLrXMLConfig; Path: String);
begin
Inherited SavetoXML(XML,Path);
XML.SetValue(Path+'Width/Value', Width);
XML.SetValue(Path+'Height/Value', Height);
XML.SetValue(Path+'Height/PageType', ord(PageType));
end;
{-----------------------------------------------------------------------}
constructor TfrPages.Create(AParent: TfrReport);
begin
inherited Create;
Parent := AParent;
FPages := TList.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.Clear;
var
i: Integer;
begin
for i := 0 to FPages.Count - 1 do
Pages[i].Free;
FPages.Clear;
end;
procedure TfrPages.Add(aClassName : string='TfrPageReport');
Var Pg : TFrPage;
Rf : TFrPageClass;
begin
Pg:=nil;
Rf:=TFrPageClass(GetClass(aClassName));
if Assigned(Rf) then
begin
Pg:=Rf.CreatePage;
if Assigned(Pg) then
begin
Pg.CreateUniqueName;
FPages.Add(Pg);
end;
end
else showMessage(Format('Class %s not found',[aClassName]))
end;
procedure TfrPages.Delete(Index: Integer);
begin
Pages[Index].Free;
FPages.Delete(Index);
end;
procedure TfrPages.LoadFromStream(Stream: TStream);
var
b: Byte;
t: TfrView;
s: String;
buf: String[8];
procedure AddObject(ot: Byte; clname: String);
begin
Stream.Read(b, 1);
Pages[b].Objects.Add(frCreateObject(ot, clname));
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 AnsiUpperCase(s) = 'TFRFRAMEDMEMOVIEW' then
AddObject(gtMemo, '')
else
AddObject(gtAddIn, s);
end
else
AddObject(b, '');
t.LoadFromStream(Stream);
if AnsiUpperCase(s) = 'TFRFRAMEDMEMOVIEW' then
Stream.Read(buf[1], 8);
end;
end;
end;
procedure TfrPages.LoadFromXML(XML: TLrXMLConfig; Path: String);
var
b: Byte;
t: TfrView;
s: string;
procedure AddObject(aPage: TFrPage; ot: Byte; clname: String);
begin
aPage.Objects.Add(frCreateObject(ot, clname));
t :=TfrView(aPage.Objects.Items[aPage.Objects.Count - 1]);
end;
var
i,j,aCount,oCount: Integer;
aTyp: byte;
aPath,aSubPath,clName: string;
begin
Clear;
{$IFDEF DebugLR}
DebugLn('TfrPages.LoadFromXML: LoadingFrom: ', Path);
{$ENDIF}
Parent.PrintToDefault:= XML.GetValue(Path+'PrintToDefault/Value', True);
Parent.DoublePass := XML.GetValue(Path+'DoublePass/Value', False); // TODO: check default
clName := XML.GetValue(Path+'SelectedPrinter/Value','');
Parent.SetPrinterTo(clName); // TODO: check default
aCount := XML.GetValue(Path+'PageCount/Value', 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);
Pages[i].LoadFromXML(XML, aPath);
oCount := XML.GetValue(aPath+'ObjectCount/Value', 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 ansiuppercase(clname)='TFRFRAMEDMEMOVIEW' then
addObject(Pages[i], gtMemo, '')
else
addObject(Pages[i], gtAddin, clName)
end else
AddObject(Pages[i], aTyp, '');
t.LoadFromXML(XML, aSubPath);
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/');
end;
procedure TfrPages.SaveToStream(Stream: TStream);
var
b: Byte;
i, j: Integer;
t: TfrView;
S:string;
begin
Stream.Write(Parent.PrintToDefault, 2);
Stream.Write(Parent.DoublePass, 2);
frWriteString(Stream, Prn.Printers[Prn.PrinterIndex]);
for i := 0 to Count - 1 do // adding pages at first
begin
b := $FF;
Stream.Write(b, 1); // page info
frWriteString(Stream, Pages[i].Classname);
Pages[i].SaveToStream(Stream);
end;
for i := 0 to Count - 1 do
begin
for j := 0 to Pages[i].Objects.Count - 1 do // then adding objects
begin
t :=TfrView(Pages[i].Objects[j]);
b := Byte(t.Typ);
Stream.Write(b, 1);
if t.Typ = gtAddIn then
frWriteString(Stream, t.ClassName);
Stream.Write(i, 1);
t.SaveToStream(Stream);
end;
end;
b := $FE;
Stream.Write(b, 1);
Parent.FVal.WriteBinaryData(Stream);
SMemo.Assign(Parent.Variables);
frWriteMemo(Stream, SMemo);
if frDataManager <> nil then
begin
b := $FD;
Stream.Write(b, 1);
frDataManager.SaveToStream(Stream);
end;
end;
procedure TfrPages.SavetoXML(XML: TLrXMLConfig; Path: String);
var
b: Byte;
i, j: Integer;
t: TfrView;
aPath,aSubPath: String;
begin
XML.SetValue(Path+'PrintToDefault/Value', Parent.PrintToDefault);
XML.SetValue(Path+'DoublePass/Value', Parent.DoublePass);
XML.SetValue(Path+'SelectedPrinter/Value', Prn.Printers[Prn.PrinterIndex]);
XML.SetValue(Path+'PageCount/Value', Count);
for i := 0 to Count - 1 do // adding pages at first
begin
aPath := Path+'Page'+IntToStr(i+1)+'/';
Pages[i].SaveToXML(XML, aPath);
XML.SetValue(aPath+'ObjectCount/Value', Pages[i].Objects.count);
for j:=0 to Pages[i].Objects.count - 1 do
begin
aSubPath := aPath + 'Object'+IntTostr(j+1)+'/';
T := TfrView(Pages[i].Objects[j]);
T.SaveToXML(XML, aSubPath);
end;
end;
Parent.FVal.WriteBinaryDataToXML(XML, Path+'FVal/');
XML.SetValue(Path+'ParentVars/Value',Parent.Variables.Text);
if frDataManager <> nil then
begin
frDataManager.SaveToXML(XML, Path+'Datamanager/');
end;
end;
{-----------------------------------------------------------------------}
constructor TfrEMFPages.Create(AParent: TfrReport);
begin
inherited Create;
Parent := AParent;
FPages := TList.Create;
end;
destructor TfrEMFPages.Destroy;
begin
Clear;
FPages.Free;
inherited Destroy;
end;
function TfrEMFPages.GetCount: Integer;
begin
Result := FPages.Count;
end;
function TfrEMFPages.GetPages(Index: Integer): PfrPageInfo;
begin
Result := FPages[Index];
end;
procedure TfrEMFPages.Clear;
begin
while FPages.Count > 0 do
Delete(0);
end;
procedure TfrEMFPages.Draw(Index: Integer; Canvas: TCanvas; DrawRect: TRect);
var
p: PfrPageInfo;
t: TfrView;
i: Integer;
sx, sy: Double;
v, IsPrinting: Boolean;
h: THandle;
begin
IsPrinting := Printer.Printing and (Canvas is TPrinterCanvas);
{$IFDEF DebugLR}
DebugLn('TfrEMFPages.Draw IsPrinting=%d PageIndex=%d Canvas.ClassName=%s '+
'CanvasPPI=%d',[ord(IsPrinting), Index, Canvas.ClassName,
Canvas.Font.pixelsPerInch]);
DebugLn('----------------------------------------------------');
{$ENDIF}
DocMode := dmPrinting;
p := FPages[Index];
with p^ do
begin
if Visible then
begin
if Page = nil then
ObjectsToPage(Index);
sx:=(DrawRect.Right-DrawRect.Left)/PrnInfo.PgW;
sy:=(DrawRect.Bottom-DrawRect.Top)/PrnInfo.PgH;
h:= Canvas.Handle;
for i := 0 to Page.Objects.Count - 1 do
begin
t :=TfrView(Page.Objects[i]);
v := True;
if not IsPrinting then
begin
with t, DrawRect do
begin
v := RectVisible(h, Rect(Round(x * sx) + Left - 10,
Round(y * sy) + Top - 10,
Round((x + dx) * sx) + Left + 10,
Round((y + dy) * sy) + Top + 10));
end;
end;
if v then
begin
t.ScaleX := sx;
t.ScaleY := sy;
t.OffsX := DrawRect.Left;
t.OffsY := DrawRect.Top;
t.IsPrinting := IsPrinting;
t.Draw(Canvas);
end;
end;
end
else
begin
Page.Free;
Page := nil;
end;
end;
end;
procedure TfrEMFPages.ExportData(Index: Integer);
var
p: PfrPageInfo;
b: Byte;
t: TfrView;
s: String;
begin
p := FPages[Index];
with p^ do
begin
Stream.Position := 0;
Stream.Read(frVersion, 1);
while Stream.Position < Stream.Size do
begin
Stream.Read(b, 1);
if b = gtAddIn then
s := ReadString(Stream) else
s := '';
t := frCreateObject(b, s);
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
Stream.Read(b, 1);
if b = gtAddIn then
s := ReadString(Stream)
else
s := '';
t := frCreateObject(b, s);
t.StreamMode := smPrinting;
t.LoadFromStream(Stream);
t.StreamMode := smDesigning;
Page.Objects.Add(t);
end;
end;
end;
procedure TfrEMFPages.PageToObjects(Index: Integer);
var
i: Integer;
p: PfrPageInfo;
t: TfrView;
begin
p := FPages[Index];
with p^ do
begin
Stream.Clear;
frVersion := frCurrentVersion;
Stream.Write(frVersion, 1);
for i := 0 to Page.Objects.Count - 1 do
begin
t :=TfrView(Page.Objects[i]);
t.StreamMode := smPrinting;
Stream.Write(t.Typ, 1);
if t.Typ = gtAddIn then
frWriteString(Stream, t.ClassName);
t.Memo1.Assign(t.Memo);
t.SaveToStream(Stream);
end;
end;
end;
procedure TfrEMFPages.Insert(Index: Integer; APage: TfrPage);
var
p: PfrPageInfo;
begin
GetMem(p, SizeOf(TfrPageInfo));
FillChar(p^, SizeOf(TfrPageInfo), 0);
if Index >= FPages.Count then
FPages.Add(p)
else
FPages.Insert(Index, p);
with p^ do
begin
Stream := TMemoryStream.Create;
frVersion := frCurrentVersion;
Stream.Write(frVersion, 1);
pgSize := APage.pgSize;
pgWidth := APage.Width;
pgHeight := APage.Height;
pgOr := APage.Orientation;
pgMargins := APage.UseMargins;
PrnInfo := APage.PrnInfo;
end;
end;
procedure TfrEMFPages.Add(APage: TfrPage);
begin
Insert(FPages.Count, APage);
if (CurReport <> nil) and Assigned(CurReport.FOnBeginPage) then
CurReport.FOnBeginPage(PageNo);
if (MasterReport <> CurReport) and (MasterReport <> nil) and
Assigned(MasterReport.FOnBeginPage) then
MasterReport.FOnBeginPage(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.LoadFromStream(AStream: TStream);
var
i, o, c: Integer;
b, compr: Byte;
p: PfrPageInfo;
s: TMemoryStream;
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;
Pict.SetBounds(0, 0, PrnInfo.PgW, PrnInfo.PgH);
Pict.Picture.Graphic.LoadFromStream(AStream);
Stream := TMemoryStream.Create;
b := frCurrentVersion;
Stream.Write(b, 1);
Pict.StreamMode := smPrinting;
Stream.Write(Pict.Typ, 1);
Pict.SaveToStream(Stream);
Pict.Free;
end;
AStream.Seek(o, soFromBeginning);
Inc(i);
until i >= c;
end;
begin
Clear;
AStream.Read(compr, 1);
if not (compr in [0, 1, 255]) then
begin
AStream.Seek(0, soFromBeginning);
ReadVersion22;
Exit;
end;
Parent.SetPrinterTo(frReadString(AStream));
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);
if compr <> 0 then
begin
s := TMemoryStream.Create;
s.CopyFrom(AStream, o - AStream.Position);
Stream := TMemoryStream.Create;
frCompressor.DeCompress(s, Stream);
s.Free;
end
else
begin
Stream := TMemoryStream.Create;
Stream.CopyFrom(AStream, o - AStream.Position);
end;
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
Prn.FillPrnInfo(PrnInfo);
end;
AStream.Seek(o, soFromBeginning);
Inc(i);
until i >= c;
end;
procedure TfrEMFPages.LoadFromXML(XML: TLrXMLConfig; 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.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
// Todo
end;
{-----------------------------------------------------------------------}
constructor TfrValues.Create;
begin
inherited Create;
FItems := TStringList.Create;
end;
destructor TfrValues.Destroy;
begin
Clear;
FItems.Free;
inherited Destroy;
end;
procedure TfrValues.WriteBinaryData(Stream: TStream);
var
i, n: Integer;
procedure WriteStr(s: String);
var
n: Byte;
begin
n := Length(s);
Stream.Write(n, 1);
Stream.Write(s[1], n);
end;
begin
with Stream do
begin
n := FItems.Count;
WriteBuffer(n, SizeOf(n));
for i := 0 to n - 1 do
with Objects[i] do
begin
WriteBuffer(Typ, SizeOf(Typ));
WriteBuffer(OtherKind, SizeOf(OtherKind));
WriteStr(DataSet);
WriteStr(Field);
WriteStr(FItems[i]);
end;
end;
end;
procedure TfrValues.WriteBinaryDataToXML(XML: TLrXMLConfig; Path: String);
var
i: integer;
aSubPath: String;
begin
XML.SetValue(Path+'Count/Value', 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', Ord(Typ));
XML.SetValue(aSubPath+'OtherKind/Value', 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;
function ReadStr: String;
var
n: Byte;
begin
Stream.Read(n, 1);
SetLength(Result, n);
Stream.Read(Result[1], n);
end;
begin
Clear;
FItems.Sorted := False;
with Stream do
begin
ReadBuffer(n, SizeOf(n));
for i := 0 to n - 1 do
begin
j := AddValue;
with Objects[j] do
begin
ReadBuffer(Typ, SizeOf(Typ));
ReadBuffer(OtherKind, SizeOf(OtherKind));
DataSet := ReadStr;
Field := ReadStr;
FItems[j] := ReadStr;
end;
end;
end;
end;
procedure TfrValues.ReadBinaryDataFromXML(XML: TLrXMLConfig; Path: String);
var
i,j,n: Integer;
aSubPath: String;
begin
clear;
FItems.Sorted := False;
n := XML.GetValue(Path+'Count/Value', 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', 0)); // TODO check default value
OtherKind := XML.GetValue( aSubPath+'OtherKind/Value', 0); // TODO check default value
DataSet := XML.GetValue(aSubPath+'Dataset/Value', ''); // TODO check default value
Field := XML.GetValue(aSubPath+'Field/Value', ''); // TODO check default value
FItems[j] := XML.GetValue(aSubPath+'Item/Value', ''); // TODO check default value
end;
end;
end;
function TfrValues.GetValue(Index: Integer): TfrValue;
begin
Result := TfrValue(FItems.Objects[Index]);
end;
function TfrValues.AddValue: Integer;
begin
Result := FItems.AddObject('', TfrValue.Create);
end;
procedure TfrValues.Clear;
var
i: Integer;
begin
for i := 0 to FItems.Count - 1 do
TfrValue(FItems.Objects[i]).Free;
FItems.Clear;
end;
function TfrValues.FindVariable(const s: String): TfrValue;
var
i: Integer;
begin
Result := nil;
i := FItems.IndexOf(s);
if i <> -1 then
Result := Objects[i];
end;
{----------------------------------------------------------------------------}
constructor TfrReport.Create(AOwner: TComponent);
const
Clr: Array[0..1] of TColor = (clWhite, clSilver);
var
j: Integer;
i: Integer;
begin
inherited Create(AOwner);
if not FRInitialized then
begin
FRInitialized := True;
SBmp := TBitmap.Create;
TempBmp := TBitmap.Create;
SBmp.Width := 8;
SBmp.Height := 8;
TempBmp.Width := 8;
TempBmp.Height := 8;
for j := 0 to 7 do
begin
for i := 0 to 7 do
SBmp.Canvas.Pixels[i, j] := Clr[(j + i) mod 2];
end;
frProgressForm := TfrProgressForm.Create(nil);
end;
FPages := TfrPages.Create(Self);
FEMFPages := TfrEMFPages.Create(Self);
FVars := TStringList.Create;
FVal := TfrValues.Create;
FShowProgress := True;
FModalPreview := True;
FModifyPrepared := True;
FPreviewButtons := [pbZoom, pbLoad, pbSave, pbPrint, pbFind, pbHelp, pbExit];
FInitialZoom := pzDefault;
FileName := sUntitled;
FComments:=TStringList.Create;
end;
destructor TfrReport.Destroy;
begin
if CurReport=Self then
CurReport:=nil;
FVal.Free;
FVars.Free;
FEMFPages.Free;
FEMFPages := nil;
FPages.Free;
FComments.Free;
inherited Destroy;
end;
procedure TfrReport.Clear;
begin
Pages.Clear;
if frDataManager <> nil then
frDataManager.Clear;
DoublePass := False;
ClearAttribs;
DocMode := dmDesigning;
end;
procedure TfrReport.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineBinaryProperty('ReportForm', @ReadBinaryData, @WriteBinaryData, True);
end;
procedure TfrReport.WriteBinaryData(Stream: TStream);
var
n: Integer;
Stream1: TMemoryStream;
begin
n := frCurrentVersion;
Stream.Write(n, 4);
if FStoreInDFM then
begin
Stream1 := TMemoryStream.Create;
SaveToStream(Stream1);
Stream1.Position := 0;
n := Stream1.Size;
Stream.Write(n, 4);
Stream.CopyFrom(Stream1, n);
Stream1.Free;
end;
end;
procedure TfrReport.ReadBinaryData(Stream: TStream);
var
n: Integer;
Stream1: TMemoryStream;
begin
Stream.Read(n, 4); // version
if FStoreInDFM then
begin
Stream.Read(n, 4);
Stream1 := TMemoryStream.Create;
Stream1.CopyFrom(Stream, n);
Stream1.Position := 0;
LoadFromStream(Stream1);
Stream1.Free;
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;
V : Variant;
ValStr: String;
begin
SubValue := '';
AFormat := CurView.Format;
AFormatStr := CurView.FormatStr;
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('%sTfrReport.InternalOnGetValue(%s) Value=%s',[sspc,ParName,ParValue]);
{$ENDIF}
end;
procedure TfrReport.InternalOnEnterRect(Memo: TStringList; View: TfrView);
begin
with View do
if (FDataSet <> nil) and frIsBlob(TfrTField(FDataSet.FindField(FField))) then
GetBlob(TfrTField(FDataSet.FindField(FField)));
if Assigned(FOnEnterRect) then
FOnEnterRect(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.InternalOnBeginColumn(Band: TfrBand);
begin
if Assigned(FOnBeginColumn) then FOnBeginColumn(Band);
end;
procedure TfrReport.InternalOnPrintColumn(ColNo: Integer; var ColWidth: Integer);
begin
if Assigned(FOnPrintColumn) then FOnPrintColumn(ColNo, ColWidth);
end;
function TfrReport.FormatValue(V: Variant;
AFormat: Integer;
const AFormatStr: String): String;
var
f1, f2: Integer;
c: Char;
s: String;
begin
if (TVarData(v).VType = varEmpty) {VarIsEmpty(v)} or VarIsNull(v) then
begin
Result := ' ';
Exit;
end;
c := DecimalSeparator;
f1 := (AFormat div $01000000) and $0F;
f2 := (AFormat div $00010000) and $FF;
try
case f1 of
fmtText:
begin
if VarIsType(v, varDate) and (trunc(Extended(v))=0) then
Result := TimeToStr(v)
else
Result := v;
end;
fmtNumber:
begin
DecimalSeparator := Chr(AFormat and $FF);
case f2 of
0: Result := FormatFloat('###.##', v);
1: Result := FloatToStrF(Extended(v), ffFixed, 15, (AFormat div $0100) and $FF);
2: Result := FormatFloat('#,###.##', v);
3: Result := FloatToStrF(Extended(v), ffNumber, 15, (AFormat div $0100) and $FF);
4: Result := FormatFloat(AFormatStr, v);
end;
end;
fmtDate:
if f2 = 4 then
Result := FormatDateTime(AFormatStr, v)
else
Result := FormatDateTime(frDateFormats[f2], v);
fmtTime:
if f2 = 4 then
Result := FormatDateTime(AFormatStr, v)
else
Result := FormatDateTime(frTimeFormats[f2], v);
fmtBoolean :
begin
if f2 = 4 then
s := AFormatStr
else
s := BoolStr[f2];
if Integer(v) = 0 then
Result := Copy(s, 1, Pos(';', s) - 1)
else
Result := Copy(s, Pos(';', s) + 1, 255);
end;
end;
except
on e:exception do
Result := v;
end;
DecimalSeparator := c;
end;
{
function TfrReport.GetLRTitle: String;
begin
if csDesigning in ComponentState then
Result:=fDefaultTitle
else
begin
if fTitle<>'' then
Result:=fTitle
else
Result:=fDefaultTitle;
end;
end;
}
procedure TfrReport.GetVariableValue(const s: String; var aValue: Variant);
var
Value: TfrValue;
D: TfrTDataSet;
F: TfrTField;
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;
if Assigned(FOnGetValue) then
FOnGetValue(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:=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
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:=F.AsVariant
end
else if s = 'VALUE' then
aValue:= CurValue
else if s = frSpecFuncs[0] then
aValue:= PageNo + 1
else if s = frSpecFuncs[2] then
aValue := CurDate
else if s = frSpecFuncs[3] then
aValue:= CurTime
else if s = frSpecFuncs[4] then
aValue:= MasterBand.Positions[psLocal]
else if s = frSpecFuncs[5] then
aValue:= MasterBand.Positions[psGlobal]
else if s = frSpecFuncs[6] then
aValue:= CurPage.ColPos
else if s = frSpecFuncs[7] then
aValue:= CurPage.CurPos
else if s = frSpecFuncs[8] then
aValue:= SavedAllPages
else
begin
if frVariables.IndexOf(s) <> -1 then
begin
aValue:= frVariables[s];
Exit;
end;
if s <> SubValue then
begin
SubValue := s;
aValue:= frParser.Calc(s);
SubValue := '';
end
else raise(EParserError.Create('Undefined symbol ";"' + SubValue + ';'));
end;
end;
end;
end;
procedure TfrReport.OnGetParsFunction(const aName: String; p1, p2, p3: Variant;
var val: Variant);
var
i: Integer;
begin
// val := '0';
val := varempty;
for i := 0 to frFunctionsCount - 1 do
if frFunctions[i].FunctionLibrary.OnFunction(aName, p1, p2, p3, val) then
exit;
if AggrBand.Visible then
if Assigned(FOnFunction) then
FOnFunction(aName, p1, p2, p3, val);
end;
// load/save methods
procedure TfrReport.LoadFromStream(Stream: TStream);
begin
CurReport := Self;
Stream.Read(frVersion, 1);
if frVersion < 21 then
begin
frVersion := 21;
Stream.Position := 0;
end;
if frVersion <= frCurrentVersion then
try
{$IFDEF FREEREP2217READ}
if FRE_COMPATIBLE_READ and (frVersion = 23) then
frVersion := 22;
{$ENDIF}
Pages.LoadFromStream(Stream);
except
Pages.Clear;
Pages.Add;
MessageDlg(sFRFError,mtError,[mbOk],0)
end
else
MessageDlg(sFRFError,mtError,[mbOk],0);
end;
procedure TfrReport.LoadFromXML(XML: TLrXMLConfig; Path: String);
begin
CurReport := Self;
frVersion := XML.GetValue(Path+'Version/Value', 21);
fComments.Text := XML.GetValue(Path+'Comments/Value', '');
fKeyWords := XML.GetValue(Path+'KeyWords/Value', '');
fSubject := XML.GetValue(Path+'Subject/Value', '');
fTitle := XML.GetValue(Path+'Title/Value', '');
// XML.SetValue(Path+'ReportCreateDate/Value', FReportCreateDate);
// XML.SetValue(Path+'ReportCreateDate/Value', FReportLastChange);
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', '');
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
Pages.Clear;
Pages.Add;
MessageDlg(sFRFError,mtError,[mbOk],0)
end
else
MessageDlg(sFRFError,mtError,[mbOk],0);
end;
procedure TfrReport.SaveToStream(Stream: TStream);
begin
CurReport := Self;
frVersion := frCurrentVersion;
Stream.Write(frVersion, 1);
Pages.SaveToStream(Stream);
end;
procedure TfrReport.LoadFromFile(FName: String);
var
Stream: TFileStream;
Ext : String;
begin
Ext:=ExtractFileExt(fName);
if SameText('.lrf',Ext) then
LoadFromXMLFile(fName)
else
begin
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
LoadFromStream(Stream);
Stream.Free;
FileName := FName;
end;
end;
procedure TfrReport.LoadFromXMLFile(Fname: String);
var
XML: TLrXMLConfig;
begin
{$IFDEF ver2_0_0}
XML := TLrXMLConfig.Create(FName);
{$ELSE}
XML := TLrXMLConfig.Create(nil);
XML.Filename := FName;
{$ENDIF}
try
LoadFromXML(XML, 'LazReport/');
FileName := FName;
finally
XML.Free;
end;
end;
procedure TfrReport.SaveToFile(FName: String);
var
Stream: TFileStream;
Ext : string;
begin
Ext:=ExtractFileExt(fName);
if (Ext='') or (Ext='.') then
begin
Ext:='.lrf';
fName:=ChangeFileExt(fName,Ext);
end;
if SameText('.lrf',Ext) then
SaveToXMLFile(fName)
else
begin
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
SaveToStream(Stream);
Stream.Free;
end;
end;
procedure TfrReport.SavetoXML(XML: TLrXMLConfig; Path: String);
begin
CurReport := Self;
frVersion := frCurrentVersion;
XML.SetValue(Path+'Version/Value', 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', FReportCreateDate);
// XML.SetValue(Path+'ReportCreateDate/Value', 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);
Pages.SaveToXML(XML, Path+'Pages/');
end;
procedure TfrReport.SaveToXMLFile(FName: String);
var
XML: TLrXMLConfig;
begin
{$IFDEF ver2_0_0}
XML := TLrXMLConfig.CreateClean(FName);
{$ELSE}
XML := TLrXMLConfig.Create(nil);
XML.StartEmpty := True;
XML.Filename := FName;
{$ENDIF}
try
SaveToXML(XML, 'LazReport/');
XML.Flush;
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(FName: String);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
EMFPages.LoadFromStream(Stream);
Stream.Free;
CanRebuild := False;
end;
procedure TfrReport.SavePreparedReport(FName: String);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
EMFPages.SaveToStream(Stream);
Stream.Free;
end;
procedure TfrReport.LoadTemplate(FName: String; comm: TStrings;
Bmp: TBitmap; Load: Boolean);
var
Stream: TFileStream;
b: Byte;
fb: TBitmap;
fm: TStringList;
pos: Integer;
begin
fb := TBitmap.Create;
fm := TStringList.Create;
Stream := TFileStream.Create(UTF8ToSys(FName), fmOpenRead);
if Load then
begin
ReadMemo(Stream, fm);
Stream.Read(pos, 4);
Stream.Read(b, 1);
if b <> 0 then
fb.LoadFromStream(Stream);
Stream.Position := pos;
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.SaveTemplate(FName: String; Comm: TStrings; Bmp: TBitmap);
var
Stream: TFileStream;
b: Byte;
pos, lpos: Integer;
begin
Stream := TFileStream.Create(UTF8ToSys(FName), fmCreate);
frWriteMemo(Stream, Comm);
b := 0;
pos := Stream.Position;
lpos := 0;
Stream.Write(lpos, 4);
if Bmp.Empty then
Stream.Write(b, 1)
else
begin
b := 1;
Stream.Write(b, 1);
Bmp.SaveToStream(Stream);
end;
lpos := Stream.Position;
Stream.Position := pos;
Stream.Write(lpos, 4);
Stream.Position := lpos;
Pages.SaveToStream(Stream);
Stream.Free;
end;
// report manipulation methods
procedure TfrReport.DesignReport;
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
{$IFDEF MODALDESIGNER}
frDesigner.ShowModal;
{$ELSE}
frDesigner.Show;
{$ENDIF}
Application.HelpFile := HF;
end;
var
FirstPassTerminated, FirstTime: Boolean;
procedure TfrReport.BuildBeforeModal(Sender: TObject);
begin
{$IFDEF DebugLR}
DebugLn('20');
{$ENDIF}
DoBuildReport;
{$IFDEF DebugLR}
DebugLn('21');
{$ENDIF}
if FinalPass then
begin
if Terminated then
frProgressForm.ModalResult := mrCancel
else
frProgressForm.ModalResult := mrOk;
end
else
begin
{$IFDEF DebugLR}
DebugLn('22');
{$ENDIF}
FirstPassTerminated := Terminated;
SavedAllPages := EMFPages.Count;
DoublePass := False;
FirstTime := False;
DoPrepareReport; // do final pass
DoublePass := True;
{$IFDEF DebugLR}
DebugLn('23');
{$ENDIF}
end;
end;
function TfrReport.PrepareReport: Boolean;
var
ParamOk: Boolean;
begin
DocMode := dmPrinting;
CurDate := Date;
CurTime := Time;
MasterReport := Self;
CurReport := Self;
Values.Items.Sorted := True;
frParser.OnGetValue := @GetVariableValue;
frParser.OnFunction := @OnGetParsFunction;
if Assigned(FOnBeginDoc) then FOnBeginDoc;
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;
if Assigned(FOnEndDoc) then
FOnEndDoc;
end;
function TfrReport.DoPrepareReport: Boolean;
var
s: String;
begin
Result := True;
Terminated := False;
Append := False;
DisableDrawing := False;
FinalPass := True;
FirstTime := True;
PageNo := 0;
EMFPages.Clear;
{$IFDEF DebugLR}
DebugLn('DoPrepareReport DoublePass=',BoolToStr(DoublePass));
{$ENDIF}
s := sReportPreparing;
if DoublePass then
begin
{$IFDEF DebugLR}
DebugLn('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}
DebugLn('DoPrepareReport FirstPass End');
{$ENDIF}
end
else BuildBeforeModal(nil);
Exit;
end;
if not Assigned(FOnProgress) and FShowProgress then
begin
{$IFDEF DebugLR}
DebugLn('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}
DebugLn('DoPrepareReport SecondPass End');
{$ENDIF}
end;
end
else BuildBeforeModal(nil);
Terminated := False;
end;
var
ExportStream: TFileStream;
procedure TfrReport.ExportBeforeModal(Sender: TObject);
var
i: Integer;
begin
Application.ProcessMessages;
for i := 0 to EMFPages.Count - 1 do
begin
FCurrentFilter.OnBeginPage;
EMFPages.ExportData(i);
InternalOnProgress(i + 1);
Application.ProcessMessages;
FCurrentFilter.OnEndPage;
end;
FCurrentFilter.OnEndDoc;
frProgressForm.ModalResult := mrOk;
end;
procedure TfrReport.ExportTo(Filter: TClass; aFileName: String);
var
s: String;
begin
ExportStream := TFileStream.Create(UTF8ToSys(aFileName), fmCreate);
FCurrentFilter := TfrExportFilter(Filter.NewInstance);
FCurrentFilter.Create(ExportStream);
FCurrentFilter.OnBeginDoc;
CurReport := Self;
MasterReport := Self;
SavedAllPages := EMFPages.Count;
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;
FCurrentFilter.Free;
FCurrentFilter := nil;
ExportStream.Free;
end;
procedure TfrReport.FillQueryParams;
var
i, j: Integer;
t: TfrView;
procedure PrepareDS(ds: TfrDataSet);
begin
if (ds <> nil) and (ds is TfrDBDataSet) then
frDataManager.PrepareDataSet(TfrTDataSet((ds as TfrDBDataSet).GetDataSet));
end;
begin
if frDataManager = nil then Exit;
frDataManager.BeforePreparing;
if Dataset <> nil then
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) as TfrDataSet);
end;
frDataManager.AfterPreparing;
end;
procedure TfrReport.DoBuildReport;
var
i : Integer;
b : Boolean;
BM : Pointer;
begin
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
for i := 0 to Pages.Count - 1 do
Pages[i].Skip := False;
for i := 0 to Pages.Count - 1 do
Pages[i].InitReport;
PrepareDataSets;
for i := 0 to Pages.Count - 1 do
if Pages[i].PageType = ptReport 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].PageType = ptReport then
begin
FCurPage := Pages[i];
if FCurPage.Skip then
Continue;
FCurPage.Mode := pmNormal;
if Assigned(FOnManualBuild) then
FOnManualBuild(FCurPage)
else
FCurPage.FormPage;
{$IFDEF DebugLR}
debugLn('p3');
{$ENDIF}
Append := False;
if ((i = Pages.Count - 1) and CompositeMode and (not b or Dataset.Eof)) or
((i <> Pages.Count - 1) and Pages[i + 1].PrintToPrevPage) then
begin
Dec(PageNo);
Append := True;
end;
if not Append then
begin
PageNo := MasterReport.EMFPages.Count;
InternalOnProgress(PageNo);
end;
if MasterReport.Terminated then
Break;
end;
end;
{$IFDEF DebugLR}
DebugLn('p4');
{$ENDIF}
InternalOnProgress(PageNo);
if b then
Dataset.Next;
until MasterReport.Terminated or not b or Dataset.Eof;
for i := 0 to Pages.Count - 1 do
Pages[i].DoneReport;
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;
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
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);
{$IFDEF DebugLR}
DebugLn('1 TfrPreviewForm.visible=',BooLToStr(p.Visible));
{$ENDIF}
p.Caption := s;
{$IFDEF DebugLR}
DebugLn('2 TfrPreviewForm.visible=',BooLToStr(p.Visible));
{$ENDIF}
p.Show_Modal(Self);
end;
end;
procedure TfrReport.PrintBeforeModal(Sender: TObject);
begin
DoPrintReport(FPageNumbers, FCopies);
frProgressForm.ModalResult := mrOk;
end;
procedure TfrReport.PrintPreparedReport(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(PageNumbers: String; Copies: Integer);
var
i, j: Integer;
f: Boolean;
pgList: TStringList;
procedure ParsePageNumbers;
var
i, j, n1, n2: Integer;
s: String;
IsRange: Boolean;
begin
s := PageNumbers;
while Pos(' ', s) <> 0 do
Delete(s, Pos(' ', s), 1);
if s = '' then Exit;
s := s + ',';
i := 1; j := 1; n1 := 1;
IsRange := False;
while i <= Length(s) do
begin
if s[i] = ',' then
begin
n2 := StrToInt(Copy(s, j, i - j));
j := i + 1;
if IsRange then
begin
while n1 <= n2 do
begin
pgList.Add(IntToStr(n1));
Inc(n1);
end;
end
else
pgList.Add(IntToStr(n2));
IsRange := False;
end
else if s[i] = '-' then
begin
IsRange := True;
n1 := StrToInt(Copy(s, j, i - j));
j := i + 1;
end;
Inc(i);
end;
end;
procedure PrintPage(n: Integer);
begin
with Printer, EMFPages[n]^ do
begin
if not Prn.IsEqual(pgSize, pgWidth, pgHeight, pgOr) then
begin
EndDoc;
Prn.SetPrinterInfo(pgSize, pgWidth, pgHeight, pgOr);
BeginDoc;
end
else if not f then
NewPage;
Prn.FillPrnInfo(PrnInfo);
Visible := True;
with PrnInfo do
begin
if pgMargins then
EMFPages.Draw(n, Printer.Canvas, Rect(-POfx, -POfy, PPgw - POfx, PPgh - POfy))
else
EMFPages.Draw(n, Printer.Canvas, Rect(0, 0, PPw, PPh));
end;
Visible := False;
EMFPages.Draw(n, Printer.Canvas, Rect(0, 0, 0, 0));
end;
InternalOnProgress(n + 1);
Application.ProcessMessages;
f := False;
end;
{$IFDEF DebugLR}
procedure DebugPrnInfo(msg: string);
var
k: integer;
begin
DebugLn('--------------------------------------------------');
DebugLn(Msg);
for k:=0 to EMFPages.Count-1 do begin
DebugLn('EMFPage ',dbgs(k));
with EmfPages[k]^.PrnInfo do begin
DebugLn(Format(' Ppgw=%d PPgh=%d Pgw=%d Pgh=%d',[PPgw,PPgh,Pgw,Pgh]));
DebugLn(Format(' Pofx=%d POfy=%d Ofx=%d Ofy=%d',[POfx,POfy,Ofx,Ofy]));
DebugLn(Format(' Ppw=%d Pph=%d Pw=%d Ph=%d',[Ppw,Pph,Pw,Ph]));
end;
end;
end;
{$ENDIF}
begin
{$IFDEF DebugLR}
DebugLn('DoPrintReport INIT');
DebugPrnInfo('=== INIT');
{$ENDIF}
Prn.Printer := Printer;
pgList := TStringList.Create;
ParsePageNumbers;
if Copies <= 0 then
Copies := 1;
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('LazReport : %s',[Title])
else
Printer.Title:=Format('LazReport : %s',[sUntitled]);
Printer.BeginDoc;
f:= True;
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;
Printer.EndDoc;
pgList.Free;
{$IFDEF DebugLR}
DebugPrnInfo('=== END');
{$ENDIF}
end;
procedure TfrReport.SetComments(const AValue: TStringList);
begin
FComments.Assign(AValue);
end;
procedure TfrReport.SetDataset(const AValue: TfrDataset);
begin
FDataSet := AValue;
end;
// printer manipulation methods
procedure TfrReport.SetPrinterTo(PrnName: String);
begin
{$ifdef dbgPrinter}
DebugLn('TfrReport.SetPrinterTo PrnName=%s PrintToDefault=%d PrnExist?=%d PrnIndex=%d PrinterIndex=%d Name=%s',
[prnName, Ord(PrintToDefault), Ord(Prn.Printers.IndexOf(PrnName)>=0),
prn.PrinterIndex, Prn.Printer.PrinterIndex, prn.Printer.Printers[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;
end;
procedure TfrReport.SetReportAutor(const AValue: string);
begin
if FReportAutor=AValue then exit;
FReportAutor:=AValue;
end;
procedure TfrReport.SetReportCreateDate(const AValue: TDateTime);
begin
if FReportCreateDate=AValue then exit;
FReportCreateDate:=AValue;
end;
procedure TfrReport.SetReportLastChange(const AValue: TDateTime);
begin
if FReportLastChange=AValue then exit;
FReportLastChange:=AValue;
end;
procedure TfrReport.SetReportVersionBuild(const AValue: string);
begin
if FReportVersionBuild=AValue then exit;
FReportVersionBuild:=AValue;
end;
procedure TfrReport.SetReportVersionMajor(const AValue: string);
begin
if FReportVersionMajor=AValue then exit;
FReportVersionMajor:=AValue;
end;
procedure TfrReport.SetReportVersionMinor(const AValue: string);
begin
if FReportVersionMinor=AValue then exit;
FReportVersionMinor:=AValue;
end;
procedure TfrReport.SetReportVersionRelease(const AValue: string);
begin
if FReportVersionRelease=AValue then exit;
FReportVersionRelease:=AValue;
end;
function TfrReport.ChangePrinter(OldIndex, NewIndex: Integer): Boolean;
procedure ChangePages;
var
i: Integer;
begin
for i := 0 to Pages.Count - 1 do
begin
with Pages[i] do
ChangePaper(pgSize, Width, Height, Orientation);
end;
end;
begin
Result := True;
try
{$ifdef dbgPrinter}
DebugLn('TfrReport.ChangePrinter CurIndex=%d OldIndex=%d NewIndex=%d',
[Prn.PrinterIndex,OldIndex,NewIndex]);
{$endif}
Prn.PrinterIndex := NewIndex;
Prn.PaperSize := -1;
ChangePages;
except
on Exception do
begin
MessageDlg(sPrinterError,mtError,[mbOk],0);
Prn.PrinterIndex := OldIndex;
ChangePages;
Result := False;
end;
end;
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);
Stream := TMemoryStream.Create;
SaveToStream(Stream);
Pages.Clear;
EMFPages.ObjectsToPage(PageIndex);
p := EMFPages[PageIndex];
Pages.FPages.Add(p^.Page);
CurReport := Self;
Screen.Cursor := crDefault;
try
frDesigner.ShowModal;
if frDesigner.Modified then
if MessageDlg(sSaveChanges+' ?',mtConfirmation,[mbYes,mbNo],0)=mrYes then
EMFPages.PageToObjects(PageIndex);
finally
Pages.FPages.Clear;
Stream.Position := 0;
LoadFromStream(Stream);
Stream.Free;
frDesigner.Free;
frDesigner := Designer;
frDesigner.Name := DesName;
frDesigner.Page := Pages[0];
frDesigner.RedrawPage;
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;
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.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(aName: String): TfrObject;
var
i, j: 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 := TList.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;
if Assigned(Doc.FOnBeginDoc) and FirstTime then
Doc.FOnBeginDoc;
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 Assigned(Doc.FOnEndDoc) and FinalPass then
Doc.FOnEndDoc;
Append := CompositeMode;
CompositeMode := False;
if Terminated then break;
end;
end;
{----------------------------------------------------------------------------}
procedure TfrObjEditorForm.ShowEditor(t: TfrView);
begin
// abstract method
end;
{----------------------------------------------------------------------------}
constructor TfrExportFilter.Create(AStream: TStream);
begin
inherited Create;
Stream := AStream;
Lines := TList.Create;
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;
FreeMem(p1, SizeOf(TfrTextRec));
end;
end;
Lines.Clear;
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;
{----------------------------------------------------------------------------}
constructor TfrFunctionLibrary.Create;
begin
inherited Create;
List := TStringList.Create;
//List.Sorted := True;
end;
destructor TfrFunctionLibrary.Destroy;
var
i:integer;
begin
for i:=0 to List.Count-1 do
if Assigned(List.Objects[i]) then
begin
List.Objects[i].Free;
List.Objects[i]:=nil;
end;
List.Free;
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.AddFunctionDesc(funName, funGroup,
funDescription: string);
var
i: Integer;
begin
if List.Find(funName, i) then
begin
if not Assigned(List.Objects[i]) then
List.Objects[i]:=TfrFunctionDescription.Create;
TfrFunctionDescription(List.Objects[i]).funName:=funName;
TfrFunctionDescription(List.Objects[i]).funGroup:=funGroup;
TfrFunctionDescription(List.Objects[i]).funDescription:=funDescription;
end
end;
{----------------------------------------------------------------------------}
constructor TfrStdFunctionLibrary.Create;
begin
inherited Create;
with List do
begin
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}
end;
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('INPUT', SOtherCategory, SDescriptionINPUT);
AddFunctionDesc('MESSAGEBOX', SOtherCategory, SDescriptionMESSAGEBOX);
AddFunctionDesc('MAXNUM', SMathCategory, SDescriptionMAXNUM);
AddFunctionDesc('MINNUM', SMathCategory, SDescriptionMINNUM);
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 : Pointer;
begin
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 := Length(frParser.Calc(p1)); //Add('LENGTH'); {7}
8: val := AnsiLowerCase(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 := AnsiLowerCase(frParser.Calc(p1));
if Length(s1) > 0 then
val := AnsiUpperCase(s1[1]) + Copy(s1, 2, Length(s1) - 1)
else
val := '';
end;
16:begin // Add('POS'); {16}
S1:=frParser.Calc(p1);
S2:=frParser.Calc(p2);
val := Pos(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 := AnsiUpperCase(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
frGetDataSetAndField(lrGetUnBrackedStr(p1), DataSet, Field);
end;
if (DataSet <> 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 := FloatToStr(d);
end
else if DataSet = nil then
begin
s1 := Trim(string(p2));
if s1 = '' then
s1 := CurBand.View.Name;
if dk <> dkCount then
s2 := Trim(string(p3)) else
s2 := Trim(string(p2));
if (AggrBand.Typ in [btPageFooter, btMasterFooter, btDetailFooter,
btSubDetailFooter, btGroupFooter, btCrossFooter, btReportSummary]) and
((s2 = '1') or ((s2 <> '1') and CurBand.Visible)) then
begin
VarName := List[FNo] + p1;
if IsColumns then
if AggrBand.Typ = btCrossFooter then
VarName := VarName + '00' else
VarName := VarName + IntToStr(CurPage.ColPos);
if not AggrBand.Visible and (AnsiCompareText(CurBand.View.Name, s1) = 0) then
begin
s1 := AggrBand.Values.Values[VarName];
if s1 <> '' then
if s1[1] = '1' then
Exit else
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;
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);
Exit;
end
else if AggrBand.Visible then
begin
val := Copy(AggrBand.Values.Values[VarName], 2, 255);
if dk = dkAvg then
val := FloatToStr(StrToFloat(val) / AggrBand.Count);
Exit;
end;
end;
end;
end;
end;
{-----------------------------------------------------------------------------}
const
PropCount = 6;
PropNames: Array[0..PropCount - 1] of String =
('Text','FontName', 'FontSize', 'FontStyle', 'FontColor', 'Adjust');
ColNames: Array[0..16] of String =
('clWhite', 'clBlack', 'clMaroon', 'clGreen', 'clOlive', 'clNavy',
'clPurple', 'clTeal', 'clGray', 'clSilver', 'clRed', 'clLime',
'clYellow', 'clBlue', 'clFuchsia', 'clAqua', 'clTransparent');
{$WARNINGS OFF}
procedure TInterpretator.GetValue(const Name: String; var Value: Variant);
var
t : TfrObject;
Prop : String;
PropInfo : PPropInfo;
St : String;
i : Integer;
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,') INIT');
{$ENDIF}
//Value := 0;
t := CurView;
Prop := Name;
if frVariables.IndexOf(Name) <> -1 then
begin
Value := frVariables[Name];
Exit;
end;
if Name = 'FREESPACE' then
begin
Value:=IntToStr(CurPage.CurBottomY-CurPage.CurY);
Exit;
end;
if Pos('.', Name) <> 0 then
begin
//Find Object
t := CurPage.FindRTObject(Copy(Name, 1, Pos('.', Name) - 1));
//Property of object
Prop:=Copy(Name, Pos('.',Name)+1,255);
end;
if not Assigned(t) then
frParser.OnGetValue(Name, Value)
else
begin
//Retreive property informations
PropInfo:=GetPropInfo(t,Prop);
if Assigned(PropInfo) then
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,') Prop=',Prop,
' Kind=',InttoStr(Ord(PropInfo^.PropType^.Kind)));
{$ENDIF}
Case PropInfo^.PropType^.Kind of
tkChar,tkAString,tkWString,
tkSString,tkLString : begin
St:=GetStrProp(t,Prop);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
Value:=St;
end;
tkBool,tkInt64,tkQWord,
tkInteger : Value:=GetOrdProp(t,PropInfo);
tkSet : begin
St:=GetSetProp(t,Prop);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
Value:=St;
end;
tkFloat : Value:=GetFloatProp(t,Prop);
tkEnumeration : begin
St:=GetEnumProp(t,Prop);
{$IFDEF DebugLR}
DebugLn('St=',St);
{$ENDIF}
Value:=St;
end;
end;
end else
begin
// it's not a property of t, try with known color names first
for i := 0 to 16 do
if AnsiCompareText(ColNames[i], Prop) = 0 then
begin
// color constant found.
if i <> 16 then
Value := frColors[i] else
Value := clNone;
exit;
end;
// it's not a color name, try with customized properties
// not included directly in t
if not (t is TfrBandView) then
begin
for i:=0 to propcount-1 do
if CompareText(PropNames[i], Prop)=0 then
begin
{$IFDEF DebugLR}
DbgOut('A CustomField was found ', Prop);
if i=0 then
DbgOut(', t.memo.text=',DbgStr(t.Memo.Text));
DebugLn;
{$ENDIF}
case i of
0: Value := t.Memo.Text;
1: Value := TfrMemoView(t).Font.Name;
2: Value := TfrMemoView(t).Font.Size;
3: Value := frGetFontStyle(TfrMemoView(t).Font.Style);
4: Value := TfrMemoView(t).Font.Color;
5: Value := TfrMemoView(t).Adjust;
end;
exit;
end;
end;
// no luck yet, try next if it's a custom variable
if Assigned(frParser.OnGetValue) then
frParser.OnGetValue(Name, Value);
end;
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,') No Propinfo for Prop=',Prop);
{$ENDIF}
if VarIsNull(Value) or VarIsEmpty(Value) then
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.GetValue(',Name,')=NULL >> Value="',Name,'"');
{$ENDIF}
Value:=Name;
end
{$IFDEF DebugLR}
else
DebugLn('TInterpretator.GetValue(',Name,')=',VarToStr(Value));
{$ENDIF}
end;
end;
{$WARNINGS ON}
procedure TInterpretator.SetValue(const Name: String; Value: Variant);
var
t : TfrObject;
Prop : String;
PropInfo : PPropInfo;
St : String;
i : Integer;
begin
{$IFDEF DebugLR}
DebugLn('TInterpretator.SetValue(',Name,',',Value,')');
if VarIsNull(Value) or VarIsEmpty(Value) then
DebugLn('Value=NULL');
{$ENDIF}
t := CurView;
Prop := Name;
if Pos('.', Name) <> 0 then
begin
St := Copy(Name, 1, Pos('.', Name) - 1);
{$IFDEF DebugLR}
DebugLn('Trying to find RT Object "',St,'"');
{$ENDIF}
t := CurPage.FindRTObject(St);
Prop := Copy(Name, Pos('.', Name) + 1, 255);
end;
{$IFDEF DebugLR}
DebugLn('t=', dbgsName(t),' Prop=',Prop);
{$ENDIF}
//Retreive property informations
PropInfo:=GetPropInfo(t,Prop);
if Assigned(PropInfo) then
begin
St:=VarToStr(Value);
{$IFDEF DebugLR}
DebugLn('PropInfo for ',prop,' found, Setting Value=',St);
{$ENDIF}
Case PropInfo^.PropType^.Kind of
tkChar,tkAString,tkWString,
tkSString,tkLString : SetStrProp(t,Prop,St);
tkBool,tkInt64,tkQWord,
tkInteger : begin
if AnsiCompareText(PropInfo^.PropType^.Name,'TGraphicsColor')=0 then
SetOrdProp(t,PropInfo,StringToColor(St))
else
SetOrdProp(t,PropInfo,Value)
end;
tkSet : SetSetProp(t,Prop,St);
tkFloat : SetFloatProp(t,Prop,Value);
tkEnumeration : SetEnumProp(t,Prop,St);
end;
end
else
begin
if not (t is TfrBandView) then
begin
// try with customized properties not included directly in t
for i:=0 to propcount-1 do
if CompareText(PropNames[i], Prop)=0 then
begin
{$IFDEF DebugLR}
DbgOut('A CustomField was found ', Prop);
if i=0 then
DbgOut(', t.memo.text=',DbgStr(t.Memo.Text),' nuevo valor=',VarToStr(Value));
DebugLn;
{$ENDIF}
case i of
0: t.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}
frVariables[Name] := Value;
Exit;
end;
end;
procedure TInterpretator.DoFunction(const Name: String; p1, p2, p3: Variant;
var val: Variant);
begin
if Name = 'NEWPAGE' then
begin
CurBand.ForceNewPage := True;
Val := '0';
end
else if Name = 'NEWCOLUMN' then
begin
CurBand.ForceNewColumn := True;
Val := '0';
end
else
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);
frCharset := StrToInt(sCharset);
frBandNames[btReportTitle] := sBand1;
frBandNames[btReportSummary] := sBand2;
frBandNames[btPageHeader] := sBand3;
frBandNames[btPageFooter] := sBand4;
frBandNames[btMasterHeader] := sBand5;
frBandNames[btMasterData] := sBand6;
frBandNames[btMasterFooter] := sBand7;
frBandNames[btDetailHeader] := sBand8;
frBandNames[btDetailData] := sBand9;
frBandNames[btDetailFooter] := sBand10;
frBandNames[btSubDetailHeader] := sBand11;
frBandNames[btSubDetailData] := sBand12;
frBandNames[btSubDetailFooter] := sBand13;
frBandNames[btOverlay] := sBand14;
frBandNames[btColumnHeader] := sBand15;
frBandNames[btColumnFooter] := sBand16;
frBandNames[btGroupHeader] := sBand17;
frBandNames[btGroupFooter] := sBand18;
frBandNames[btCrossHeader] := sBand19;
frBandNames[btCrossData] := sBand20;
frBandNames[btCrossFooter] := sBand21;
frBandNames[btNone] := sBand22;
frSpecArr[0] := sVar1;
frSpecArr[1] := sVar2;
frSpecArr[2] := sVar3;
frSpecArr[3] := sVar4;
frSpecArr[4] := sVar5;
frSpecArr[5] := sVar6;
frSpecArr[6] := sVar7;
frSpecArr[7] := sVar8;
frSpecArr[8] := sVar9;
BoolStr[0] :=SFormat51;
BoolStr[1] :=SFormat52;
BoolStr[2] :=SFormat53;
BoolStr[3] :=SFormat54;
frDateFormats[0] :=sDateFormat1;
frDateFormats[1] :=sDateFormat2;
frDateFormats[2] :=sDateFormat3;
frDateFormats[3] :=sDateFormat4;
frTimeFormats[0] :=sTimeFormat1;
frTimeFormats[1] :=sTimeFormat2;
frTimeFormats[2] :=sTimeFormat3;
frTimeFormats[3] :=sTimeFormat4;
frParser := TfrParser.Create;
frInterpretator := TInterpretator.Create;
frVariables := TfrVariables.Create;
frCompressor := TfrCompressor.Create;
HookList := TList.Create;
end;
procedure DoExit;
var
i: Integer;
begin
SBmp.Free;
TempBmp.Free;
SMemo.Free;
frProgressForm.Free;
for i := 0 to frFunctionsCount - 1 do
frFunctions[i].FunctionLibrary.Free;
frParser.Free;
frInterpretator.Free;
frVariables.Free;
frCompressor.Free;
HookList.Free;
end;
{ TfrObject }
procedure TfrObject.SetMemo(const AValue: TfrMemoStrings);
begin
if fMemo=AValue then exit;
fMemo.Assign(AValue);
end;
procedure TfrObject.SetName(const AValue: string);
var i : Integer;
Flg : Boolean;
begin
if fName=AValue then exit;
Flg:=False;
{if Assigned(Objects) then
begin
for i:=0 to Objects.Count-1 do
begin
if (TfrView(Objects[i]).Name=aValue) then
begin
Flg:=True;
MessageDlg('This name it''s already exists.',mtError,[mbOk],0);
Break;
end;
end;
end;
}
if not Flg then
fName:=AValue;
end;
procedure TfrObject.SetScript(const AValue: TfrScriptStrings);
begin
if fScript=AValue then exit;
fScript.Assign(AValue);
end;
//Code from FormStorage
function TfrObject.GetSaveProperty(Prop: String; aObj : TPersistent=nil): string;
Var PropInfo : PPropInfo;
Obj : TObject;
OldSep : char;
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
OldSep := DecimalSeparator;
DecimalSeparator := '.';
Result := FloatToStr(GetFloatProp(aObj,Prop));
DecimalSeparator := OldSep;
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(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 : SetFloatProp(aObj,Prop,StrToFloat(aValue));
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;
begin
inherited Create;
fUpdate:=0;
BaseName:='LRObj';
fVisible:=True;
fMemo:=TfrMemoStrings.Create;
fScript:=TfrScriptStrings.Create;
end;
destructor TfrObject.Destroy;
begin
fmemo.Free;
fScript.Free;
inherited Destroy;
end;
procedure TfrObject.Assign(From: TfrView);
begin
x := From.x;
y := From.y;
dx := From.dx;
dy := From.dy;
Memo.Assign(From.Memo);
Script.Assign(From.Script);
Visible:=From.Visible;
end;
procedure TfrObject.BeginUpdate;
begin
Inc(fUpdate)
end;
procedure TfrObject.EndUpdate;
begin
if fUpdate>0 then
Dec(fUpdate)
end;
procedure TfrObject.CreateUniqueName;
var i: Integer;
begin
fName := '';
if Assigned(CurReport) then
begin
for i := 1 to 10000 do
begin
if CurReport.FindObject(BaseName + IntToStr(i)) = nil then
begin
fName := BaseName + IntToStr(i);
Exit;
end;
end;
end
else fName := BaseName + '1';
end;
procedure TfrObject.LoadFromXML(XML: TLrXMLConfig; Path: String);
begin
//ClassName not read here.
Name:=XML.GetValue(Path+'Name/Value','');
if Name='' then
CreateUniqueName;
Visible:=XML.GetValue(Path+'Visible/Value', true);
end;
procedure TfrObject.SaveToXML(XML: TLrXMLConfig; Path: String);
begin
XML.SetValue(Path+'Name/Value', GetSaveProperty('Name'));
XML.SetValue(Path+'ClassName/Value', self.Classname);
XML.SetValue(Path+'Visible/Value', GetSaveProperty('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; Path: String);
var
Rc : TRect;
begin
inherited LoadFromXML(XML, Path);
pgSize := XML.GetValue(Path+'PgSize/Value', 0); // TODO chk
rc.left := XML.GetValue(Path+'Margins/left/Value', 0); // TODO chk
rc.top := XML.GetValue(Path+'Margins/Top/Value', 0); // TODO chk
rc.Right := XML.GetValue(Path+'Margins/Right/Value', 0); // TODO chk
rc.Bottom := XML.GetValue(Path+'Margins/Bottom/Value', 0); // TODO chk
Margins.AsRect := rc;
RestoreProperty('Orientation',XML.GetValue(Path+'Orientation/Value',''));
UseMargins := XML.GetValue(Path+'UseMargins/Value', True); // TODO chk
PrintToPrevPage := XML.GetValue(Path+'PrintToPrevPage/Value', True); // TODO chk
ColCount := XML.GetValue(Path+'ColCount/Value', 1); // TODO chk
ColGap := XML.GetValue(Path+'ColGap/Value', 0);
RestoreProperty('LayoutOrder',XML.GetValue(Path+'LayoutOrder/Value','loColumns'));
ChangePaper(pgSize, Width, Height, Orientation);
end;
procedure TfrPageReport.SavetoXML(XML: TLrXMLConfig; Path: String);
var
Rc : TRect;
begin
inherited SavetoXML(XML, Path);
Rc:=Margins.AsRect;
XML.SetValue(Path+'PgSize/Value', PgSize);
XML.SetValue(Path+'Margins/left/Value', Rc.Left);
XML.SetValue(Path+'Margins/Top/Value', Rc.Top);
XML.SetValue(Path+'Margins/Right/Value', Rc. Right);
XML.SetValue(Path+'Margins/Bottom/Value', Rc.Bottom);
XML.SetValue(Path+'Orientation/Value', GetSaveProperty('Orientation'));
XML.SetValue(Path+'UseMargins/Value', UseMargins);
XML.SetValue(Path+'PrintToPrevPage/Value', PrintToPrevPage);
XML.SetValue(Path+'ColCount/Value', ColCount);
XML.SetValue(Path+'ColGap/Value', ColGap);
XML.SetValue(Path+'LayoutOrder/Value', GetSaveProperty('LayoutOrder'));
end;
constructor TfrPageReport.CreatePage;
begin
self.Create(prn.DefaultPageSize, 0, 0, poPortrait);
end;
{ TfrPageDialog }
procedure TfrPageDialog.PrepareObjects;
begin
//Do nothing
end;
procedure TfrPageDialog.InitReport;
var i : Integer;
begin
//inherited InitReport;
fHasVisibleControls:=False;
end;
constructor TfrPageDialog.Create;
begin
inherited Create;
fForm :=nil;
BaseName:='Dialog';
Width :=200;
Height:=150;
PageType:=ptDialog;
end;
procedure TfrPageDialog.LoadFromXML(XML: TLrXMLConfig; Path: String);
begin
inherited LoadFromXML(XML, Path);
XML.GetValue(Path+'Caption/Value', '');
end;
procedure TfrPageDialog.SavetoXML(XML: TLrXMLConfig; Path: String);
begin
inherited SavetoXML(XML, Path);
XML.SetValue(Path+'Caption/Value', Caption);
end;
{ TLrXMLConfig }
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 := inherited GetValue(APath, ADefault)
else
begin
WValue := inherited GetValue(UTF8Decode(APath), UTF8Decode(ADefault));
Result := UTF8Encode(WValue);
end;
end;
initialization
DoInit;
finalization
DoExit;
end.