|
@@ -93,6 +93,8 @@ type
|
|
TFPReportCustomGroupHeaderBand = class;
|
|
TFPReportCustomGroupHeaderBand = class;
|
|
TFPReportExporter = class;
|
|
TFPReportExporter = class;
|
|
TFPReportTextAlignment = class;
|
|
TFPReportTextAlignment = class;
|
|
|
|
+ TFPReportLayouter = Class;
|
|
|
|
+
|
|
TBandList = class;
|
|
TBandList = class;
|
|
|
|
|
|
TFPReportElementClass = class of TFPReportElement;
|
|
TFPReportElementClass = class of TFPReportElement;
|
|
@@ -1327,7 +1329,6 @@ type
|
|
procedure BuiltinGetPageNoPerDesignerPage(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
procedure BuiltinGetPageNoPerDesignerPage(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
procedure BuiltinGetPageCount(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
procedure BuiltinGetPageCount(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
{ checks if children are visble, removes children if needed, and recalc Band.Layout bounds }
|
|
{ checks if children are visble, removes children if needed, and recalc Band.Layout bounds }
|
|
- procedure RecalcBandLayout(ABand: TFPReportCustomBand);
|
|
|
|
procedure EmptyRTObjects;
|
|
procedure EmptyRTObjects;
|
|
procedure ClearDataBandLastTextValues(ABand: TFPReportCustomBandWithData);
|
|
procedure ClearDataBandLastTextValues(ABand: TFPReportCustomBandWithData);
|
|
procedure ProcessAggregates(const APageIdx: integer; const AData: TFPReportData);
|
|
procedure ProcessAggregates(const APageIdx: integer; const AData: TFPReportData);
|
|
@@ -1349,6 +1350,7 @@ type
|
|
function CreateVariables: TFPReportVariables; virtual;
|
|
function CreateVariables: TFPReportVariables; virtual;
|
|
function CreateImages: TFPReportImages; virtual;
|
|
function CreateImages: TFPReportImages; virtual;
|
|
function CreateReportData: TFPReportDataCollection; virtual;
|
|
function CreateReportData: TFPReportDataCollection; virtual;
|
|
|
|
+ function CreateLayouter : TFPReportLayouter; virtual;
|
|
|
|
|
|
procedure RestoreDefaultVariables; virtual;
|
|
procedure RestoreDefaultVariables; virtual;
|
|
procedure DoPrepareReport; virtual;
|
|
procedure DoPrepareReport; virtual;
|
|
@@ -1413,6 +1415,102 @@ type
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
+ { TFPReportLayouter }
|
|
|
|
+
|
|
|
|
+ TFPReportLayouter = Class(TComponent)
|
|
|
|
+ Private
|
|
|
|
+ FMyReport: TFPCustomReport;
|
|
|
|
+ FPageIdx: integer;
|
|
|
|
+ FNewPage: boolean; // indicates if a new ReportPage needs to be created - used if DataBand spans multiple pages for example
|
|
|
|
+ FNewColumn: boolean;
|
|
|
|
+ FNewGroupHeader: boolean;
|
|
|
|
+ FLastDsgnDataBand: TFPReportCustomDataBand;
|
|
|
|
+ FSpaceLeft: TFPReportUnits;
|
|
|
|
+ FLastYPos: TFPReportUnits;
|
|
|
|
+ FLastXPos: TFPReportUnits;
|
|
|
|
+ FPageFooterYPos: TFPReportUnits;
|
|
|
|
+ FOverflowed: boolean;
|
|
|
|
+ FLastGroupCondition: string;
|
|
|
|
+ FFoundDataBand: boolean;
|
|
|
|
+ FHasGroupBand: boolean;
|
|
|
|
+ FHasGroupFooter: boolean;
|
|
|
|
+ FHasReportSummaryBand: boolean;
|
|
|
|
+ FDataHeaderPrinted: boolean;
|
|
|
|
+ FCurrentColumn: UInt8;
|
|
|
|
+ FMultiColumn: boolean;
|
|
|
|
+ FHeaderList: TBandList;
|
|
|
|
+ FFooterList: TBandList;
|
|
|
|
+ FRTPage: TFPReportCustomPage;
|
|
|
|
+ FRTBand: TFPReportCustomBand;
|
|
|
|
+ FCurrentRTColumnFooterBand: TFPReportCustomColumnFooterBand;
|
|
|
|
+ FDataLevelStack: UInt8;
|
|
|
|
+ procedure ClearBandList;
|
|
|
|
+ function GetPage(AIndex: integer): TFPReportCustomPage;
|
|
|
|
+ function GetPerDesignerPageCount(Index : Cardinal): Cardinal;
|
|
|
|
+ function GetRTCurPageIdx: Integer;
|
|
|
|
+ function GetRTObjects: TFPList;
|
|
|
|
+ procedure SetGetPerDesignerPageCount(Index : Cardinal; AValue: Cardinal);
|
|
|
|
+ Function GetPageNumberPerDesignerPage : Integer;
|
|
|
|
+ Procedure SetPageNumberPerDesignerPage(aValue : Integer);
|
|
|
|
+ protected
|
|
|
|
+ function HandleBandVisibility(aBand: TFPReportCustomBand; doRecalcLayout : Boolean): Boolean;
|
|
|
|
+ procedure CheckNewOrOverFlow(CheckMulticolumn: Boolean = True);
|
|
|
|
+ procedure CheckRemaining(CheckMulticolumn: Boolean = True);
|
|
|
|
+ procedure SetPageCount(aCount : Integer);
|
|
|
|
+ procedure IncPageNumberPerDesignerPage;
|
|
|
|
+ procedure InitRTCurPageIdx;
|
|
|
|
+ procedure IncPageNumber;
|
|
|
|
+ Procedure InitPageNumber;
|
|
|
|
+ function FRTCurBand : TFPReportCustomBand;
|
|
|
|
+ Function IsFirstPass : Boolean;
|
|
|
|
+ procedure InitPass(aPassIdx: Integer); virtual;
|
|
|
|
+ procedure InitBandList(aPage: TFPReportCustomPage; aDataLoop: TFPReportData); virtual;
|
|
|
|
+ procedure InitDesignPage(aPageIdx: integer); virtual;
|
|
|
|
+ procedure RunDataLoop(lPageIdx: Integer; lPageData: TFPReportData); virtual;
|
|
|
|
+ procedure RecalcBandLayout(ABand: TFPReportCustomBand); virtual;
|
|
|
|
+ procedure PopulateFooterList(APage: TFPReportCustomPage); virtual;
|
|
|
|
+ procedure PopulateHeaderList(APage: TFPReportCustomPage);virtual;
|
|
|
|
+ procedure RemoveTitleBandFromHeaderList;virtual;
|
|
|
|
+ procedure RemoveColumnFooterFromFooterList;virtual;
|
|
|
|
+ procedure UpdateSpaceRemaining(const ABand: TFPReportCustomBand; const AUpdateYPos: boolean = True);virtual;
|
|
|
|
+ procedure CommonRuntimeBandProcessing(const aBand: TFPReportCustomBand); virtual;
|
|
|
|
+ function MaybeSkipBand(const ADsgnBand: TFPReportCustomBand): boolean; virtual;
|
|
|
|
+ procedure ShowDataBand(const aBand: TFPReportCustomDataBand);virtual;
|
|
|
|
+ procedure ShowDataFooterBand(const aBand: TFPReportCustomDataFooterBand); virtual;
|
|
|
|
+ procedure ShowDataHeaderBand(const aBand: TFPReportCustomDataHeaderBand); virtual;
|
|
|
|
+ procedure ShowDetailBand(const AMasterBand: TFPReportCustomDataBand);virtual;
|
|
|
|
+ function ShowPageHeaderBand(const aBand: TFPReportCustomBand): boolean; virtual;
|
|
|
|
+ function ShowColumnHeaderBand(const aBand: TFPReportCustomBand): boolean; virtual;
|
|
|
|
+ procedure ShowFooterBand(aBand: TFPReportCustomPageFooterBand); virtual;
|
|
|
|
+ procedure ShowColumnFooterBand(APage: TFPReportCustomPage; ABand: TFPReportCustomColumnFooterBand); virtual;
|
|
|
|
+ Procedure HandleHeaderBands; virtual;
|
|
|
|
+ Procedure HandleFooterBands; virtual;
|
|
|
|
+ procedure HandleDatabands; virtual;
|
|
|
|
+ procedure HandleGroupBands; virtual;
|
|
|
|
+ procedure HandleGroupFooters; virtual;
|
|
|
|
+ procedure HandleReportSummaries; virtual;
|
|
|
|
+ procedure PrepareGroupHeaderBand(aBand: TFPReportCustomGroupHeaderBand); virtual;
|
|
|
|
+ function NoSpaceRemaining: boolean;virtual;
|
|
|
|
+ procedure StartNewPage; virtual;
|
|
|
|
+ procedure StartNewColumn;virtual;
|
|
|
|
+ procedure HandleOverflowed;virtual;
|
|
|
|
+ Procedure DoExecute; virtual;
|
|
|
|
+ // In case descendents need these, make them available
|
|
|
|
+ Property PerDesignerPageCount [Index : Cardinal] : Cardinal Read GetPerDesignerPageCount Write SetGetPerDesignerPageCount;
|
|
|
|
+ property Pages[AIndex: integer]: TFPReportCustomPage read GetPage;
|
|
|
|
+ property RTObjects: TFPList read GetRTObjects;
|
|
|
|
+ Property RTCurPageIdx : Integer Read GetRTCurPageIdx;
|
|
|
|
+ Property RTCurColumn : UInt8 Read FCurrentColumn;
|
|
|
|
+ Property RTCurPage : TFPReportCustomPage Read FRTPage;
|
|
|
|
+ Property RTCurBand : TFPReportCustomBand Read FRTBand;
|
|
|
|
+ Property RTCurColumnFooterBand : TFPReportCustomColumnFooterBand Read FCurrentRTColumnFooterBand;
|
|
|
|
+ Property PageIdx : Integer Read FPageIdx;
|
|
|
|
+ Property PageNumberPerDesignerPage : Integer Read GetPageNumberPerDesignerPage Write SetPageNumberPerDesignerPage;
|
|
|
|
+ Public
|
|
|
|
+ Procedure Execute(aReport : TFPCustomReport);
|
|
|
|
+ Property Report : TFPCustomReport Read FMyReport;
|
|
|
|
+ end;
|
|
|
|
+
|
|
EReportError = class(Exception);
|
|
EReportError = class(Exception);
|
|
EReportExportError = class(EReportError);
|
|
EReportExportError = class(EReportError);
|
|
EReportFontNotFound = class(EReportError);
|
|
EReportFontNotFound = class(EReportError);
|
|
@@ -6479,6 +6577,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFPCustomReport.BuiltinGetPageCount(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
procedure TFPCustomReport.BuiltinGetPageCount(var Result: TFPExpressionResult; const Args: TExprParameterArray);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
if UsePageCountMarker then
|
|
if UsePageCountMarker then
|
|
Result.ResString := cPageCountMarker
|
|
Result.ResString := cPageCountMarker
|
|
@@ -6486,21 +6585,6 @@ begin
|
|
Result.ResString := IntToStr(FPageCount);
|
|
Result.ResString := IntToStr(FPageCount);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.RecalcBandLayout(ABand: TFPReportCustomBand);
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
- e: TFPReportElement;
|
|
|
|
-begin
|
|
|
|
- for i := ABand.ChildCount-1 downto 0 do
|
|
|
|
- begin
|
|
|
|
- e := ABand.Child[i];
|
|
|
|
- if not e.EvaluateVisibility then
|
|
|
|
- begin
|
|
|
|
- ABand.RemoveChild(e);
|
|
|
|
- FreeAndNil(e);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-end;
|
|
|
|
|
|
|
|
procedure TFPCustomReport.EmptyRTObjects;
|
|
procedure TFPCustomReport.EmptyRTObjects;
|
|
begin
|
|
begin
|
|
@@ -6638,6 +6722,7 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TFPCustomReport.DoGetExpressionVariableValue(var Result: TFPExpressionResult; constref AName: ShortString);
|
|
procedure TFPCustomReport.DoGetExpressionVariableValue(var Result: TFPExpressionResult; constref AName: ShortString);
|
|
|
|
+
|
|
var
|
|
var
|
|
p: integer;
|
|
p: integer;
|
|
b: integer;
|
|
b: integer;
|
|
@@ -6719,3160 +6804,3209 @@ end;
|
|
|
|
|
|
procedure TFPCustomReport.DoPrepareReport;
|
|
procedure TFPCustomReport.DoPrepareReport;
|
|
|
|
|
|
-var
|
|
|
|
- lPageIdx: integer;
|
|
|
|
- b: integer;
|
|
|
|
- s: string;
|
|
|
|
- lNewPage: boolean; // indicates if a new ReportPage needs to be created - used if DataBand spans multiple pages for example
|
|
|
|
- lNewColumn: boolean;
|
|
|
|
- lNewGroupHeader: boolean;
|
|
|
|
- lDsgnBand: TFPReportCustomBand;
|
|
|
|
- lLastDsgnDataBand: TFPReportCustomDataBand;
|
|
|
|
- lRTPage: TFPReportCustomPage;
|
|
|
|
- lRTBand: TFPReportCustomBand;
|
|
|
|
- lSpaceLeft: TFPReportUnits;
|
|
|
|
- lLastYPos: TFPReportUnits;
|
|
|
|
- lLastXPos: TFPReportUnits;
|
|
|
|
- lPageFooterYPos: TFPReportUnits;
|
|
|
|
- lOverflowed: boolean;
|
|
|
|
- lLastGroupCondition: string;
|
|
|
|
- lFoundDataBand: boolean;
|
|
|
|
- lHasGroupBand: boolean;
|
|
|
|
- lHasGroupFooter: boolean;
|
|
|
|
- lHasReportSummaryBand: boolean;
|
|
|
|
- lDataHeaderPrinted: boolean;
|
|
|
|
- lCurrentColumn: UInt8;
|
|
|
|
- lMultiColumn: boolean;
|
|
|
|
- lHeaderList: TBandList;
|
|
|
|
- lFooterList: TBandList;
|
|
|
|
- lNewRTColumnFooterBand: TFPReportCustomColumnFooterBand;
|
|
|
|
- lDataLevelStack: UInt8;
|
|
|
|
- lPassCount: UInt8;
|
|
|
|
- lPassIdx: UInt8;
|
|
|
|
-
|
|
|
|
- procedure RemoveTitleBandFromHeaderList;
|
|
|
|
- var
|
|
|
|
- idx: integer;
|
|
|
|
- lBand: TFPReportCustomBand;
|
|
|
|
- begin
|
|
|
|
- idx := lHeaderList.Find(TFPReportCustomTitleBand, lBand);
|
|
|
|
- if idx > -1 then
|
|
|
|
- lHeaderList.Delete(idx);
|
|
|
|
- end;
|
|
|
|
|
|
+Var
|
|
|
|
+ L : TFPReportLayouter;
|
|
|
|
|
|
- procedure RemoveColumnFooterFromFooterList;
|
|
|
|
- var
|
|
|
|
- idx: integer;
|
|
|
|
- lBand: TFPReportCustomBand;
|
|
|
|
- begin
|
|
|
|
- idx := lFooterList.Find(TFPReportCustomColumnFooterBand, lBand);
|
|
|
|
- if idx > -1 then
|
|
|
|
- lFooterList.Delete(idx);
|
|
|
|
|
|
+begin
|
|
|
|
+ FPageCount:=0;
|
|
|
|
+ FBands:=Nil;
|
|
|
|
+ L:=CreateLayouter;
|
|
|
|
+ try
|
|
|
|
+ FBands:=TBandList.Create;
|
|
|
|
+ SetLength(FPerDesignerPageCount, PageCount);
|
|
|
|
+ L.Execute(Self);
|
|
|
|
+ finally
|
|
|
|
+ SetLength(FPerDesignerPageCount, 0);
|
|
|
|
+ Fbands.Free;
|
|
|
|
+ L.Free;
|
|
end;
|
|
end;
|
|
|
|
+end;
|
|
|
|
|
|
- procedure UpdateSpaceRemaining(const ABand: TFPReportCustomBand; const AUpdateYPos: boolean = True);
|
|
|
|
- begin
|
|
|
|
- lSpaceLeft := lSpaceLeft - ABand.RTLayout.Height;
|
|
|
|
- if AUpdateYPos then
|
|
|
|
- lLastYPos := lLastYPos + ABand.RTLayout.Height;
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.DoBeginReport;
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FOnBeginReport) then
|
|
|
|
+ FOnBeginReport;
|
|
|
|
+end;
|
|
|
|
|
|
- procedure CommonRuntimeBandProcessing(const ADsgnBand: TFPReportCustomBand);
|
|
|
|
- begin
|
|
|
|
- ADsgnBand.PrepareObjects;
|
|
|
|
- lRTBand := FRTCurBand;
|
|
|
|
- lRTBand.RecalcLayout;
|
|
|
|
- lRTBand.BeforePrint;
|
|
|
|
- lRTBand.RTLayout.Top := lLastYPos;
|
|
|
|
- lRTBand.RTLayout.Left := lLastXPos;
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.DoEndReport;
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FOnEndReport) then
|
|
|
|
+ FOnEndReport;
|
|
|
|
+end;
|
|
|
|
|
|
- { Result of True means ADsgnBand must be skipped. Result of False means ADsgnBand
|
|
|
|
- must be rendered (ie: not skipped). }
|
|
|
|
- function DoVisibleOnPageChecks(const ADsgnBand: TFPReportCustomBand): boolean;
|
|
|
|
- begin
|
|
|
|
- Result := True;
|
|
|
|
- if ADsgnBand.VisibleOnPage = vpAll then
|
|
|
|
- begin
|
|
|
|
- // do nothing special
|
|
|
|
- end
|
|
|
|
- else if (FPageNumberPerDesignerPage = 1) then
|
|
|
|
- begin // first page rules
|
|
|
|
- if (ADsgnBand.VisibleOnPage in [vpFirstOnly, vpFirstAndLastOnly]) then
|
|
|
|
- begin
|
|
|
|
- // do nothing special
|
|
|
|
- end
|
|
|
|
- else if (ADsgnBand.VisibleOnPage in [vpNotOnFirst, vpLastOnly, vpNotOnFirstAndLast]) then
|
|
|
|
- Exit; // user asked to skip this band
|
|
|
|
- end
|
|
|
|
- else if (FPageNumberPerDesignerPage > 1) then
|
|
|
|
- begin // multi-page rules
|
|
|
|
- if ADsgnBand.VisibleOnPage in [vpFirstOnly] then
|
|
|
|
- Exit // user asked to skip this band
|
|
|
|
- else if ADsgnBand.VisibleOnPage in [vpNotOnFirst] then
|
|
|
|
- begin
|
|
|
|
- // do nothing special
|
|
|
|
- end
|
|
|
|
- else if (not IsFirstPass) then
|
|
|
|
- begin // last page rules
|
|
|
|
- if (ADsgnBand.VisibleOnPage in [vpLastOnly, vpFirstAndLastOnly]) and (FPageNumberPerDesignerPage < FPerDesignerPageCount[lPageIdx]) then
|
|
|
|
- Exit
|
|
|
|
- else if (ADsgnBand.VisibleOnPage in [vpNotOnLast, vpFirstOnly, vpNotOnFirstAndLast]) and (FPageNumberPerDesignerPage = FPerDesignerPageCount[lPageIdx]) then
|
|
|
|
- Exit; // user asked to skip this band
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- Result := False;
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.RestoreDefaultVariables;
|
|
|
|
|
|
- { Result of True means ADsgnBand must be skipped. Result of False means ADsgnBand
|
|
|
|
- must be rendered (ie: not skipped). }
|
|
|
|
- function ShowPageHeaderBand(const ADsgnBand: TFPReportCustomBand): boolean;
|
|
|
|
- begin
|
|
|
|
- Result := True;
|
|
|
|
- if not (ADsgnBand is TFPReportCustomPageHeaderBand) then
|
|
|
|
- Exit;
|
|
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
|
|
- if DoVisibleOnPageChecks(ADsgnBand as TFPReportCustomPageHeaderBand) then
|
|
|
|
- Exit;
|
|
|
|
|
|
+begin
|
|
|
|
+ For I:=0 to FVariables.Count-1 do
|
|
|
|
+ FVariables[i].RestoreValue;
|
|
|
|
+end;
|
|
|
|
|
|
- CommonRuntimeBandProcessing(ADsgnBand);
|
|
|
|
- Result := False;
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.InitializeDefaultExpressions;
|
|
|
|
|
|
- function ShowColumnHeaderBand(const ADsgnBand: TFPReportCustomBand): boolean;
|
|
|
|
- var
|
|
|
|
- lBand: TFPReportCustomBand;
|
|
|
|
- begin
|
|
|
|
- Result := False;
|
|
|
|
- CommonRuntimeBandProcessing(ADsgnBand);
|
|
|
|
- { Only once we show the first column header do we take into account
|
|
|
|
- the column footer. }
|
|
|
|
- lBand := Pages[lPageIdx].FindBand(TFPReportCustomColumnFooterBand);
|
|
|
|
- lFooterList.Add(lBand);
|
|
|
|
- if Assigned(lBand) then
|
|
|
|
- lSpaceLeft := lSpaceLeft - lBand.Layout.Height;
|
|
|
|
- end;
|
|
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
+ V : TFPReportVariable;
|
|
|
|
+ lHasAggregates: Boolean;
|
|
|
|
|
|
- function LayoutColumnFooterBand(APage: TFPReportCustomPage; ABand: TFPReportCustomColumnFooterBand): TFPReportCustomColumnFooterBand;
|
|
|
|
- var
|
|
|
|
- lBandCount: integer;
|
|
|
|
- lOverflowBand: TFPReportCustomBand;
|
|
|
|
|
|
+begin
|
|
|
|
+ FExpr.Clear;
|
|
|
|
+ FExpr.Identifiers.Clear;
|
|
|
|
+ FExpr.BuiltIns := [bcStrings,bcDateTime,bcMath,bcBoolean,bcConversion,bcData,bcVaria,bcUser, bcAggregate];
|
|
|
|
+ FExpr.Identifiers.AddDateTimeVariable('TODAY', Date);
|
|
|
|
+ FExpr.Identifiers.AddStringVariable('AUTHOR', Author);
|
|
|
|
+ FExpr.Identifiers.AddStringVariable('TITLE', Title);
|
|
|
|
+ FExpr.Identifiers.AddFunction('RecNo', 'I', '', @BuiltinExprRecNo);
|
|
|
|
+ FExpr.Identifiers.AddFunction('PageNo', 'I', '', @BuiltinGetPageNumber);
|
|
|
|
+ FExpr.Identifiers.AddFunction('PageNoPerDesignerPage', 'I', '', @BuiltInGetPageNoPerDesignerPage);
|
|
|
|
+ lHasAggregates:=false;
|
|
|
|
+ For I:=0 to FVariables.Count-1 do
|
|
begin
|
|
begin
|
|
- lBandCount := lRTPage.BandCount - 1;
|
|
|
|
- lOverflowBand := lRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
|
|
|
|
|
|
+ V:=FVariables[i];
|
|
|
|
+ V.SaveValue;
|
|
|
|
+ if V.Expression = '' then
|
|
|
|
+ FExpr.Identifiers.AddVariable(V.Name,V.DataType,@V.GetRTValue)
|
|
|
|
+ else
|
|
|
|
+ lHasAggregates:=true;
|
|
|
|
+ end;
|
|
|
|
+ if lHasAggregates then
|
|
|
|
+ TwoPass:=true;
|
|
|
|
+ if UsePageCountMarker then
|
|
|
|
+ FExpr.Identifiers.AddFunction('PageCount', 'S', '', @BuiltinGetPageCount)
|
|
|
|
+ else
|
|
|
|
+ FExpr.Identifiers.AddFunction('PageCount', 'I', '', @BuiltinGetPageCount);
|
|
|
|
+end;
|
|
|
|
|
|
- CommonRuntimeBandProcessing(ABand);
|
|
|
|
- Result := TFPReportCustomColumnFooterBand(lRTBand);
|
|
|
|
|
|
+procedure TFPCustomReport.InitializeExpressionVariables(const APage: TFPReportCustomPage; const AData: TFPReportData);
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+ f: string;
|
|
|
|
+ r: TResultType;
|
|
|
|
+ d: string;
|
|
|
|
+ v: TFPReportVariable;
|
|
|
|
|
|
- if lPageFooterYPos = -1 then
|
|
|
|
- lRTBand.RTLayout.Top := (APage.RTLayout.Top + APage.RTLayout.Height) - lRTBand.RTLayout.Height
|
|
|
|
- else
|
|
|
|
- lRTBand.RTLayout.Top := lPageFooterYPos - lRTBand.RTLayout.Height;
|
|
|
|
- if Result.FooterPosition = fpAfterLast then
|
|
|
|
- begin
|
|
|
|
- if lNewColumn or lOverflowed then
|
|
|
|
- { take height of overflowed band into account }
|
|
|
|
- lRTBand.RTLayout.Top := lLastYPos - lOverflowBand.RTLayout.Height
|
|
|
|
|
|
+ function ReportKindToResultType(const AType: TFPReportFieldKind): TResultType;
|
|
|
|
+ begin
|
|
|
|
+ case AType of
|
|
|
|
+ rfkString: Result := rtString;
|
|
|
|
+ rfkBoolean: Result := rtBoolean;
|
|
|
|
+ rfkInteger: Result := rtInteger;
|
|
|
|
+ rfkFloat: Result := rtFloat;
|
|
|
|
+ rfkDateTime: Result := rtDateTime;
|
|
|
|
+ rfkStream: Result := rtString; // TODO: What do we do here?????
|
|
else
|
|
else
|
|
- lRTBand.RTLayout.Top := lLastYPos;
|
|
|
|
|
|
+ Result := rtString;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
- function NoSpaceRemaining: boolean;
|
|
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ {$ifdef gdebug}
|
|
|
|
+ writeln('********** TFPCustomReport.InitializeExpressionVariables');
|
|
|
|
+ {$endif}
|
|
|
|
+ F:='';
|
|
|
|
+ For I:=0 to FExpr.Identifiers.Count-1 do
|
|
|
|
+ f:=f+FExpr.Identifiers[i].Name+'; ';
|
|
|
|
+ for i := 0 to AData.DataFields.Count-1 do
|
|
begin
|
|
begin
|
|
- if lSpaceLeft <= 0 then
|
|
|
|
- begin
|
|
|
|
- Result := True;
|
|
|
|
- if lMultiColumn and (lCurrentColumn < Pages[lPageIdx].ColumnCount) then
|
|
|
|
|
|
+ d := AData.Name;
|
|
|
|
+ f := AData.DataFields[i].FieldName;
|
|
|
|
+ r := ReportKindToResultType(AData.DataFields[i].FieldKind);
|
|
|
|
+ if d <> '' then
|
|
begin
|
|
begin
|
|
- lNewColumn := True;
|
|
|
|
|
|
+ {$ifdef gdebug}
|
|
|
|
+ writeln('registering (dotted name)... '+ d+'.'+f);
|
|
|
|
+ {$endif}
|
|
|
|
+ FExpr.Identifiers.AddVariable(d+'.'+f, r, @DoGetExpressionVariableValue);
|
|
end
|
|
end
|
|
- else
|
|
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- lOverflowed := True;
|
|
|
|
- lNewPage := True;
|
|
|
|
|
|
+ {$ifdef gdebug}
|
|
|
|
+ writeln('registering... '+ f);
|
|
|
|
+ {$endif}
|
|
|
|
+ FExpr.Identifiers.AddVariable(f, r, @DoGetExpressionVariableValue);
|
|
end;
|
|
end;
|
|
- end
|
|
|
|
- else
|
|
|
|
- Result := False;
|
|
|
|
end;
|
|
end;
|
|
-
|
|
|
|
- procedure StartNewColumn;
|
|
|
|
- var
|
|
|
|
- lIdx: integer;
|
|
|
|
- lBandCount: integer;
|
|
|
|
- lBand: TFPReportCustomBand;
|
|
|
|
- lOverflowBand: TFPReportCustomBand;
|
|
|
|
|
|
+ if APage.Data = AData then
|
|
begin
|
|
begin
|
|
- if Assigned(lLastDsgnDataBand) then
|
|
|
|
- ClearDataBandLastTextValues(lLastDsgnDataBand);
|
|
|
|
-
|
|
|
|
- if lMultiColumn and (lFooterList.Find(TFPReportCustomColumnFooterBand) <> nil) then
|
|
|
|
- lBandCount := lRTPage.BandCount - 2 // skip over the ColumnFooter band
|
|
|
|
- else
|
|
|
|
- lBandCount := lRTPage.BandCount - 1;
|
|
|
|
- lOverflowBand := lRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
|
|
|
|
- lSpaceLeft := Pages[lPageIdx].Layout.Height; // original designer page
|
|
|
|
- lRTPage := TFPReportCustomPage(RTObjects[FRTCurPageIdx]);
|
|
|
|
-
|
|
|
|
- lLastYPos := lRTPage.RTLayout.Top;
|
|
|
|
- lLastXPos := lLastXPos + lOverflowBand.RTLayout.Width + Pages[lPageIdx].ColumnGap;
|
|
|
|
-
|
|
|
|
- { Adjust starting Y-Pos based on bands in lHeaderList. }
|
|
|
|
- for lIdx := 0 to lHeaderList.Count-1 do
|
|
|
|
|
|
+ For I:=0 to FVariables.Count-1 do
|
|
begin
|
|
begin
|
|
- lBand := lHeaderList[lIdx];
|
|
|
|
-
|
|
|
|
- if lBand is TFPReportCustomPageHeaderBand then
|
|
|
|
|
|
+ v:=FVariables[I];
|
|
|
|
+ if v.Expression<>'' then
|
|
begin
|
|
begin
|
|
- if DoVisibleOnPageChecks(lBand) then
|
|
|
|
- Continue;
|
|
|
|
- end
|
|
|
|
- else if lBand is TFPReportCustomColumnHeaderBand then
|
|
|
|
|
|
+ FExpr.Expression:=v.Expression;
|
|
|
|
+ FExpr.ExtractNode(v.FExpressionNode);
|
|
|
|
+ v.FIsAggregate:=v.FExpressionNode.IsAggregate;
|
|
|
|
+ if v.FExpressionNode.HasAggregate and
|
|
|
|
+ not v.FExpressionNode.IsAggregate then
|
|
|
|
+ raise EReportError.CreateFmt(SErrExprVarisbleAggregateOnWrongLevel, [v.FExpressionNode.AsString]);
|
|
|
|
+ if not v.FIsAggregate then begin
|
|
|
|
+ v.FResetType:=rtNone;
|
|
|
|
+ v.FResetValueExpression:='';
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if v.ResetValueExpression<>'' then
|
|
begin
|
|
begin
|
|
- if ShowColumnHeaderBand(lBand) then
|
|
|
|
- Continue;
|
|
|
|
|
|
+ FExpr.Expression := v.ResetValueExpression;
|
|
|
|
+ FExpr.ExtractNode(v.FResetValueExpressionNode);
|
|
end;
|
|
end;
|
|
-
|
|
|
|
- lSpaceLeft := lSpaceLeft - lBand.Layout.Height;
|
|
|
|
- lLastYPos := lLastYPos + lBand.Layout.Height;
|
|
|
|
end;
|
|
end;
|
|
|
|
+ For I:=0 to FVariables.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ v:=FVariables[I];
|
|
|
|
+ if v.Expression<>'' then
|
|
|
|
+ FExpr.Identifiers.AddVariable(v.Name, v.DataType, @v.GetRTExpressionValue);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
- inc(lCurrentColumn);
|
|
|
|
|
|
+procedure TFPCustomReport.CacheMemoExpressions(const APageIdx: integer; const AData: TFPReportData);
|
|
|
|
+var
|
|
|
|
+ b: integer;
|
|
|
|
+ c: integer;
|
|
|
|
+ m: TFPReportCustomMemo;
|
|
|
|
+begin
|
|
|
|
+ for b := 0 to Pages[APageIdx].BandCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ if Pages[APageIdx].Bands[b] is TFPReportCustomBandWithData then
|
|
|
|
+ begin
|
|
|
|
+ if TFPReportCustomBandWithData(Pages[APageIdx].Bands[b]).Data <> AData then
|
|
|
|
+ Continue; // band is from a different data-loop
|
|
|
|
+ end;
|
|
|
|
|
|
- { If footer band exists, reduce available space }
|
|
|
|
- lBand := lRTPage.FindBand(TFPReportCustomPageFooterBand);
|
|
|
|
- if Assigned(lBand) then
|
|
|
|
- UpdateSpaceRemaining(lBand, False);
|
|
|
|
|
|
+ for c := 0 to Pages[APageIdx].Bands[b].ChildCount-1 do
|
|
|
|
+ if Pages[APageIdx].Bands[b].Child[c] is TFPReportCustomMemo then
|
|
|
|
+ begin
|
|
|
|
+ m := TFPReportCustomMemo(Pages[APageIdx].Bands[b].Child[c]);
|
|
|
|
+ m.ParseText;
|
|
|
|
+ end;
|
|
|
|
+ end; { bands }
|
|
|
|
+end;
|
|
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- Exit;
|
|
|
|
|
|
+constructor TFPCustomReport.Create(AOwner: TComponent);
|
|
|
|
+begin
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FReportData:=CreateReportData;
|
|
|
|
+ FRTObjects := TFPList.Create;
|
|
|
|
+ FImages := CreateImages;
|
|
|
|
+ FVariables:=CreateVariables;
|
|
|
|
+ FRTCurPageIdx := -1;
|
|
|
|
+ FDateCreated := Now;
|
|
|
|
+ FTwoPass := False;
|
|
|
|
+ FIsFirstPass := False;
|
|
|
|
+end;
|
|
|
|
|
|
- { Fix position of last band that caused the new column }
|
|
|
|
- lOverflowBand.RTLayout.Left := lLastXPos;
|
|
|
|
- lOverflowBand.RTLayout.Top := lLastYPos;
|
|
|
|
- { Adjust the next starting point of the next data band. }
|
|
|
|
- UpdateSpaceRemaining(lOverflowBand);
|
|
|
|
|
|
+function TFPCustomReport.CreateImages: TFPReportImages;
|
|
|
|
|
|
- lNewColumn := False;
|
|
|
|
- end;
|
|
|
|
|
|
+begin
|
|
|
|
+ Result:=TFPReportImages.Create(self, TFPReportImageItem);
|
|
|
|
+end;
|
|
|
|
|
|
- procedure HandleOverflowed;
|
|
|
|
- var
|
|
|
|
- lPrevRTPage: TFPReportCustomPage;
|
|
|
|
- lOverflowBand: TFPReportCustomBand;
|
|
|
|
- lBandCount: integer;
|
|
|
|
- begin
|
|
|
|
- lOverflowed := False;
|
|
|
|
- lPrevRTPage := TFPReportCustomPage(RTObjects[FRTCurPageIdx-1]);
|
|
|
|
- if lMultiColumn and (lFooterList.Find(TFPReportCustomColumnFooterBand) <> nil) then
|
|
|
|
- lBandCount := lPrevRTPage.BandCount - 2 // skip over the ColumnFooter band
|
|
|
|
- else
|
|
|
|
- lBandCount := lPrevRTPage.BandCount - 1;
|
|
|
|
- lOverflowBand := lPrevRTPage.Bands[lBandCount]; // get the last band - the one that didn't fit
|
|
|
|
- lPrevRTPage.RemoveChild(lOverflowBand);
|
|
|
|
- lRTPage.AddChild(lOverflowBand);
|
|
|
|
|
|
+function TFPCustomReport.CreateVariables: TFPReportVariables;
|
|
|
|
|
|
- { Fix position of last band that caused the overflow }
|
|
|
|
- lOverflowBand.RTLayout.Top := lLastYPos;
|
|
|
|
- lOverflowBand.RTLayout.Left := lLastXPos;
|
|
|
|
- UpdateSpaceRemaining(lOverflowBand);
|
|
|
|
- end;
|
|
|
|
|
|
+begin
|
|
|
|
+ Result:=TFPReportVariables.Create(Self,TFPReportVariable);
|
|
|
|
+end;
|
|
|
|
|
|
- procedure LayoutFooterBand;
|
|
|
|
- var
|
|
|
|
- lBand: TFPReportCustomPageFooterBand;
|
|
|
|
- begin
|
|
|
|
- lPageFooterYPos := -1;
|
|
|
|
- if not (lDsgnBand is TFPReportCustomPageFooterBand) then
|
|
|
|
- Exit;
|
|
|
|
|
|
+function TFPCustomReport.CreateReportData : TFPReportDataCollection;
|
|
|
|
|
|
- lBand := TFPReportCustomPageFooterBand(lDsgnBand);
|
|
|
|
- if DoVisibleOnPageChecks(lBand) then
|
|
|
|
- Exit;
|
|
|
|
|
|
+begin
|
|
|
|
+ Result:=TFPReportDataCollection.Create(TFPReportDataItem);
|
|
|
|
+end;
|
|
|
|
|
|
- lDsgnBand.PrepareObjects;
|
|
|
|
- lRTBand := FRTCurBand;
|
|
|
|
- lRTBand.RecalcLayout;
|
|
|
|
- lRTBand.BeforePrint;
|
|
|
|
- lRTBand.RTLayout.Top := (lRTPage.RTLayout.Top + lRTPage.RTLayout.Height) - lRTBand.RTLayout.Height;
|
|
|
|
- lPageFooterYPos := lRTBand.RTLayout.Top;
|
|
|
|
- // We don't adjust lLastYPos because this is a page footer
|
|
|
|
- UpdateSpaceRemaining(lRTBand, False);
|
|
|
|
- end;
|
|
|
|
|
|
+function TFPCustomReport.CreateLayouter: TFPReportLayouter;
|
|
|
|
+begin
|
|
|
|
+ Result:=TFPReportLayouter.Create(Self);
|
|
|
|
+end;
|
|
|
|
|
|
- procedure PopulateHeaderList(APage: TFPReportCustomPage);
|
|
|
|
- begin
|
|
|
|
- lHeaderList.Clear;
|
|
|
|
- lHeaderList.Add(APage.FindBand(TFPReportCustomPageHeaderBand));
|
|
|
|
- lHeaderList.Add(APage.FindBand(TFPReportCustomTitleBand));
|
|
|
|
- if lMultiColumn then
|
|
|
|
- lHeaderList.Add(Pages[lPageIdx].FindBand(TFPReportColumnHeaderBand));
|
|
|
|
- end;
|
|
|
|
|
|
+destructor TFPCustomReport.Destroy;
|
|
|
|
+begin
|
|
|
|
+ EmptyRTObjects;
|
|
|
|
+ FreeAndNil(FReportData);
|
|
|
|
+ FreeAndNil(FRTObjects);
|
|
|
|
+ FreeAndNil(FPages);
|
|
|
|
+ FreeAndNil(FExpr);
|
|
|
|
+ FreeAndNil(FReferenceList);
|
|
|
|
+ FreeAndNil(FImages);
|
|
|
|
+ FreeAndNil(FVariables);
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
|
|
- procedure PopulateFooterList(APage: TFPReportCustomPage);
|
|
|
|
- begin
|
|
|
|
- lFooterList.Clear;
|
|
|
|
- lFooterList.Add(APage.FindBand(TFPReportCustomPageFooterBand));
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.SaveDataToNames;
|
|
|
|
|
|
- procedure StartNewPage;
|
|
|
|
- var
|
|
|
|
- lIdx: integer;
|
|
|
|
- begin
|
|
|
|
- if Assigned(lLastDsgnDataBand) then
|
|
|
|
- ClearDataBandLastTextValues(lLastDsgnDataBand);
|
|
|
|
- lSpaceLeft := Pages[lPageIdx].Layout.Height; // original designer page
|
|
|
|
- Pages[lPageIdx].PrepareObjects; // creates a new page object
|
|
|
|
- //not needed here, it's done in TFPReportCustomPage.PrepareObjects: FRTCurPageIdx := RTObjects.Count-1;
|
|
|
|
- lRTPage := TFPReportCustomPage(RTObjects[FRTCurPageIdx]);
|
|
|
|
- lLastYPos := lRTPage.RTLayout.Top;
|
|
|
|
- lLastXPos := lRTPage.RTLayout.Left;
|
|
|
|
- Inc(FPageNumber);
|
|
|
|
- lCurrentColumn := 1;
|
|
|
|
- lNewColumn := False;
|
|
|
|
-
|
|
|
|
- if IsFirstPass then
|
|
|
|
- FPerDesignerPageCount[lPageIdx] := FPerDesignerPageCount[lPageIdx] + 1;
|
|
|
|
-
|
|
|
|
- if (FPageNumberPerDesignerPage = 1) then
|
|
|
|
- RemoveTitleBandFromHeaderList;
|
|
|
|
- inc(FPageNumberPerDesignerPage);
|
|
|
|
-
|
|
|
|
- { Show all header bands }
|
|
|
|
- for lIdx := 0 to lHeaderList.Count - 1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := lHeaderList[lIdx];
|
|
|
|
- if lDsgnBand is TFPReportCustomPageHeaderBand then
|
|
|
|
- begin
|
|
|
|
- if ShowPageHeaderBand(lDsgnBand) then
|
|
|
|
- Continue;
|
|
|
|
- end
|
|
|
|
- else if lDsgnBand is TFPReportCustomColumnHeaderBand then
|
|
|
|
- begin
|
|
|
|
- if ShowColumnHeaderBand(lDsgnBand) then
|
|
|
|
- Continue;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- CommonRuntimeBandProcessing(lDsgnBand);
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- end;
|
|
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
|
|
- { Show footer band if it exists }
|
|
|
|
- lDsgnBand := lFooterList.Find(TFPReportCustomPageFooterBand);
|
|
|
|
- if Assigned(lDsgnBand) then
|
|
|
|
- LayoutFooterBand;
|
|
|
|
|
|
+begin
|
|
|
|
+ For I:=0 to PageCount-1 do
|
|
|
|
+ Pages[i].SaveDataToNames;
|
|
|
|
+end;
|
|
|
|
|
|
- lNewPage := False;
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPCustomReport.RestoreDataFromNames;
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
|
|
- procedure ShowDataBand(const ADsgnBand: TFPReportCustomDataBand);
|
|
|
|
- var
|
|
|
|
- lDsgnChildBand: TFPReportChildBand;
|
|
|
|
- lLastDataBand: TFPReportCustomBand;
|
|
|
|
- begin
|
|
|
|
- lLastDsgnDataBand := ADsgnBand;
|
|
|
|
- CommonRuntimeBandProcessing(ADsgnBand);
|
|
|
|
- if lRTBand.EvaluateVisibility then
|
|
|
|
- begin
|
|
|
|
- lLastDataBand := lRTBand;
|
|
|
|
- RecalcBandLayout(lRTBand);
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- begin
|
|
|
|
- { Process ColumnFooterBand as needed }
|
|
|
|
- if lMultiColumn then
|
|
|
|
- begin
|
|
|
|
- lNewRTColumnFooterBand := TFPReportCustomColumnFooterBand(lFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
- if Assigned(lNewRTColumnFooterBand) then
|
|
|
|
- LayoutColumnFooterBand(lRTPage, lNewRTColumnFooterBand);
|
|
|
|
- end;
|
|
|
|
|
|
+begin
|
|
|
|
+ For I:=0 to PageCount-1 do
|
|
|
|
+ Pages[i].RestoreDataFromNames;
|
|
|
|
+end;
|
|
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
|
|
+procedure TFPCustomReport.AddPage(APage: TFPReportCustomPage);
|
|
|
|
+begin
|
|
|
|
+ if not Assigned(FPages) then
|
|
|
|
+ begin
|
|
|
|
+ FPages := TFPList.Create;
|
|
|
|
+ FPages.Add(APage);
|
|
|
|
+ end
|
|
|
|
+ else if FPages.IndexOf(APage) = -1 then
|
|
|
|
+ FPages.Add(APage);
|
|
|
|
+end;
|
|
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
|
|
+procedure TFPCustomReport.RemovePage(APage: TFPReportCustomPage);
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FPages) then
|
|
|
|
+ FPages.Remove(APage);
|
|
|
|
+end;
|
|
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
- end;
|
|
|
|
- { process any child bands off of DataBand }
|
|
|
|
- lDsgnChildBand := lLastDataBand.ChildBand;
|
|
|
|
- while lDsgnChildBand <> nil do
|
|
|
|
|
|
+procedure TFPCustomReport.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
|
|
+var
|
|
|
|
+ i: integer;
|
|
|
|
+begin
|
|
|
|
+ // ignore AOriginal here as we don't support whole report diffs, only element diffs
|
|
|
|
+ AWriter.PushElement('Report');
|
|
|
|
+ try
|
|
|
|
+ inherited WriteElement(AWriter, AOriginal);
|
|
|
|
+ // local properties
|
|
|
|
+ AWriter.WriteString('Title', Title);
|
|
|
|
+ AWriter.WriteString('Author', Author);
|
|
|
|
+ AWriter.WriteDateTime('DateCreated', DateCreated);
|
|
|
|
+ // now the design-time images
|
|
|
|
+ AWriter.PushElement('Images');
|
|
|
|
+ try
|
|
|
|
+ for i := 0 to Images.Count-1 do
|
|
begin
|
|
begin
|
|
- CommonRuntimeBandProcessing(lDsgnChildBand);
|
|
|
|
- if lRTBand.EvaluateVisibility then
|
|
|
|
- begin
|
|
|
|
- RecalcBandLayout(lRTBand);
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- begin
|
|
|
|
- { Process ColumnFooterBand as needed }
|
|
|
|
- if lMultiColumn then
|
|
|
|
- begin
|
|
|
|
- lNewRTColumnFooterBand := TFPReportCustomColumnFooterBand(lFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
- if Assigned(lNewRTColumnFooterBand) then
|
|
|
|
- LayoutColumnFooterBand(lRTPage, lNewRTColumnFooterBand);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- // remove invisible band
|
|
|
|
- lRTPage.RemoveChild(lRTBand);
|
|
|
|
- FreeAndNil(lRTBand);
|
|
|
|
|
|
+ AWriter.PushElement(IntToStr(i)); // use image index as identifier
|
|
|
|
+ try
|
|
|
|
+ Images[i].WriteElement(AWriter);
|
|
|
|
+ finally
|
|
|
|
+ AWriter.PopElement;
|
|
end;
|
|
end;
|
|
- lDsgnChildBand := lDsgnChildBand.ChildBand;
|
|
|
|
- end; { while ChildBand <> nil }
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- // remove invisible band
|
|
|
|
- lRTPage.RemoveChild(lRTBand);
|
|
|
|
- FreeAndNil(lRTBand);
|
|
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ AWriter.PopElement;
|
|
end;
|
|
end;
|
|
- end;
|
|
|
|
-
|
|
|
|
- procedure ShowDataHeaderBand(const ADsgnBand: TFPReportCustomDataHeaderBand);
|
|
|
|
- begin
|
|
|
|
- if lDataHeaderPrinted then
|
|
|
|
- Exit; // nothing further to do
|
|
|
|
-
|
|
|
|
- CommonRuntimeBandProcessing(ADsgnBand);
|
|
|
|
- if lRTBand.EvaluateVisibility then
|
|
|
|
- begin
|
|
|
|
- lDataHeaderPrinted := True;
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
|
|
+ // now the pages
|
|
|
|
+ AWriter.PushElement('Pages');
|
|
|
|
+ try
|
|
|
|
+ for i := 0 to PageCount - 1 do
|
|
begin
|
|
begin
|
|
- { Process ColumnFooterBand as needed }
|
|
|
|
- if lMultiColumn then
|
|
|
|
- begin
|
|
|
|
- lNewRTColumnFooterBand := TFPReportCustomColumnFooterBand(lFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
- if Assigned(lNewRTColumnFooterBand) then
|
|
|
|
- LayoutColumnFooterBand(lRTPage, lNewRTColumnFooterBand);
|
|
|
|
|
|
+ AWriter.PushElement(IntToStr(i)); // use page index as identifier
|
|
|
|
+ try
|
|
|
|
+ Pages[i].WriteElement(AWriter);
|
|
|
|
+ finally
|
|
|
|
+ AWriter.PopElement;
|
|
end;
|
|
end;
|
|
-
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
- end; { no space remaining }
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- // remove invisible band
|
|
|
|
- lRTPage.RemoveChild(lRTBand);
|
|
|
|
- FreeAndNil(lRTBand);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- procedure ShowDataFooterBand(const ADsgnBand: TFPReportCustomDataFooterBand);
|
|
|
|
- begin
|
|
|
|
- CommonRuntimeBandProcessing(ADsgnBand);
|
|
|
|
- if lRTBand.EvaluateVisibility then
|
|
|
|
- begin
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- begin
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
- end; { no space remaining }
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- // remove invisible band
|
|
|
|
- lRTPage.RemoveChild(lRTBand);
|
|
|
|
- FreeAndNil(lRTBand);
|
|
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ AWriter.PopElement;
|
|
end;
|
|
end;
|
|
|
|
+ finally
|
|
|
|
+ AWriter.PopElement;
|
|
end;
|
|
end;
|
|
|
|
+ // TODO: Implement writing OnRenderReport, OnBeginReport, OnEndReport
|
|
|
|
+end;
|
|
|
|
|
|
- procedure ShowDetailBand(const AMasterBand: TFPReportCustomDataBand);
|
|
|
|
- var
|
|
|
|
- lDsgnDetailBand: TFPReportCustomDataBand;
|
|
|
|
- lDetailBandList: TBandList;
|
|
|
|
- lDetailBand: TFPReportCustomBand;
|
|
|
|
- lData: TFPReportData;
|
|
|
|
- i: integer;
|
|
|
|
|
|
+procedure TFPCustomReport.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
+var
|
|
|
|
+ E: TObject;
|
|
|
|
+ i: integer;
|
|
|
|
+ p: TFPReportPage;
|
|
|
|
+ lImgItem: TFPReportImageItem;
|
|
|
|
+begin
|
|
|
|
+ ClearReferenceList;
|
|
|
|
+ E := AReader.FindChild('Report');
|
|
|
|
+ if Assigned(E) then
|
|
begin
|
|
begin
|
|
- if AMasterBand = nil then
|
|
|
|
- Exit;
|
|
|
|
- lDsgnDetailBand := nil;
|
|
|
|
- lDetailBandList := TBandList.Create;
|
|
|
|
|
|
+ AReader.PushElement(E);
|
|
try
|
|
try
|
|
- { collect bands of interest }
|
|
|
|
- for i := 0 to Pages[lPageIdx].BandCount-1 do
|
|
|
|
- begin
|
|
|
|
- lDetailBand := Pages[lPageIdx].Bands[i];
|
|
|
|
- if (lDetailBand is TFPReportCustomDataBand)
|
|
|
|
- and (TFPReportCustomDataBand(lDetailBand).MasterBand = AMasterBand)
|
|
|
|
- and (TFPReportCustomDataBand(lDetailBand).Data <> nil) then
|
|
|
|
- lDetailBandList.Add(lDetailBand);
|
|
|
|
- end;
|
|
|
|
- if lDetailBandList.Count = 0 then
|
|
|
|
- exit; // nothing further to do
|
|
|
|
- lDetailBandList.Sort(@SortDataBands);
|
|
|
|
|
|
+ inherited ReadElement(AReader);
|
|
|
|
+ FTitle := AReader.ReadString('Title', Title);
|
|
|
|
+ FAuthor := AReader.ReadString('Author', Author);
|
|
|
|
+ FDateCreated := AReader.ReadDateTime('DateCreated', Now);
|
|
|
|
|
|
- { process Detail bands }
|
|
|
|
- for i := 0 to lDetailBandList.Count-1 do
|
|
|
|
|
|
+ E := AReader.FindChild('Images');
|
|
|
|
+ if Assigned(E) then
|
|
begin
|
|
begin
|
|
- lDsgnDetailBand := TFPReportCustomDataBand(lDetailBandList[i]);
|
|
|
|
- lData := lDsgnDetailBand.Data;
|
|
|
|
- if not lData.IsOpened then
|
|
|
|
|
|
+ AReader.PushElement(E);
|
|
|
|
+ for i := 0 to AReader.ChildCount-1 do
|
|
begin
|
|
begin
|
|
- lData.Open;
|
|
|
|
- InitializeExpressionVariables(Pages[lPageIdx], lData);
|
|
|
|
- CacheMemoExpressions(lPageIdx, lData);
|
|
|
|
- end;
|
|
|
|
- lData.First;
|
|
|
|
|
|
+ E := AReader.GetChild(i);
|
|
|
|
+ AReader.PushElement(E); // child index is the identifier
|
|
|
|
+ try
|
|
|
|
+ lImgItem := Images.AddImageItem;
|
|
|
|
+ lImgItem.ReadElement(AReader);
|
|
|
|
+ finally
|
|
|
|
+ AReader.PopElement;
|
|
|
|
+ end;
|
|
|
|
+ end; { for i }
|
|
|
|
+ AReader.PopElement;
|
|
|
|
+ end; { images }
|
|
|
|
|
|
- if (not lData.EOF) and (lDsgnDetailBand.HeaderBand <> nil) then
|
|
|
|
- ShowDataHeaderBand(lDsgnDetailBand.HeaderBand);
|
|
|
|
- while not lData.EOF do
|
|
|
|
|
|
+ E := AReader.FindChild('Pages');
|
|
|
|
+ if Assigned(E) then
|
|
|
|
+ begin
|
|
|
|
+ AReader.PushElement(E);
|
|
|
|
+ for i := 0 to AReader.ChildCount-1 do
|
|
begin
|
|
begin
|
|
- If TwoPass and IsFirstPass then
|
|
|
|
- Variables.BuildAggregates;
|
|
|
|
- inc(lDataLevelStack);
|
|
|
|
- ShowDataBand(lDsgnDetailBand);
|
|
|
|
- ShowDetailBand(lDsgnDetailBand);
|
|
|
|
- dec(lDataLevelStack);
|
|
|
|
- lData.Next;
|
|
|
|
- end; { while not lData.EOF }
|
|
|
|
- lDataHeaderPrinted := False;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
-
|
|
|
|
- // only print if we actually had data
|
|
|
|
- if (lData.RecNo > 1) and (lDsgnDetailBand.FooterBand <> nil) then
|
|
|
|
- ShowDataFooterBand(lDsgnDetailBand.FooterBand);
|
|
|
|
|
|
+ E := AReader.GetChild(i);
|
|
|
|
+ AReader.PushElement(E); // child index is the identifier
|
|
|
|
+ try
|
|
|
|
+ p := TFPReportPage.Create(self);
|
|
|
|
+ p.ReadElement(AReader);
|
|
|
|
+ AddPage(p);
|
|
|
|
+ finally
|
|
|
|
+ AReader.PopElement;
|
|
|
|
+ end;
|
|
|
|
+ end; { for i }
|
|
|
|
+ AReader.PopElement;
|
|
|
|
+ end; { pages }
|
|
|
|
|
|
- lDsgnDetailBand := nil;
|
|
|
|
- end;
|
|
|
|
|
|
+ // TODO: Implement reading OnRenderReport, OnBeginReport, OnEndReport
|
|
finally
|
|
finally
|
|
- lDetailBandList.Free;
|
|
|
|
|
|
+ AReader.PopElement;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
+ FixupReferences;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPCustomReport.StartRender;
|
|
begin
|
|
begin
|
|
- EmptyRTObjects;
|
|
|
|
- lHeaderList := Nil;
|
|
|
|
- lFooterList := Nil;
|
|
|
|
- FBands := Nil;
|
|
|
|
- try
|
|
|
|
- lHeaderList := TBandList.Create;
|
|
|
|
- lFooterList := TBandList.Create;
|
|
|
|
- FBands := TBandList.Create;
|
|
|
|
- SetLength(FPerDesignerPageCount, PageCount);
|
|
|
|
|
|
+ inherited StartRender;
|
|
|
|
+ DoBeforeRenderReport;
|
|
|
|
+end;
|
|
|
|
|
|
- if TwoPass then
|
|
|
|
- lPassCount := 2
|
|
|
|
- else
|
|
|
|
- lPassCount := 1;
|
|
|
|
|
|
+procedure TFPCustomReport.EndRender;
|
|
|
|
+begin
|
|
|
|
+ inherited EndRender;
|
|
|
|
+ DoAfterRenderReport;
|
|
|
|
+end;
|
|
|
|
|
|
- FPageCount := 0;
|
|
|
|
- for lPassIdx := 1 to lPassCount do
|
|
|
|
|
|
+function TFPCustomReport.FindRecursive(const AName: string): TFPReportElement;
|
|
|
|
+var
|
|
|
|
+ p, b, c: integer;
|
|
|
|
+begin
|
|
|
|
+ Result := nil;
|
|
|
|
+ if AName = '' then
|
|
|
|
+ Exit;
|
|
|
|
+ for p := 0 to PageCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ for b := 0 to Pages[p].BandCount-1 do
|
|
begin
|
|
begin
|
|
- IsFirstPass := lPassIdx = 1;
|
|
|
|
- lHeaderList.Clear;
|
|
|
|
- lFooterList.Clear;
|
|
|
|
- FBands.Clear;
|
|
|
|
- FRTCurPageIdx := -1;
|
|
|
|
- lOverflowed := False;
|
|
|
|
- lHasGroupBand := False;
|
|
|
|
- lHasGroupFooter := False;
|
|
|
|
- lHasReportSummaryBand := False;
|
|
|
|
- lDataHeaderPrinted := False;
|
|
|
|
- lLastGroupCondition := '';
|
|
|
|
- FPageNumber := 0;
|
|
|
|
- lDataLevelStack := 0;
|
|
|
|
-
|
|
|
|
- for lPageIdx := 0 to PageCount-1 do
|
|
|
|
- begin
|
|
|
|
- lNewPage := True;
|
|
|
|
- lNewGroupHeader := True;
|
|
|
|
- lCurrentColumn := 1;
|
|
|
|
- lMultiColumn := Pages[lPageIdx].ColumnCount > 1;
|
|
|
|
- lNewColumn := False;
|
|
|
|
- lPageFooterYPos := -1;
|
|
|
|
- FPageData := Pages[lPageIdx].Data;
|
|
|
|
- FPageNumberPerDesignerPage := 0;
|
|
|
|
- lFoundDataBand := False;
|
|
|
|
- lLastDsgnDataBand := nil;
|
|
|
|
-
|
|
|
|
- if Assigned(FPageData) then
|
|
|
|
- begin
|
|
|
|
- if not FPageData.IsOpened then
|
|
|
|
- FPageData.Open;
|
|
|
|
- if IsFirstPass then
|
|
|
|
- begin
|
|
|
|
- InitializeExpressionVariables(Pages[lPageIdx], FPageData);
|
|
|
|
- CacheMemoExpressions(lPageIdx, FPageData);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- Variables.InitSecondPass;
|
|
|
|
|
|
+ if SameText(Pages[p].Bands[b].Name, AName) then
|
|
|
|
+ Result := Pages[p].Bands[b];
|
|
|
|
+ if Assigned(Result) then
|
|
|
|
+ Exit;
|
|
|
|
|
|
- FPageData.First;
|
|
|
|
|
|
+ for c := 0 to Pages[p].Bands[b].ChildCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ if SameText(Pages[p].Bands[b].Child[c].Name, AName) then
|
|
|
|
+ Result := Pages[p].Bands[b].Child[c];
|
|
|
|
+ if Assigned(Result) then
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
- // Create a list of band that need to be printed as page headers
|
|
|
|
- PopulateHeaderList(Pages[lPageIdx]);
|
|
|
|
|
|
+procedure TFPCustomReport.RunReport;
|
|
|
|
+begin
|
|
|
|
+ DoBeginReport;
|
|
|
|
|
|
- // Create a list of bands that need to be printed as page footers
|
|
|
|
- PopulateFooterList(Pages[lPageIdx]);
|
|
|
|
|
|
+ StartLayout;
|
|
|
|
+ FExpr := TFPexpressionParser.Create(nil);
|
|
|
|
+ try
|
|
|
|
+ InitializeDefaultExpressions;
|
|
|
|
+ DoPrepareReport;
|
|
|
|
+ finally
|
|
|
|
+ RestoreDefaultVariables;
|
|
|
|
+ FreeAndNil(FExpr);
|
|
|
|
+ end;
|
|
|
|
+ EndLayout;
|
|
|
|
|
|
- // find Bands of interest
|
|
|
|
- FBands.Clear;
|
|
|
|
- for b := 0 to Pages[lPageIdx].BandCount-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := Pages[lPageIdx].Bands[b];
|
|
|
|
- if (lDsgnBand is TFPReportCustomDataBand) then
|
|
|
|
- begin
|
|
|
|
- if TFPReportCustomDataBand(lDsgnBand).Data = FPageData then
|
|
|
|
- begin
|
|
|
|
- { Do a quick sanity check - we may not have more than one master data band }
|
|
|
|
- if lFoundDataBand then
|
|
|
|
- ReportError(SErrMultipleDataBands);
|
|
|
|
- FBands.Add(lDsgnBand);
|
|
|
|
- lFoundDataBand := True;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- continue; // it's a databand but not for the current data loop
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- if (lDsgnBand is TFPReportCustomGroupHeaderBand) and (TFPReportCustomGroupHeaderBand(lDsgnBand).GroupHeader <> nil) then
|
|
|
|
- continue; // this is not the toplevel GroupHeader Band.
|
|
|
|
- if lDsgnBand is TFPReportCustomGroupFooterBand then
|
|
|
|
- continue; // we will get the Footer from the GroupHeaderBand.FooterBand property
|
|
|
|
- FBands.Add(Pages[lPageIdx].Bands[b]); { all non-data bands are of interest }
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- if lDsgnBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
- begin
|
|
|
|
- lHasGroupBand := True;
|
|
|
|
- if Assigned(TFPReportCustomGroupHeaderBand(lDsgnBand).GroupFooter) then
|
|
|
|
- lHasGroupFooter := True;
|
|
|
|
- end
|
|
|
|
- else if lDsgnBand is TFPReportCustomSummaryBand then
|
|
|
|
- lHasReportSummaryBand := True;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- while not FPageData.EOF do
|
|
|
|
- begin
|
|
|
|
- if TwoPass and IsFirstPass then
|
|
|
|
- Variables.BuildAggregates;
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
-
|
|
|
|
- if lHasGroupBand then
|
|
|
|
- begin
|
|
|
|
- if lLastGroupCondition = '' then
|
|
|
|
- lNewGroupHeader := True
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- { Do GroupHeader evaluation }
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- { group header }
|
|
|
|
- if lDsgnBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
- begin
|
|
|
|
- // Writeln('Found group with expr: ',TFPReportCustomGroupHeaderBand(lDsgnBand).GroupCondition);
|
|
|
|
- s := TFPReportCustomGroupHeaderBand(lDsgnBand).Evaluate;
|
|
|
|
- // Writeln('Group new ? "',lLastGroupCondition,'" <> "', s,'"');
|
|
|
|
- if (lLastGroupCondition <> s) then
|
|
|
|
- begin
|
|
|
|
- lNewGroupHeader := True;
|
|
|
|
- { process group footer }
|
|
|
|
- if Assigned(TFPReportCustomGroupHeaderBand(lDsgnBand).GroupFooter) then
|
|
|
|
- begin
|
|
|
|
- FRTUseLastValues:=true;
|
|
|
|
- try
|
|
|
|
- lDsgnBand := TFPReportCustomGroupHeaderBand(lDsgnBand).GroupFooter;
|
|
|
|
- CommonRuntimeBandProcessing(lDsgnBand);
|
|
|
|
- finally
|
|
|
|
- FRTUseLastValues:=false;
|
|
|
|
- end;
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- begin
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
- end;
|
|
|
|
- end; { group footer }
|
|
|
|
- end;
|
|
|
|
- end; { group header }
|
|
|
|
- end; { bands for loop }
|
|
|
|
- end; { if/else }
|
|
|
|
-
|
|
|
|
- if lNewGroupHeader then
|
|
|
|
- begin
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- { group header }
|
|
|
|
- if lDsgnBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
- begin
|
|
|
|
- if Assigned(lLastDsgnDataBand) then
|
|
|
|
- ClearDataBandLastTextValues(lLastDsgnDataBand);
|
|
|
|
-
|
|
|
|
- CommonRuntimeBandProcessing(lDsgnBand);
|
|
|
|
- lLastGroupCondition := TFPReportGroupHeaderBand(lRTBand).GroupConditionValue;
|
|
|
|
- if lDsgnBand.EvaluateVisibility = False then
|
|
|
|
- begin
|
|
|
|
- lRTPage.RemoveChild(lRTBand);
|
|
|
|
- lRTBand.Free;
|
|
|
|
- Continue; // process next band
|
|
|
|
- end;
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- if NoSpaceRemaining then
|
|
|
|
- Break; { break out of FOR loop }
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- lNewGroupHeader := False;
|
|
|
|
- lDataHeaderPrinted := False;
|
|
|
|
- end; { lNewGroupHeader = True }
|
|
|
|
- end; { if lHasGroupBand }
|
|
|
|
-
|
|
|
|
- { handle overflow possibly caused by Group Band just processed. }
|
|
|
|
- if lOverflowed then
|
|
|
|
- Continue;
|
|
|
|
-
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
-
|
|
|
|
- { Process Master DataBand }
|
|
|
|
- if (lDsgnBand is TFPReportCustomDataBand) then
|
|
|
|
- begin
|
|
|
|
- inc(lDataLevelStack);
|
|
|
|
- if TFPReportCustomDataBand(lDsgnBand).HeaderBand <> nil then
|
|
|
|
- ShowDataHeaderBand(TFPReportCustomDataBand(lDsgnBand).HeaderBand);
|
|
|
|
- ShowDataBand(lDsgnBand as TFPReportCustomDataBand);
|
|
|
|
- ShowDetailBand(TFPReportCustomDataBand(lDsgnBand));
|
|
|
|
- dec(lDataLevelStack);
|
|
|
|
- end;
|
|
|
|
- end; { Bands for loop }
|
|
|
|
-
|
|
|
|
- FPageData.Next;
|
|
|
|
- end; { while not FPageData.EOF }
|
|
|
|
-
|
|
|
|
- if not (TwoPass and IsFirstPass) then
|
|
|
|
- begin
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
-
|
|
|
|
- // only print if we actually had data
|
|
|
|
- if (FPageData.RecNo > 1) then
|
|
|
|
- begin
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- if lDsgnBand is TFPReportCustomDataBand then
|
|
|
|
- if TFPReportCustomDataBand(lDsgnBand).FooterBand <> nil then
|
|
|
|
- ShowDataFooterBand(TFPReportCustomDataBand(lDsgnBand).FooterBand);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- { Process ColumnFooterBand as needed }
|
|
|
|
- if lMultiColumn then
|
|
|
|
- begin
|
|
|
|
- lNewRTColumnFooterBand := TFPReportCustomColumnFooterBand(lFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
- if Assigned(lNewRTColumnFooterBand) then
|
|
|
|
- begin
|
|
|
|
- LayoutColumnFooterBand(lRTPage, lNewRTColumnFooterBand);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- { ColumnFooter could have caused a new column or page }
|
|
|
|
- if lNewColumn then
|
|
|
|
- StartNewColumn;
|
|
|
|
-
|
|
|
|
- if lNewPage then
|
|
|
|
- StartNewPage;
|
|
|
|
-
|
|
|
|
- { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
- if lOverflowed then
|
|
|
|
- HandleOverflowed;
|
|
|
|
-
|
|
|
|
- if lHasGroupFooter then
|
|
|
|
- begin
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- if lDsgnBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
- begin
|
|
|
|
- lDsgnBand:=(lDsgnBand as TFPReportCustomGroupHeaderBand).GroupFooter;
|
|
|
|
- { We are allowed to use design Layout.Height instead of RTLayout.Height
|
|
|
|
- because this band appears outside the data loop, thus memos will not
|
|
|
|
- grow. Height of the band is as it was at design time. }
|
|
|
|
- if lDsgnBand.Layout.Height > lSpaceLeft then
|
|
|
|
- StartNewPage;
|
|
|
|
- CommonRuntimeBandProcessing(lDsgnBand);
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- Break;
|
|
|
|
- end;
|
|
|
|
- end; { for FBands }
|
|
|
|
- end; { lHasGroupFooter }
|
|
|
|
- end;
|
|
|
|
|
|
+ DoEndReport;
|
|
|
|
+end;
|
|
|
|
|
|
- FPageData.Close;
|
|
|
|
|
|
+procedure TFPCustomReport.RenderReport(const AExporter: TFPReportExporter);
|
|
|
|
+begin
|
|
|
|
+ if not Assigned(AExporter) then
|
|
|
|
+ Exit;
|
|
|
|
+ StartRender;
|
|
|
|
+ try
|
|
|
|
+ AExporter.Report := self;
|
|
|
|
+ AExporter.Execute;
|
|
|
|
+ finally
|
|
|
|
+ EndRender;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
- end; { if Assigned(FPageData) }
|
|
|
|
|
|
+{$IFDEF gdebug}
|
|
|
|
+function TFPCustomReport.DebugPreparedPageAsJSON(const APageNo: Byte): string;
|
|
|
|
+var
|
|
|
|
+ rs: TFPReportStreamer;
|
|
|
|
+begin
|
|
|
|
+ if APageNo > RTObjects.Count-1 then
|
|
|
|
+ Exit;
|
|
|
|
+ rs := TFPReportJSONStreamer.Create(nil);
|
|
|
|
+ try
|
|
|
|
+ TFPReportCustomPage(RTObjects[APageNo]).WriteElement(rs);
|
|
|
|
+ Result := TFPReportJSONStreamer(rs).JSON.FormatJSON;
|
|
|
|
+ finally
|
|
|
|
+ rs.Free;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+{$ENDIF}
|
|
|
|
|
|
- if lHasReportSummaryBand then
|
|
|
|
- begin
|
|
|
|
- for b := 0 to FBands.Count-1 do
|
|
|
|
- begin
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- if lDsgnBand is TFPReportCustomSummaryBand then
|
|
|
|
- begin
|
|
|
|
- { We are allowed to use design Layout.Height instead of RTLayout.Height
|
|
|
|
- because this band appears outside the data loop, thus memos will not
|
|
|
|
- grow. Height of the band is as it was at design time. }
|
|
|
|
- if (TFPReportCustomSummaryBand(lDsgnBand).StartNewPage) or (lDsgnBand.Layout.Height > lSpaceLeft) then
|
|
|
|
- StartNewPage;
|
|
|
|
- { Restore reference to lDsgnBand and SummaryBand, because StartNewPage
|
|
|
|
- could have changed the value of lDsgnBand. }
|
|
|
|
- lDsgnBand := TFPReportCustomBand(FBands[b]);
|
|
|
|
- CommonRuntimeBandProcessing(lDsgnBand);
|
|
|
|
- UpdateSpaceRemaining(lRTBand);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end; { lHasReportSummaryBand }
|
|
|
|
|
|
+{ TFPReportMargins }
|
|
|
|
|
|
- end; { for ... pages }
|
|
|
|
|
|
+procedure TFPReportMargins.SetBottom(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FBottom = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FBottom := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
|
|
- FPageCount := RTObjects.Count;
|
|
|
|
- if TwoPass and (lPassIdx = 1) then
|
|
|
|
- EmptyRTObjects;
|
|
|
|
|
|
+procedure TFPReportMargins.SetLeft(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FLeft = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FLeft := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
|
|
- end; { for ... lPassCount }
|
|
|
|
|
|
+procedure TFPReportMargins.SetRight(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FRight = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FRight := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
|
|
- // DoProcessPass only substitutes cPageCountMarker by FPageCount.
|
|
|
|
- // It is pointless to do so if we're doing 2 passes anyway
|
|
|
|
- if UsePageCountMarker then
|
|
|
|
- DoProcessTwoPass;
|
|
|
|
|
|
+procedure TFPReportMargins.SetTop(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FTop = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FTop := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
|
|
- finally
|
|
|
|
- FreeAndNil(lHeaderList);
|
|
|
|
- FreeAndNil(lFooterList);
|
|
|
|
- FreeAndNil(FBands);
|
|
|
|
- SetLength(FPerDesignerPageCount, 0);
|
|
|
|
- end;
|
|
|
|
|
|
+procedure TFPReportMargins.Changed;
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FPage) then
|
|
|
|
+ FPage.MarginsChanged;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.DoBeginReport;
|
|
|
|
|
|
+constructor TFPReportMargins.Create(APage: TFPReportCustomPage);
|
|
begin
|
|
begin
|
|
- if Assigned(FOnBeginReport) then
|
|
|
|
- FOnBeginReport;
|
|
|
|
|
|
+ inherited Create;
|
|
|
|
+ FPage := APage;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.DoEndReport;
|
|
|
|
|
|
+procedure TFPReportMargins.Assign(Source: TPersistent);
|
|
|
|
+var
|
|
|
|
+ S: TFPReportMargins;
|
|
begin
|
|
begin
|
|
- if Assigned(FOnEndReport) then
|
|
|
|
- FOnEndReport;
|
|
|
|
|
|
+ if Source is TFPReportMargins then
|
|
|
|
+ begin
|
|
|
|
+ S := Source as TFPReportMargins;
|
|
|
|
+ FTop := S.Top;
|
|
|
|
+ FBottom := S.Bottom;
|
|
|
|
+ FLeft := S.Left;
|
|
|
|
+ FRight := S.Right;
|
|
|
|
+ Changed;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited Assign(Source);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.RestoreDefaultVariables;
|
|
|
|
|
|
+function TFPReportMargins.Equals(AMargins: TFPReportMargins): boolean;
|
|
|
|
+begin
|
|
|
|
+ Result := (AMargins = Self)
|
|
|
|
+ or ((Top = AMargins.Top) and (Left = AMargins.Left) and
|
|
|
|
+ (Right = AMargins.Right) and (Bottom = AMargins.Bottom));
|
|
|
|
+end;
|
|
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+procedure TFPReportMargins.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportMargins);
|
|
|
|
+begin
|
|
|
|
+ if (AOriginal = nil) then
|
|
|
|
+ begin
|
|
|
|
+ AWriter.WriteFloat('Top', Top);
|
|
|
|
+ AWriter.WriteFloat('Left', Left);
|
|
|
|
+ AWriter.WriteFloat('Bottom', Bottom);
|
|
|
|
+ AWriter.WriteFloat('Right', Right);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ AWriter.WriteFloatDiff('Top', Top, AOriginal.Top);
|
|
|
|
+ AWriter.WriteFloatDiff('Left', Left, AOriginal.Left);
|
|
|
|
+ AWriter.WriteFloatDiff('Bottom', Bottom, AOriginal.Bottom);
|
|
|
|
+ AWriter.WriteFloatDiff('Right', Right, AOriginal.Right);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportMargins.ReadElement(AReader: TFPReportStreamer);
|
|
begin
|
|
begin
|
|
- For I:=0 to FVariables.Count-1 do
|
|
|
|
- FVariables[i].RestoreValue;
|
|
|
|
|
|
+ Top := AReader.ReadFloat('Top', Top);
|
|
|
|
+ Left := AReader.ReadFloat('Left', Left);
|
|
|
|
+ Bottom := AReader.ReadFloat('Bottom', Bottom);
|
|
|
|
+ Right := AReader.ReadFloat('Right', Right);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.InitializeDefaultExpressions;
|
|
|
|
|
|
+{ TFPReportCustomBand }
|
|
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
- V : TFPReportVariable;
|
|
|
|
- lHasAggregates: Boolean;
|
|
|
|
|
|
+function TFPReportCustomBand.GetReportPage: TFPReportCustomPage;
|
|
|
|
+begin
|
|
|
|
+ Result := Parent as TFPReportCustomPage;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+function TFPReportCustomBand.GetFont: TFPReportFont;
|
|
begin
|
|
begin
|
|
- FExpr.Clear;
|
|
|
|
- FExpr.Identifiers.Clear;
|
|
|
|
- FExpr.BuiltIns := [bcStrings,bcDateTime,bcMath,bcBoolean,bcConversion,bcData,bcVaria,bcUser, bcAggregate];
|
|
|
|
- FExpr.Identifiers.AddDateTimeVariable('TODAY', Date);
|
|
|
|
- FExpr.Identifiers.AddStringVariable('AUTHOR', Author);
|
|
|
|
- FExpr.Identifiers.AddStringVariable('TITLE', Title);
|
|
|
|
- FExpr.Identifiers.AddFunction('RecNo', 'I', '', @BuiltinExprRecNo);
|
|
|
|
- FExpr.Identifiers.AddFunction('PageNo', 'I', '', @BuiltinGetPageNumber);
|
|
|
|
- FExpr.Identifiers.AddFunction('PageNoPerDesignerPage', 'I', '', @BuiltInGetPageNoPerDesignerPage);
|
|
|
|
- lHasAggregates:=false;
|
|
|
|
- For I:=0 to FVariables.Count-1 do
|
|
|
|
|
|
+ if UseParentFont then
|
|
begin
|
|
begin
|
|
- V:=FVariables[i];
|
|
|
|
- V.SaveValue;
|
|
|
|
- if V.Expression = '' then
|
|
|
|
- FExpr.Identifiers.AddVariable(V.Name,V.DataType,@V.GetRTValue)
|
|
|
|
|
|
+ if Assigned(Owner) then
|
|
|
|
+ Result := TFPReportCustomPage(Owner).Font
|
|
else
|
|
else
|
|
- lHasAggregates:=true;
|
|
|
|
- end;
|
|
|
|
- if lHasAggregates then
|
|
|
|
- TwoPass:=true;
|
|
|
|
- if UsePageCountMarker then
|
|
|
|
- FExpr.Identifiers.AddFunction('PageCount', 'S', '', @BuiltinGetPageCount)
|
|
|
|
|
|
+ begin
|
|
|
|
+ FFont := TFPReportFont.Create;
|
|
|
|
+ Result := FFont;
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
else
|
|
else
|
|
- FExpr.Identifiers.AddFunction('PageCount', 'I', '', @BuiltinGetPageCount);
|
|
|
|
|
|
+ Result := FFont;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.InitializeExpressionVariables(const APage: TFPReportCustomPage; const AData: TFPReportData);
|
|
|
|
|
|
+function TFPReportCustomBand.IsStringValueZero(const AValue: string): boolean;
|
|
var
|
|
var
|
|
- i: Integer;
|
|
|
|
- f: string;
|
|
|
|
- r: TResultType;
|
|
|
|
- d: string;
|
|
|
|
- v: TFPReportVariable;
|
|
|
|
-
|
|
|
|
- function ReportKindToResultType(const AType: TFPReportFieldKind): TResultType;
|
|
|
|
|
|
+ lIntVal: integer;
|
|
|
|
+ lFloatVal: double;
|
|
|
|
+begin
|
|
|
|
+ Result := False;
|
|
|
|
+ if TryStrToInt(AValue, lIntVal) then
|
|
begin
|
|
begin
|
|
- case AType of
|
|
|
|
- rfkString: Result := rtString;
|
|
|
|
- rfkBoolean: Result := rtBoolean;
|
|
|
|
- rfkInteger: Result := rtInteger;
|
|
|
|
- rfkFloat: Result := rtFloat;
|
|
|
|
- rfkDateTime: Result := rtDateTime;
|
|
|
|
- rfkStream: Result := rtString; // TODO: What do we do here?????
|
|
|
|
- else
|
|
|
|
- Result := rtString;
|
|
|
|
- end;
|
|
|
|
|
|
+ if lIntVal = 0 then
|
|
|
|
+ Result := True;
|
|
|
|
+ end
|
|
|
|
+ else if TryStrToFloat(AValue, lFloatVal) then
|
|
|
|
+ begin
|
|
|
|
+ if lFloatVal = 0 then
|
|
|
|
+ Result := True;
|
|
end;
|
|
end;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportCustomBand.SetChildBand(AValue: TFPReportChildBand);
|
|
|
|
+var
|
|
|
|
+ b: TFPReportCustomBand;
|
|
|
|
+begin
|
|
|
|
+ if FChildBand = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FChildBand := AValue;
|
|
|
|
+ b := FChildBand;
|
|
|
|
+ while b <> nil do
|
|
|
|
+ begin
|
|
|
|
+ b := b.ChildBand;
|
|
|
|
+ if b = self then
|
|
|
|
+ raise EReportError.Create(SErrChildBandCircularReference);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportCustomBand.ApplyStretchMode;
|
|
|
|
+var
|
|
|
|
+ h: TFPReportUnits;
|
|
|
|
+ c: TFPReportElement;
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- {$ifdef gdebug}
|
|
|
|
- writeln('********** TFPCustomReport.InitializeExpressionVariables');
|
|
|
|
- {$endif}
|
|
|
|
- F:='';
|
|
|
|
- For I:=0 to FExpr.Identifiers.Count-1 do
|
|
|
|
- f:=f+FExpr.Identifiers[i].Name+'; ';
|
|
|
|
- for i := 0 to AData.DataFields.Count-1 do
|
|
|
|
|
|
+ h := RTLayout.Height;
|
|
|
|
+ for i := 0 to ChildCount-1 do
|
|
begin
|
|
begin
|
|
- d := AData.Name;
|
|
|
|
- f := AData.DataFields[i].FieldName;
|
|
|
|
- r := ReportKindToResultType(AData.DataFields[i].FieldKind);
|
|
|
|
- if d <> '' then
|
|
|
|
- begin
|
|
|
|
- {$ifdef gdebug}
|
|
|
|
- writeln('registering (dotted name)... '+ d+'.'+f);
|
|
|
|
- {$endif}
|
|
|
|
- FExpr.Identifiers.AddVariable(d+'.'+f, r, @DoGetExpressionVariableValue);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- {$ifdef gdebug}
|
|
|
|
- writeln('registering... '+ f);
|
|
|
|
- {$endif}
|
|
|
|
- FExpr.Identifiers.AddVariable(f, r, @DoGetExpressionVariableValue);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- if APage.Data = AData then
|
|
|
|
- begin
|
|
|
|
- For I:=0 to FVariables.Count-1 do
|
|
|
|
- begin
|
|
|
|
- v:=FVariables[I];
|
|
|
|
- if v.Expression<>'' then
|
|
|
|
- begin
|
|
|
|
- FExpr.Expression:=v.Expression;
|
|
|
|
- FExpr.ExtractNode(v.FExpressionNode);
|
|
|
|
- v.FIsAggregate:=v.FExpressionNode.IsAggregate;
|
|
|
|
- if v.FExpressionNode.HasAggregate and
|
|
|
|
- not v.FExpressionNode.IsAggregate then
|
|
|
|
- raise EReportError.CreateFmt(SErrExprVarisbleAggregateOnWrongLevel, [v.FExpressionNode.AsString]);
|
|
|
|
- if not v.FIsAggregate then begin
|
|
|
|
- v.FResetType:=rtNone;
|
|
|
|
- v.FResetValueExpression:='';
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- if v.ResetValueExpression<>'' then
|
|
|
|
- begin
|
|
|
|
- FExpr.Expression := v.ResetValueExpression;
|
|
|
|
- FExpr.ExtractNode(v.FResetValueExpressionNode);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- For I:=0 to FVariables.Count-1 do
|
|
|
|
- begin
|
|
|
|
- v:=FVariables[I];
|
|
|
|
- if v.Expression<>'' then
|
|
|
|
- FExpr.Identifiers.AddVariable(v.Name, v.DataType, @v.GetRTExpressionValue);
|
|
|
|
- end;
|
|
|
|
|
|
+ c := Child[i];
|
|
|
|
+ if c.RTLayout.Top + c.RTLayout.Height > h then
|
|
|
|
+ h := c.RTLayout.Top + c.RTLayout.Height;
|
|
end;
|
|
end;
|
|
|
|
+ RTLayout.Height := h;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.CacheMemoExpressions(const APageIdx: integer; const AData: TFPReportData);
|
|
|
|
-var
|
|
|
|
- b: integer;
|
|
|
|
- c: integer;
|
|
|
|
- m: TFPReportCustomMemo;
|
|
|
|
|
|
+procedure TFPReportCustomBand.SetFont(AValue: TFPReportFont);
|
|
begin
|
|
begin
|
|
- for b := 0 to Pages[APageIdx].BandCount-1 do
|
|
|
|
|
|
+ if UseParentFont then
|
|
|
|
+ UseParentFont := False;
|
|
|
|
+ FFont.Assign(AValue);
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportCustomBand.SetUseParentFont(AValue: boolean);
|
|
|
|
+begin
|
|
|
|
+ if FUseParentFont = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FUseParentFont := AValue;
|
|
|
|
+ if FUseParentFont then
|
|
|
|
+ FreeAndNil(FFont)
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- if Pages[APageIdx].Bands[b] is TFPReportCustomBandWithData then
|
|
|
|
- begin
|
|
|
|
- if TFPReportCustomBandWithData(Pages[APageIdx].Bands[b]).Data <> AData then
|
|
|
|
- Continue; // band is from a different data-loop
|
|
|
|
- end;
|
|
|
|
|
|
+ FFont := TFPReportFont.Create;
|
|
|
|
+ if Assigned(Owner) then
|
|
|
|
+ FFont.Assign(TFPReportCustomPage(Owner).Font);
|
|
|
|
+ end;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
|
|
- for c := 0 to Pages[APageIdx].Bands[b].ChildCount-1 do
|
|
|
|
- if Pages[APageIdx].Bands[b].Child[c] is TFPReportCustomMemo then
|
|
|
|
- begin
|
|
|
|
- m := TFPReportCustomMemo(Pages[APageIdx].Bands[b].Child[c]);
|
|
|
|
- m.ParseText;
|
|
|
|
- end;
|
|
|
|
- end; { bands }
|
|
|
|
|
|
+procedure TFPReportCustomBand.SetVisibleOnPage(AValue: TFPReportVisibleOnPage);
|
|
|
|
+begin
|
|
|
|
+ if FVisibleOnPage = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FVisibleOnPage := AValue;
|
|
|
|
+ Changed;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPCustomReport.Create(AOwner: TComponent);
|
|
|
|
|
|
+function TFPReportCustomBand.GetReportBandName: string;
|
|
begin
|
|
begin
|
|
- inherited Create(AOwner);
|
|
|
|
- FReportData:=CreateReportData;
|
|
|
|
- FRTObjects := TFPList.Create;
|
|
|
|
- FImages := CreateImages;
|
|
|
|
- FVariables:=CreateVariables;
|
|
|
|
- FRTCurPageIdx := -1;
|
|
|
|
- FDateCreated := Now;
|
|
|
|
- FTwoPass := False;
|
|
|
|
- FIsFirstPass := False;
|
|
|
|
|
|
+ Result := 'FPCustomReportBand';
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPCustomReport.CreateImages: TFPReportImages;
|
|
|
|
|
|
+function TFPReportCustomBand.GetData: TFPReportData;
|
|
|
|
+begin
|
|
|
|
+ result := nil;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportCustomBand.SetDataFromName(AName: String);
|
|
begin
|
|
begin
|
|
- Result:=TFPReportImages.Create(self, TFPReportImageItem);
|
|
|
|
|
|
+ // Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPCustomReport.CreateVariables: TFPReportVariables;
|
|
|
|
|
|
+procedure TFPReportCustomBand.SetParent(const AValue: TFPReportElement);
|
|
|
|
+begin
|
|
|
|
+ if not ((AValue = nil) or (AValue is TFPReportCustomPage)) then
|
|
|
|
+ ReportError(SErrNotAReportPage, [AValue.ClassName, AValue.Name]);
|
|
|
|
+ inherited SetParent(AValue);
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportCustomBand.CreateRTLayout;
|
|
begin
|
|
begin
|
|
- Result:=TFPReportVariables.Create(Self,TFPReportVariable);
|
|
|
|
|
|
+ inherited CreateRTLayout;
|
|
|
|
+ FRTLayout.Left := Page.Layout.Left;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPCustomReport.CreateReportData : TFPReportDataCollection;
|
|
|
|
|
|
+procedure TFPReportCustomBand.PrepareObjects;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lRTPage: TFPReportCustomPage;
|
|
|
|
+ i: integer;
|
|
|
|
+ m: TFPReportMemo;
|
|
|
|
+ cb: TFPReportCheckbox;
|
|
|
|
+ img: TFPReportCustomImage;
|
|
|
|
+ s: string;
|
|
|
|
+ c: integer;
|
|
|
|
+ n: TFPExprNode;
|
|
|
|
+ nIdx: integer;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=TFPReportDataCollection.Create(TFPReportDataItem);
|
|
|
|
|
|
+ i := Page.Report.FRTCurPageIdx;
|
|
|
|
+ if Assigned(Page.Report.RTObjects[i]) then
|
|
|
|
+ begin
|
|
|
|
+ lRTPage := TFPReportCustomPage(Page.Report.RTObjects[i]);
|
|
|
|
+ Page.Report.FRTCurBand := TFPReportBandClass(ClassType).Create(lRTPage);
|
|
|
|
+ Page.Report.FRTCurBand.Assign(self);
|
|
|
|
+ Page.Report.FRTCurBand.CreateRTLayout;
|
|
|
|
+ end;
|
|
|
|
+ inherited PrepareObjects;
|
|
|
|
+
|
|
|
|
+ if self is TFPReportGroupHeaderBand then
|
|
|
|
+ TFPReportGroupHeaderBand(Page.Report.FRTCurBand).CalcGroupConditionValue;
|
|
|
|
+
|
|
|
|
+ if Assigned(FChildren) then
|
|
|
|
+ begin
|
|
|
|
+ for c := 0 to Page.Report.FRTCurBand.ChildCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomMemo then
|
|
|
|
+ begin
|
|
|
|
+ m := TFPReportMemo(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
+ if moDisableExpressions in m.Options then
|
|
|
|
+ Continue; // nothing further to do
|
|
|
|
+ m.ExpandExpressions;
|
|
|
|
+ // visibility handling
|
|
|
|
+ if moHideZeros in m.Options then
|
|
|
|
+ begin
|
|
|
|
+ if IsStringValueZero(m.Text) then
|
|
|
|
+ begin
|
|
|
|
+ m.Visible := False;
|
|
|
|
+ Continue;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if moSuppressRepeated in m.Options then
|
|
|
|
+ begin
|
|
|
|
+ if m.Original.FLastText = m.Text then
|
|
|
|
+ begin
|
|
|
|
+ m.Visible := False;
|
|
|
|
+ Continue;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ m.Original.FLastText := m.Text;
|
|
|
|
+ end;
|
|
|
|
+ // aggregate handling
|
|
|
|
+ for nIdx := 0 to Length(m.Original.ExpressionNodes)-1 do
|
|
|
|
+ begin
|
|
|
|
+ n := m.Original.ExpressionNodes[nIdx].ExprNode;
|
|
|
|
+ if not Assigned(n) then
|
|
|
|
+ Continue;
|
|
|
|
+ if n.HasAggregate then
|
|
|
|
+ begin
|
|
|
|
+ if moNoResetAggregateOnPrint in m.Options then
|
|
|
|
+ begin
|
|
|
|
+ // do nothing
|
|
|
|
+ end
|
|
|
|
+ // apply memo.Options rules if applicable
|
|
|
|
+ else if ((self is TFPReportCustomPageHeaderBand) and (moResetAggregateOnPage in m.Options))
|
|
|
|
+ or ((self is TFPReportCustomColumnHeaderBand) and (moResetAggregateOnColumn in m.Options))
|
|
|
|
+ or ((self is TFPReportCustomGroupHeaderBand) and (moResetAggregateOnGroup in m.Options)) then
|
|
|
|
+ n.InitAggregate
|
|
|
|
+ // apply Page/Column/Group/Data footer rule
|
|
|
|
+ else if (self is TFPReportCustomPageFooterBand)
|
|
|
|
+ or (self is TFPReportCustomColumnFooterBand)
|
|
|
|
+ or (self is TFPReportCustomGroupFooterBand)
|
|
|
|
+ or (self is TFPReportCustomDataFooterBand) then
|
|
|
|
+ n.InitAggregate
|
|
|
|
+ else
|
|
|
|
+ // default rule - reset on print. applies to all memos
|
|
|
|
+ n.InitAggregate;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
|
|
+ else if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomCheckbox then
|
|
|
|
+ begin
|
|
|
|
+ cb := TFPReportCheckbox(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
+ s := ExpandMacro(cb.Expression, True);
|
|
|
|
+ cb.FTestResult := StrToBoolDef(s, False);
|
|
|
|
+ end
|
|
|
|
+ else if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomImage then
|
|
|
|
+ begin
|
|
|
|
+ img := TFPReportCustomImage(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
+ if (img.FieldName <> '') and Assigned(GetData) then
|
|
|
|
+ img.LoadDBData(GetData);
|
|
|
|
+ end;
|
|
|
|
+ end; { for c := 0 to ... }
|
|
|
|
+ end; { if Assigned(FChildren) ... }
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPCustomReport.Destroy;
|
|
|
|
|
|
+procedure TFPReportCustomBand.RecalcLayout;
|
|
begin
|
|
begin
|
|
- EmptyRTObjects;
|
|
|
|
- FreeAndNil(FReportData);
|
|
|
|
- FreeAndNil(FRTObjects);
|
|
|
|
- FreeAndNil(FPages);
|
|
|
|
- FreeAndNil(FExpr);
|
|
|
|
- FreeAndNil(FReferenceList);
|
|
|
|
- FreeAndNil(FImages);
|
|
|
|
- FreeAndNil(FVariables);
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ inherited RecalcLayout;
|
|
|
|
+ if StretchMode <> smDontStretch then
|
|
|
|
+ ApplyStretchMode;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.SaveDataToNames;
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+procedure TFPReportCustomBand.Assign(Source: TPersistent);
|
|
|
|
+var
|
|
|
|
+ E: TFPReportCustomBand;
|
|
|
|
+begin
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+ if Source is TFPReportCustomBand then
|
|
|
|
+ begin
|
|
|
|
+ E := TFPReportCustomBand(Source);
|
|
|
|
+ FChildBand := E.ChildBand;
|
|
|
|
+ FStretchMode := E.StretchMode;
|
|
|
|
+ FVisibleOnPage := E.VisibleOnPage;
|
|
|
|
+ UseParentFont := E.UseParentFont;
|
|
|
|
+ if not UseParentFont then
|
|
|
|
+ Font.Assign(E.Font);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+class function TFPReportCustomBand.ReportBandType: TFPReportBandType;
|
|
begin
|
|
begin
|
|
- For I:=0 to PageCount-1 do
|
|
|
|
- Pages[i].SaveDataToNames;
|
|
|
|
|
|
+ Result:=btUnknown;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.RestoreDataFromNames;
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+procedure TFPReportCustomBand.BeforePrint;
|
|
|
|
+var
|
|
|
|
+ i: integer;
|
|
|
|
+ c: TFPReportElement;
|
|
|
|
+begin
|
|
|
|
+ inherited BeforePrint;
|
|
|
|
+ if Visible = false then
|
|
|
|
+ exit;
|
|
|
|
+ if Assigned(FChildren) then
|
|
|
|
+ begin
|
|
|
|
+ for i := 0 to FChildren.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ c := Child[i];
|
|
|
|
+ c.BeforePrint;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
|
|
+procedure TFPReportCustomBand.DoWriteLocalProperties(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
begin
|
|
begin
|
|
- For I:=0 to PageCount-1 do
|
|
|
|
- Pages[i].RestoreDataFromNames;
|
|
|
|
|
|
+ inherited DoWriteLocalProperties(AWriter, AOriginal);
|
|
|
|
+ AWriter.WriteBoolean('UseParentFont', UseParentFont);
|
|
|
|
+ if not UseParentFont then
|
|
|
|
+ begin
|
|
|
|
+ AWriter.WriteString('FontName', Font.Name);
|
|
|
|
+ AWriter.WriteInteger('FontSize', Font.Size);
|
|
|
|
+ AWriter.WriteInteger('FontColor', Font.Color);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.AddPage(APage: TFPReportCustomPage);
|
|
|
|
|
|
+constructor TFPReportCustomBand.Create(AOwner: TComponent);
|
|
begin
|
|
begin
|
|
- if not Assigned(FPages) then
|
|
|
|
- begin
|
|
|
|
- FPages := TFPList.Create;
|
|
|
|
- FPages.Add(APage);
|
|
|
|
- end
|
|
|
|
- else if FPages.IndexOf(APage) = -1 then
|
|
|
|
- FPages.Add(APage);
|
|
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FVisibleOnPage := vpAll;
|
|
|
|
+ FUseParentFont := True;
|
|
|
|
+ FFont := nil
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.RemovePage(APage: TFPReportCustomPage);
|
|
|
|
|
|
+destructor TFPReportCustomBand.Destroy;
|
|
begin
|
|
begin
|
|
- if Assigned(FPages) then
|
|
|
|
- FPages.Remove(APage);
|
|
|
|
|
|
+ FreeAndNil(FFont);
|
|
|
|
+ inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
|
|
+procedure TFPReportCustomBand.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
begin
|
|
begin
|
|
- // ignore AOriginal here as we don't support whole report diffs, only element diffs
|
|
|
|
- AWriter.PushElement('Report');
|
|
|
|
|
|
+ AWriter.PushElement(GetReportBandName);
|
|
try
|
|
try
|
|
inherited WriteElement(AWriter, AOriginal);
|
|
inherited WriteElement(AWriter, AOriginal);
|
|
- // local properties
|
|
|
|
- AWriter.WriteString('Title', Title);
|
|
|
|
- AWriter.WriteString('Author', Author);
|
|
|
|
- AWriter.WriteDateTime('DateCreated', DateCreated);
|
|
|
|
- // now the design-time images
|
|
|
|
- AWriter.PushElement('Images');
|
|
|
|
- try
|
|
|
|
- for i := 0 to Images.Count-1 do
|
|
|
|
- begin
|
|
|
|
- AWriter.PushElement(IntToStr(i)); // use image index as identifier
|
|
|
|
- try
|
|
|
|
- Images[i].WriteElement(AWriter);
|
|
|
|
- finally
|
|
|
|
- AWriter.PopElement;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- finally
|
|
|
|
- AWriter.PopElement;
|
|
|
|
- end;
|
|
|
|
- // now the pages
|
|
|
|
- AWriter.PushElement('Pages');
|
|
|
|
- try
|
|
|
|
- for i := 0 to PageCount - 1 do
|
|
|
|
- begin
|
|
|
|
- AWriter.PushElement(IntToStr(i)); // use page index as identifier
|
|
|
|
- try
|
|
|
|
- Pages[i].WriteElement(AWriter);
|
|
|
|
- finally
|
|
|
|
- AWriter.PopElement;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- finally
|
|
|
|
- AWriter.PopElement;
|
|
|
|
- end;
|
|
|
|
|
|
+ if Assigned(ChildBand) then
|
|
|
|
+ AWriter.WriteString('ChildBand', ChildBand.Name);
|
|
|
|
+ if Assigned(GetData) then
|
|
|
|
+ AWriter.WriteString('Data', GetData.Name);
|
|
|
|
+ AWriter.WriteString('VisibleOnPage', VisibleOnPageToString(FVisibleOnPage));
|
|
finally
|
|
finally
|
|
AWriter.PopElement;
|
|
AWriter.PopElement;
|
|
end;
|
|
end;
|
|
- // TODO: Implement writing OnRenderReport, OnBeginReport, OnEndReport
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
|
|
+procedure TFPReportCustomBand.ReadElement(AReader: TFPReportStreamer);
|
|
var
|
|
var
|
|
E: TObject;
|
|
E: TObject;
|
|
- i: integer;
|
|
|
|
- p: TFPReportPage;
|
|
|
|
- lImgItem: TFPReportImageItem;
|
|
|
|
|
|
+ s: string;
|
|
begin
|
|
begin
|
|
- ClearReferenceList;
|
|
|
|
- E := AReader.FindChild('Report');
|
|
|
|
|
|
+ E := AReader.FindChild(GetReportBandName);
|
|
if Assigned(E) then
|
|
if Assigned(E) then
|
|
begin
|
|
begin
|
|
AReader.PushElement(E);
|
|
AReader.PushElement(E);
|
|
try
|
|
try
|
|
inherited ReadElement(AReader);
|
|
inherited ReadElement(AReader);
|
|
- FTitle := AReader.ReadString('Title', Title);
|
|
|
|
- FAuthor := AReader.ReadString('Author', Author);
|
|
|
|
- FDateCreated := AReader.ReadDateTime('DateCreated', Now);
|
|
|
|
-
|
|
|
|
- E := AReader.FindChild('Images');
|
|
|
|
- if Assigned(E) then
|
|
|
|
- begin
|
|
|
|
- AReader.PushElement(E);
|
|
|
|
- for i := 0 to AReader.ChildCount-1 do
|
|
|
|
- begin
|
|
|
|
- E := AReader.GetChild(i);
|
|
|
|
- AReader.PushElement(E); // child index is the identifier
|
|
|
|
- try
|
|
|
|
- lImgItem := Images.AddImageItem;
|
|
|
|
- lImgItem.ReadElement(AReader);
|
|
|
|
- finally
|
|
|
|
- AReader.PopElement;
|
|
|
|
- end;
|
|
|
|
- end; { for i }
|
|
|
|
- AReader.PopElement;
|
|
|
|
- end; { images }
|
|
|
|
-
|
|
|
|
- E := AReader.FindChild('Pages');
|
|
|
|
- if Assigned(E) then
|
|
|
|
|
|
+ s := AReader.ReadString('ChildBand', '');
|
|
|
|
+ if s <> '' then
|
|
|
|
+ Page.Report.AddReference(self.Name, s);
|
|
|
|
+// Page.Report.AddReference(self, 'ChildBand', s);
|
|
|
|
+ FVisibleOnPage := StringToVisibleOnPage(AReader.ReadString('VisibleOnPage', 'vpAll'));
|
|
|
|
+ FUseParentFont := AReader.ReadBoolean('UseParentFont', UseParentFont);
|
|
|
|
+ if not FUseParentFont then
|
|
begin
|
|
begin
|
|
- AReader.PushElement(E);
|
|
|
|
- for i := 0 to AReader.ChildCount-1 do
|
|
|
|
- begin
|
|
|
|
- E := AReader.GetChild(i);
|
|
|
|
- AReader.PushElement(E); // child index is the identifier
|
|
|
|
- try
|
|
|
|
- p := TFPReportPage.Create(self);
|
|
|
|
- p.ReadElement(AReader);
|
|
|
|
- AddPage(p);
|
|
|
|
- finally
|
|
|
|
- AReader.PopElement;
|
|
|
|
- end;
|
|
|
|
- end; { for i }
|
|
|
|
- AReader.PopElement;
|
|
|
|
- end; { pages }
|
|
|
|
|
|
+ Font.Name := AReader.ReadString('FontName', Font.Name);
|
|
|
|
+ Font.Size := AReader.ReadInteger('FontSize', Font.Size);
|
|
|
|
+ Font.Color := AReader.ReadInteger('FontColor', Font.Color);
|
|
|
|
+ end;
|
|
|
|
|
|
- // TODO: Implement reading OnRenderReport, OnBeginReport, OnEndReport
|
|
|
|
|
|
+ // TODO: Read Data information
|
|
|
|
+ S:=AReader.ReadString('Data','');
|
|
|
|
+ if (S<>'') then
|
|
|
|
+ SetDataFromName(S);
|
|
finally
|
|
finally
|
|
AReader.PopElement;
|
|
AReader.PopElement;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
- FixupReferences;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.StartRender;
|
|
|
|
|
|
+{ TFPReportCustomBandWithData }
|
|
|
|
+
|
|
|
|
+procedure TFPReportCustomBandWithData.SetData(const AValue: TFPReportData);
|
|
begin
|
|
begin
|
|
- inherited StartRender;
|
|
|
|
- DoBeforeRenderReport;
|
|
|
|
|
|
+ if FData = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ if Assigned(FData) then
|
|
|
|
+ FData.RemoveFreeNotification(Self);
|
|
|
|
+ FData := AValue;
|
|
|
|
+ if Assigned(FData) then
|
|
|
|
+ FData.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.EndRender;
|
|
|
|
|
|
+procedure TFPReportCustomBandWithData.SaveDataToNames;
|
|
begin
|
|
begin
|
|
- inherited EndRender;
|
|
|
|
- DoAfterRenderReport;
|
|
|
|
|
|
+ inherited SaveDataToNames;
|
|
|
|
+ if Assigned(FData) then
|
|
|
|
+ FDataName:=FData.Name
|
|
|
|
+ else
|
|
|
|
+ FDataName:='';
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPCustomReport.FindRecursive(const AName: string): TFPReportElement;
|
|
|
|
-var
|
|
|
|
- p, b, c: integer;
|
|
|
|
-begin
|
|
|
|
- Result := nil;
|
|
|
|
- if AName = '' then
|
|
|
|
- Exit;
|
|
|
|
- for p := 0 to PageCount-1 do
|
|
|
|
- begin
|
|
|
|
- for b := 0 to Pages[p].BandCount-1 do
|
|
|
|
- begin
|
|
|
|
- if SameText(Pages[p].Bands[b].Name, AName) then
|
|
|
|
- Result := Pages[p].Bands[b];
|
|
|
|
- if Assigned(Result) then
|
|
|
|
- Exit;
|
|
|
|
|
|
+procedure TFPReportCustomBandWithData.ResolveDataName;
|
|
|
|
|
|
- for c := 0 to Pages[p].Bands[b].ChildCount-1 do
|
|
|
|
- begin
|
|
|
|
- if SameText(Pages[p].Bands[b].Child[c].Name, AName) then
|
|
|
|
- Result := Pages[p].Bands[b].Child[c];
|
|
|
|
- if Assigned(Result) then
|
|
|
|
- Exit;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
|
|
+begin
|
|
|
|
+ if (FDataName<>'') then
|
|
|
|
+ Data:=Report.ReportData.FindReportData(FDataName)
|
|
|
|
+ else
|
|
|
|
+ Data:=Nil;
|
|
end;
|
|
end;
|
|
|
|
+procedure TFPReportCustomBandWithData.RestoreDataFromNames;
|
|
|
|
|
|
-procedure TFPCustomReport.RunReport;
|
|
|
|
begin
|
|
begin
|
|
- DoBeginReport;
|
|
|
|
|
|
+ inherited RestoreDataFromNames;
|
|
|
|
+ ResolveDataName;
|
|
|
|
+end;
|
|
|
|
|
|
- StartLayout;
|
|
|
|
- FExpr := TFPexpressionParser.Create(nil);
|
|
|
|
- try
|
|
|
|
- InitializeDefaultExpressions;
|
|
|
|
- DoPrepareReport;
|
|
|
|
- finally
|
|
|
|
- RestoreDefaultVariables;
|
|
|
|
- FreeAndNil(FExpr);
|
|
|
|
- end;
|
|
|
|
- EndLayout;
|
|
|
|
|
|
+function TFPReportCustomBandWithData.GetData: TFPReportData;
|
|
|
|
+begin
|
|
|
|
+ Result := FData;
|
|
|
|
+end;
|
|
|
|
|
|
- DoEndReport;
|
|
|
|
|
|
+procedure TFPReportCustomBandWithData.SetDataFromName(AName: String);
|
|
|
|
+begin
|
|
|
|
+ FDataName:=AName;
|
|
|
|
+ ResolveDataName;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPCustomReport.RenderReport(const AExporter: TFPReportExporter);
|
|
|
|
|
|
+procedure TFPReportCustomBandWithData.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
begin
|
|
- if not Assigned(AExporter) then
|
|
|
|
- Exit;
|
|
|
|
- StartRender;
|
|
|
|
- try
|
|
|
|
- AExporter.Report := self;
|
|
|
|
- AExporter.Execute;
|
|
|
|
- finally
|
|
|
|
- EndRender;
|
|
|
|
|
|
+ if Operation = opRemove then
|
|
|
|
+ begin
|
|
|
|
+ if AComponent = FData then
|
|
|
|
+ FData := nil;
|
|
end;
|
|
end;
|
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{$IFDEF gdebug}
|
|
|
|
-function TFPCustomReport.DebugPreparedPageAsJSON(const APageNo: Byte): string;
|
|
|
|
-var
|
|
|
|
- rs: TFPReportStreamer;
|
|
|
|
|
|
+constructor TFPReportCustomBandWithData.Create(AOwner: TComponent);
|
|
begin
|
|
begin
|
|
- if APageNo > RTObjects.Count-1 then
|
|
|
|
- Exit;
|
|
|
|
- rs := TFPReportJSONStreamer.Create(nil);
|
|
|
|
- try
|
|
|
|
- TFPReportCustomPage(RTObjects[APageNo]).WriteElement(rs);
|
|
|
|
- Result := TFPReportJSONStreamer(rs).JSON.FormatJSON;
|
|
|
|
- finally
|
|
|
|
- rs.Free;
|
|
|
|
|
|
+ FData := nil;
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TFPReportCustomGroupFooterBand }
|
|
|
|
+
|
|
|
|
+procedure TFPReportCustomGroupFooterBand.SetGroupHeader(const AValue: TFPReportCustomGroupHeaderBand);
|
|
|
|
+begin
|
|
|
|
+ if FGroupHeader = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ if Assigned(FGroupHeader) then
|
|
|
|
+ begin
|
|
|
|
+ FGroupHeader.FGroupFooter := nil;
|
|
|
|
+ FGroupHeader.RemoveFreeNotification(Self);
|
|
|
|
+ end;
|
|
|
|
+ FGroupHeader := AValue;
|
|
|
|
+ if Assigned(FGroupHeader) then
|
|
|
|
+ begin
|
|
|
|
+ FGroupHeader.FGroupFooter := Self;
|
|
|
|
+ FGroupHeader.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
-{$ENDIF}
|
|
|
|
|
|
|
|
-{ TFPReportMargins }
|
|
|
|
|
|
+function TFPReportCustomGroupFooterBand.GetReportBandName: string;
|
|
|
|
+begin
|
|
|
|
+ Result := 'GroupFooterBand';
|
|
|
|
+end;
|
|
|
|
|
|
-procedure TFPReportMargins.SetBottom(const AValue: TFPReportUnits);
|
|
|
|
|
|
+procedure TFPReportCustomGroupFooterBand.DoWriteLocalProperties(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
begin
|
|
begin
|
|
- if FBottom = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FBottom := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ inherited DoWriteLocalProperties(AWriter, AOriginal);
|
|
|
|
+ if Assigned(GroupHeader) then
|
|
|
|
+ AWriter.WriteString('GroupHeader', GroupHeader.Name);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.SetLeft(const AValue: TFPReportUnits);
|
|
|
|
|
|
+procedure TFPReportCustomGroupFooterBand.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
begin
|
|
- if FLeft = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FLeft := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ if (Operation = opRemove) and (AComponent = FGroupHeader) then
|
|
|
|
+ FGroupHeader := nil;
|
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.SetRight(const AValue: TFPReportUnits);
|
|
|
|
|
|
+procedure TFPReportCustomGroupFooterBand.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
+var
|
|
|
|
+ s: string;
|
|
|
|
+// c: TFPReportElement;
|
|
begin
|
|
begin
|
|
- if FRight = AValue then
|
|
|
|
|
|
+// c := nil;
|
|
|
|
+ inherited ReadElement(AReader);
|
|
|
|
+ s := AReader.ReadString('GroupHeader', '');
|
|
|
|
+ if s = '' then
|
|
Exit;
|
|
Exit;
|
|
- FRight := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ // TODO: recursively search Page.Report for the GroupHeader
|
|
|
|
+ //c := Page.Report.FindComponent(s);
|
|
|
|
+ //if Assigned(c) then
|
|
|
|
+ // FGroupHeader := TFPReportCustomGroupHeaderBand(c);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.SetTop(const AValue: TFPReportUnits);
|
|
|
|
|
|
+class function TFPReportCustomGroupFooterBand.ReportBandType: TFPReportBandType;
|
|
begin
|
|
begin
|
|
- if FTop = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FTop := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ Result:=btGroupFooter;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.Changed;
|
|
|
|
|
|
+
|
|
|
|
+{ TFPReportImageItem }
|
|
|
|
+
|
|
|
|
+function TFPReportImageItem.GetHeight: Integer;
|
|
begin
|
|
begin
|
|
- if Assigned(FPage) then
|
|
|
|
- FPage.MarginsChanged;
|
|
|
|
|
|
+ If Assigned(FImage) then
|
|
|
|
+ Result:=FImage.Height
|
|
|
|
+ else
|
|
|
|
+ Result:=FHeight;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportMargins.Create(APage: TFPReportCustomPage);
|
|
|
|
|
|
+function TFPReportImageItem.GetStreamed: TBytes;
|
|
begin
|
|
begin
|
|
- inherited Create;
|
|
|
|
- FPage := APage;
|
|
|
|
|
|
+ if Length(FStreamed)=0 then
|
|
|
|
+ CreateStreamedData;
|
|
|
|
+ Result:=FStreamed;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.Assign(Source: TPersistent);
|
|
|
|
-var
|
|
|
|
- S: TFPReportMargins;
|
|
|
|
|
|
+function TFPReportImageItem.GetWidth: Integer;
|
|
begin
|
|
begin
|
|
- if Source is TFPReportMargins then
|
|
|
|
- begin
|
|
|
|
- S := Source as TFPReportMargins;
|
|
|
|
- FTop := S.Top;
|
|
|
|
- FBottom := S.Bottom;
|
|
|
|
- FLeft := S.Left;
|
|
|
|
- FRight := S.Right;
|
|
|
|
- Changed;
|
|
|
|
- end
|
|
|
|
|
|
+ If Assigned(FImage) then
|
|
|
|
+ Result:=FImage.Width
|
|
else
|
|
else
|
|
- inherited Assign(Source);
|
|
|
|
|
|
+ Result:=FWidth;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportMargins.Equals(AMargins: TFPReportMargins): boolean;
|
|
|
|
|
|
+procedure TFPReportImageItem.SetImage(AValue: TFPCustomImage);
|
|
begin
|
|
begin
|
|
- Result := (AMargins = Self)
|
|
|
|
- or ((Top = AMargins.Top) and (Left = AMargins.Left) and
|
|
|
|
- (Right = AMargins.Right) and (Bottom = AMargins.Bottom));
|
|
|
|
|
|
+ if FImage=AValue then Exit;
|
|
|
|
+ FImage:=AValue;
|
|
|
|
+ SetLength(FStreamed,0);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportMargins);
|
|
|
|
|
|
+procedure TFPReportImageItem.SetStreamed(AValue: TBytes);
|
|
begin
|
|
begin
|
|
- if (AOriginal = nil) then
|
|
|
|
- begin
|
|
|
|
- AWriter.WriteFloat('Top', Top);
|
|
|
|
- AWriter.WriteFloat('Left', Left);
|
|
|
|
- AWriter.WriteFloat('Bottom', Bottom);
|
|
|
|
- AWriter.WriteFloat('Right', Right);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- AWriter.WriteFloatDiff('Top', Top, AOriginal.Top);
|
|
|
|
- AWriter.WriteFloatDiff('Left', Left, AOriginal.Left);
|
|
|
|
- AWriter.WriteFloatDiff('Bottom', Bottom, AOriginal.Bottom);
|
|
|
|
- AWriter.WriteFloatDiff('Right', Right, AOriginal.Right);
|
|
|
|
|
|
+ If AValue=FStreamed then exit;
|
|
|
|
+ SetLength(FStreamed,0);
|
|
|
|
+ FStreamed:=AValue;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportImageItem.LoadPNGFromStream(AStream: TStream);
|
|
|
|
+var
|
|
|
|
+ PNGReader: TFPReaderPNG;
|
|
|
|
+begin
|
|
|
|
+ if not Assigned(AStream) then
|
|
|
|
+ Exit;
|
|
|
|
+
|
|
|
|
+ { we use Image property here so it frees any previous image }
|
|
|
|
+ if Assigned(FImage) then
|
|
|
|
+ FreeAndNil(FImage);
|
|
|
|
+ FImage := TFPCompactImgRGBA8Bit.Create(0, 0);
|
|
|
|
+ try
|
|
|
|
+ PNGReader := TFPReaderPNG.Create;
|
|
|
|
+ try
|
|
|
|
+ FImage.LoadFromStream(AStream, PNGReader); // auto size image
|
|
|
|
+ finally
|
|
|
|
+ PNGReader.Free;
|
|
|
|
+ end;
|
|
|
|
+ except
|
|
|
|
+ FreeAndNil(FImage);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportMargins.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
|
|
+constructor TFPReportImageItem.Create(ACollection: TCollection);
|
|
begin
|
|
begin
|
|
- Top := AReader.ReadFloat('Top', Top);
|
|
|
|
- Left := AReader.ReadFloat('Left', Left);
|
|
|
|
- Bottom := AReader.ReadFloat('Bottom', Bottom);
|
|
|
|
- Right := AReader.ReadFloat('Right', Right);
|
|
|
|
|
|
+ inherited Create(ACollection);
|
|
|
|
+ FOwnsImage := True;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportCustomBand }
|
|
|
|
|
|
+destructor TFPReportImageItem.Destroy;
|
|
|
|
+begin
|
|
|
|
+ if FOwnsImage then
|
|
|
|
+ FreeAndNil(FImage);
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
|
|
-function TFPReportCustomBand.GetReportPage: TFPReportCustomPage;
|
|
|
|
|
|
+procedure TFPReportImageItem.CreateStreamedData;
|
|
|
|
+Var
|
|
|
|
+ X, Y: Integer;
|
|
|
|
+ C: TFPColor;
|
|
|
|
+ MS: TMemoryStream;
|
|
|
|
+ Str: TStream;
|
|
|
|
+ CWhite: TFPColor; // white color
|
|
begin
|
|
begin
|
|
- Result := Parent as TFPReportCustomPage;
|
|
|
|
|
|
+ FillMem(@CWhite, SizeOf(CWhite), $FF);
|
|
|
|
+ FWidth:=Image.Width;
|
|
|
|
+ FHeight:=Image.Height;
|
|
|
|
+ Str := nil;
|
|
|
|
+ MS := TMemoryStream.Create;
|
|
|
|
+ try
|
|
|
|
+ Str := MS;
|
|
|
|
+ for Y:=0 to FHeight-1 do
|
|
|
|
+ for X:=0 to FWidth-1 do
|
|
|
|
+ begin
|
|
|
|
+ C:=Image.Colors[x,y];
|
|
|
|
+ if C.alpha < $FFFF then // remove alpha channel - assume white background
|
|
|
|
+ C := AlphaBlend(CWhite, C);
|
|
|
|
+
|
|
|
|
+ Str.WriteByte(C.Red shr 8);
|
|
|
|
+ Str.WriteByte(C.Green shr 8);
|
|
|
|
+ Str.WriteByte(C.blue shr 8);
|
|
|
|
+ end;
|
|
|
|
+ if Str<>MS then
|
|
|
|
+ Str.Free;
|
|
|
|
+ Str := nil;
|
|
|
|
+ SetLength(FStreamed, MS.Size);
|
|
|
|
+ MS.Position := 0;
|
|
|
|
+ if MS.Size>0 then
|
|
|
|
+ MS.ReadBuffer(FStreamed[0], MS.Size);
|
|
|
|
+ finally
|
|
|
|
+ Str.Free;
|
|
|
|
+ MS.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomBand.GetFont: TFPReportFont;
|
|
|
|
|
|
+function TFPReportImageItem.WriteImageStream(AStream: TStream): UInt64;
|
|
|
|
+var
|
|
|
|
+ Img: TBytes;
|
|
begin
|
|
begin
|
|
- if UseParentFont then
|
|
|
|
- begin
|
|
|
|
- if Assigned(Owner) then
|
|
|
|
- Result := TFPReportCustomPage(Owner).Font
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- FFont := TFPReportFont.Create;
|
|
|
|
- Result := FFont;
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- Result := FFont;
|
|
|
|
|
|
+ Img := StreamedData;
|
|
|
|
+ Result := Length(Img);
|
|
|
|
+ AStream.WriteBuffer(Img[0],Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomBand.IsStringValueZero(const AValue: string): boolean;
|
|
|
|
|
|
+function TFPReportImageItem.Equals(AImage: TFPCustomImage): boolean;
|
|
var
|
|
var
|
|
- lIntVal: integer;
|
|
|
|
- lFloatVal: double;
|
|
|
|
|
|
+ x, y: Integer;
|
|
begin
|
|
begin
|
|
- Result := False;
|
|
|
|
- if TryStrToInt(AValue, lIntVal) then
|
|
|
|
- begin
|
|
|
|
- if lIntVal = 0 then
|
|
|
|
- Result := True;
|
|
|
|
- end
|
|
|
|
- else if TryStrToFloat(AValue, lFloatVal) then
|
|
|
|
- begin
|
|
|
|
- if lFloatVal = 0 then
|
|
|
|
- Result := True;
|
|
|
|
- end;
|
|
|
|
|
|
+ Result := True;
|
|
|
|
+ for x := 0 to Image.Width-1 do
|
|
|
|
+ for y := 0 to Image.Height-1 do
|
|
|
|
+ if Image.Pixels[x, y] <> AImage.Pixels[x, y] then
|
|
|
|
+ begin
|
|
|
|
+ Result := False;
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetChildBand(AValue: TFPReportChildBand);
|
|
|
|
|
|
+procedure TFPReportImageItem.WriteElement(AWriter: TFPReportStreamer);
|
|
var
|
|
var
|
|
- b: TFPReportCustomBand;
|
|
|
|
|
|
+ ms: TMemoryStream;
|
|
|
|
+ png: TFPWriterPNG;
|
|
begin
|
|
begin
|
|
- if FChildBand = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FChildBand := AValue;
|
|
|
|
- b := FChildBand;
|
|
|
|
- while b <> nil do
|
|
|
|
|
|
+ if Assigned(Image) then
|
|
begin
|
|
begin
|
|
- b := b.ChildBand;
|
|
|
|
- if b = self then
|
|
|
|
- raise EReportError.Create(SErrChildBandCircularReference);
|
|
|
|
|
|
+ ms := TMemoryStream.Create;
|
|
|
|
+ try
|
|
|
|
+ png := TFPWriterPNG.create;
|
|
|
|
+ png.Indexed := False;
|
|
|
|
+ Image.SaveToStream(ms, png);
|
|
|
|
+ ms.Position := 0;
|
|
|
|
+ AWriter.WriteStream('ImageData', ms);
|
|
|
|
+ finally
|
|
|
|
+ png.Free;
|
|
|
|
+ ms.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.ApplyStretchMode;
|
|
|
|
|
|
+procedure TFPReportImageItem.ReadElement(AReader: TFPReportStreamer);
|
|
var
|
|
var
|
|
- h: TFPReportUnits;
|
|
|
|
- c: TFPReportElement;
|
|
|
|
- i: integer;
|
|
|
|
|
|
+ ms: TMemoryStream;
|
|
begin
|
|
begin
|
|
- h := RTLayout.Height;
|
|
|
|
- for i := 0 to ChildCount-1 do
|
|
|
|
- begin
|
|
|
|
- c := Child[i];
|
|
|
|
- if c.RTLayout.Top + c.RTLayout.Height > h then
|
|
|
|
- h := c.RTLayout.Top + c.RTLayout.Height;
|
|
|
|
|
|
+ ms := TMemoryStream.Create;
|
|
|
|
+ try
|
|
|
|
+ if AReader.ReadStream('ImageData', ms) then
|
|
|
|
+ begin
|
|
|
|
+ ms.Position := 0;
|
|
|
|
+ LoadPNGFromStream(ms);
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ ms.Free;
|
|
end;
|
|
end;
|
|
- RTLayout.Height := h;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetFont(AValue: TFPReportFont);
|
|
|
|
-begin
|
|
|
|
- if UseParentFont then
|
|
|
|
- UseParentFont := False;
|
|
|
|
- FFont.Assign(AValue);
|
|
|
|
- Changed;
|
|
|
|
-end;
|
|
|
|
|
|
+{ TFPReportImages }
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetUseParentFont(AValue: boolean);
|
|
|
|
|
|
+function TFPReportImages.GetImg(AIndex: Integer): TFPReportImageItem;
|
|
begin
|
|
begin
|
|
- if FUseParentFont = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FUseParentFont := AValue;
|
|
|
|
- if FUseParentFont then
|
|
|
|
- FreeAndNil(FFont)
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- FFont := TFPReportFont.Create;
|
|
|
|
- if Assigned(Owner) then
|
|
|
|
- FFont.Assign(TFPReportCustomPage(Owner).Font);
|
|
|
|
- end;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ Result := Items[AIndex] as TFPReportImageItem;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetVisibleOnPage(AValue: TFPReportVisibleOnPage);
|
|
|
|
|
|
+function TFPReportImages.GetReportOwner: TFPCustomReport;
|
|
begin
|
|
begin
|
|
- if FVisibleOnPage = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FVisibleOnPage := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ Result:=Owner as TFPCustomReport;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomBand.GetReportBandName: string;
|
|
|
|
|
|
+
|
|
|
|
+constructor TFPReportImages.Create(AOwner: TFPCustomReport; AItemClass: TCollectionItemClass);
|
|
begin
|
|
begin
|
|
- Result := 'FPCustomReportBand';
|
|
|
|
|
|
+ inherited Create(aOwner,AItemClass);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomBand.GetData: TFPReportData;
|
|
|
|
|
|
+function TFPReportImages.AddImageItem: TFPReportImageItem;
|
|
begin
|
|
begin
|
|
- result := nil;
|
|
|
|
|
|
+ Result := Add as TFPReportImageItem;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetDataFromName(AName: String);
|
|
|
|
|
|
+function TFPReportImages.AddFromStream(const AStream: TStream;
|
|
|
|
+ Handler: TFPCustomImageReaderClass; KeepImage: Boolean): Integer;
|
|
|
|
+var
|
|
|
|
+ I: TFPCustomImage;
|
|
|
|
+ IP: TFPReportImageItem;
|
|
|
|
+ Reader: TFPCustomImageReader;
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ IP := AddImageItem;
|
|
|
|
+ I := TFPCompactImgRGBA8Bit.Create(0,0);
|
|
|
|
+ Reader := Handler.Create;
|
|
|
|
+ try
|
|
|
|
+ I.LoadFromStream(AStream, Reader);
|
|
|
|
+ finally
|
|
|
|
+ Reader.Free;
|
|
|
|
+ end;
|
|
|
|
+ IP.Image := I;
|
|
|
|
+ if Not KeepImage then
|
|
|
|
+ begin
|
|
|
|
+ IP.CreateStreamedData;
|
|
|
|
+ IP.FImage := Nil; // not through property, that would clear the image
|
|
|
|
+ I.Free;
|
|
|
|
+ end;
|
|
|
|
+ Result := Count-1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.SetParent(const AValue: TFPReportElement);
|
|
|
|
|
|
+function TFPReportImages.AddFromFile(const AFileName: string; KeepImage: Boolean): Integer;
|
|
|
|
+
|
|
|
|
+ {$IF NOT (FPC_FULLVERSION >= 30101)}
|
|
|
|
+ function FindReaderFromExtension(extension: String): TFPCustomImageReaderClass;
|
|
|
|
+ var
|
|
|
|
+ s: string;
|
|
|
|
+ r: integer;
|
|
|
|
+ begin
|
|
|
|
+ extension := lowercase (extension);
|
|
|
|
+ if (extension <> '') and (extension[1] = '.') then
|
|
|
|
+ system.delete (extension,1,1);
|
|
|
|
+ with ImageHandlers do
|
|
|
|
+ begin
|
|
|
|
+ r := count-1;
|
|
|
|
+ s := extension + ';';
|
|
|
|
+ while (r >= 0) do
|
|
|
|
+ begin
|
|
|
|
+ Result := ImageReader[TypeNames[r]];
|
|
|
|
+ if (pos(s,{$if (FPC_FULLVERSION = 20604)}Extentions{$else}Extensions{$endif}[TypeNames[r]]+';') <> 0) then
|
|
|
|
+ Exit;
|
|
|
|
+ dec (r);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ Result := nil;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ function FindReaderFromFileName(const filename: String): TFPCustomImageReaderClass;
|
|
|
|
+ begin
|
|
|
|
+ Result := FindReaderFromExtension(ExtractFileExt(filename));
|
|
|
|
+ end;
|
|
|
|
+ {$ENDIF}
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ FS: TFileStream;
|
|
begin
|
|
begin
|
|
- if not ((AValue = nil) or (AValue is TFPReportCustomPage)) then
|
|
|
|
- ReportError(SErrNotAReportPage, [AValue.ClassName, AValue.Name]);
|
|
|
|
- inherited SetParent(AValue);
|
|
|
|
|
|
+ FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
|
|
|
+ try
|
|
|
|
+ Result := AddFromStream(FS,
|
|
|
|
+ {$IF (FPC_FULLVERSION >= 30101)}TFPCustomImage.{$ENDIF}FindReaderFromFileName(AFileName), KeepImage);
|
|
|
|
+ finally
|
|
|
|
+ FS.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.CreateRTLayout;
|
|
|
|
|
|
+function TFPReportImages.AddFromData(const AImageData: Pointer; const AImageDataSize: LongWord): integer;
|
|
|
|
+var
|
|
|
|
+ s: TMemoryStream;
|
|
begin
|
|
begin
|
|
- inherited CreateRTLayout;
|
|
|
|
- FRTLayout.Left := Page.Layout.Left;
|
|
|
|
|
|
+ s := TMemoryStream.Create;
|
|
|
|
+ try
|
|
|
|
+ s.Write(AImageData^, AImageDataSize);
|
|
|
|
+ s.Position := 0;
|
|
|
|
+ Result := AddFromStream(s, TFPReaderPNG, True);
|
|
|
|
+ finally
|
|
|
|
+ s.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.PrepareObjects;
|
|
|
|
-
|
|
|
|
|
|
+function TFPReportImages.GetIndexFromID(const AID: integer): integer;
|
|
var
|
|
var
|
|
- lRTPage: TFPReportCustomPage;
|
|
|
|
i: integer;
|
|
i: integer;
|
|
- m: TFPReportMemo;
|
|
|
|
- cb: TFPReportCheckbox;
|
|
|
|
- img: TFPReportCustomImage;
|
|
|
|
- s: string;
|
|
|
|
- c: integer;
|
|
|
|
- n: TFPExprNode;
|
|
|
|
- nIdx: integer;
|
|
|
|
-
|
|
|
|
begin
|
|
begin
|
|
- i := Page.Report.FRTCurPageIdx;
|
|
|
|
- if Assigned(Page.Report.RTObjects[i]) then
|
|
|
|
|
|
+ result := -1;
|
|
|
|
+ if AID<0 then
|
|
|
|
+ exit;
|
|
|
|
+ for i := 0 to Count-1 do
|
|
begin
|
|
begin
|
|
- lRTPage := TFPReportCustomPage(Page.Report.RTObjects[i]);
|
|
|
|
- Page.Report.FRTCurBand := TFPReportBandClass(ClassType).Create(lRTPage);
|
|
|
|
- Page.Report.FRTCurBand.Assign(self);
|
|
|
|
- Page.Report.FRTCurBand.CreateRTLayout;
|
|
|
|
|
|
+ if Images[i].ID = AID then
|
|
|
|
+ begin
|
|
|
|
+ Result := i;
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
- inherited PrepareObjects;
|
|
|
|
|
|
+end;
|
|
|
|
|
|
- if self is TFPReportGroupHeaderBand then
|
|
|
|
- TFPReportGroupHeaderBand(Page.Report.FRTCurBand).CalcGroupConditionValue;
|
|
|
|
|
|
+function TFPReportImages.GetImageFromID(const AID: integer): TFPCustomImage;
|
|
|
|
|
|
- if Assigned(FChildren) then
|
|
|
|
- begin
|
|
|
|
- for c := 0 to Page.Report.FRTCurBand.ChildCount-1 do
|
|
|
|
- begin
|
|
|
|
- if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomMemo then
|
|
|
|
- begin
|
|
|
|
- m := TFPReportMemo(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
- if moDisableExpressions in m.Options then
|
|
|
|
- Continue; // nothing further to do
|
|
|
|
- m.ExpandExpressions;
|
|
|
|
- // visibility handling
|
|
|
|
- if moHideZeros in m.Options then
|
|
|
|
- begin
|
|
|
|
- if IsStringValueZero(m.Text) then
|
|
|
|
- begin
|
|
|
|
- m.Visible := False;
|
|
|
|
- Continue;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- if moSuppressRepeated in m.Options then
|
|
|
|
- begin
|
|
|
|
- if m.Original.FLastText = m.Text then
|
|
|
|
- begin
|
|
|
|
- m.Visible := False;
|
|
|
|
- Continue;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- m.Original.FLastText := m.Text;
|
|
|
|
- end;
|
|
|
|
- // aggregate handling
|
|
|
|
- for nIdx := 0 to Length(m.Original.ExpressionNodes)-1 do
|
|
|
|
- begin
|
|
|
|
- n := m.Original.ExpressionNodes[nIdx].ExprNode;
|
|
|
|
- if not Assigned(n) then
|
|
|
|
- Continue;
|
|
|
|
- if n.HasAggregate then
|
|
|
|
- begin
|
|
|
|
- if moNoResetAggregateOnPrint in m.Options then
|
|
|
|
- begin
|
|
|
|
- // do nothing
|
|
|
|
- end
|
|
|
|
- // apply memo.Options rules if applicable
|
|
|
|
- else if ((self is TFPReportCustomPageHeaderBand) and (moResetAggregateOnPage in m.Options))
|
|
|
|
- or ((self is TFPReportCustomColumnHeaderBand) and (moResetAggregateOnColumn in m.Options))
|
|
|
|
- or ((self is TFPReportCustomGroupHeaderBand) and (moResetAggregateOnGroup in m.Options)) then
|
|
|
|
- n.InitAggregate
|
|
|
|
- // apply Page/Column/Group/Data footer rule
|
|
|
|
- else if (self is TFPReportCustomPageFooterBand)
|
|
|
|
- or (self is TFPReportCustomColumnFooterBand)
|
|
|
|
- or (self is TFPReportCustomGroupFooterBand)
|
|
|
|
- or (self is TFPReportCustomDataFooterBand) then
|
|
|
|
- n.InitAggregate
|
|
|
|
- else
|
|
|
|
- // default rule - reset on print. applies to all memos
|
|
|
|
- n.InitAggregate;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end
|
|
|
|
- else if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomCheckbox then
|
|
|
|
- begin
|
|
|
|
- cb := TFPReportCheckbox(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
- s := ExpandMacro(cb.Expression, True);
|
|
|
|
- cb.FTestResult := StrToBoolDef(s, False);
|
|
|
|
- end
|
|
|
|
- else if TFPReportElement(Page.Report.FRTCurBand.Child[c]) is TFPReportCustomImage then
|
|
|
|
- begin
|
|
|
|
- img := TFPReportCustomImage(Page.Report.FRTCurBand.Child[c]);
|
|
|
|
- if (img.FieldName <> '') and Assigned(GetData) then
|
|
|
|
- img.LoadDBData(GetData);
|
|
|
|
- end;
|
|
|
|
- end; { for c := 0 to ... }
|
|
|
|
- end; { if Assigned(FChildren) ... }
|
|
|
|
|
|
+Var
|
|
|
|
+ II : TFPReportImageItem;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ II:=GetImageItemFromID(AID);
|
|
|
|
+ if II<>Nil then
|
|
|
|
+ Result:=II.Image
|
|
|
|
+ else
|
|
|
|
+ Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.RecalcLayout;
|
|
|
|
|
|
+function TFPReportImages.GetImageItemFromID(const AID: integer): TFPReportImageItem;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
begin
|
|
begin
|
|
- inherited RecalcLayout;
|
|
|
|
- if StretchMode <> smDontStretch then
|
|
|
|
- ApplyStretchMode;
|
|
|
|
|
|
+ I:=GetIndexFromID(AID);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Result:=Images[I]
|
|
|
|
+ else
|
|
|
|
+ Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.Assign(Source: TPersistent);
|
|
|
|
|
|
+{ TFPReportPageSize }
|
|
|
|
+
|
|
|
|
+procedure TFPReportPageSize.SetHeight(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FHeight = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FHeight := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportPageSize.CheckPaperSize;
|
|
var
|
|
var
|
|
- E: TFPReportCustomBand;
|
|
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- inherited Assign(Source);
|
|
|
|
- if Source is TFPReportCustomBand then
|
|
|
|
|
|
+ I := PaperManager.IndexOfPaper(FPaperName);
|
|
|
|
+ if (I <> -1) then
|
|
begin
|
|
begin
|
|
- E := TFPReportCustomBand(Source);
|
|
|
|
- FChildBand := E.ChildBand;
|
|
|
|
- FStretchMode := E.StretchMode;
|
|
|
|
- FVisibleOnPage := E.VisibleOnPage;
|
|
|
|
- UseParentFont := E.UseParentFont;
|
|
|
|
- if not UseParentFont then
|
|
|
|
- Font.Assign(E.Font);
|
|
|
|
|
|
+ FWidth := PaperManager.PaperWidth[I];
|
|
|
|
+ FHeight := PaperManager.PaperHeight[I];
|
|
|
|
+ Changed;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportCustomBand.ReportBandType: TFPReportBandType;
|
|
|
|
|
|
+procedure TFPReportPageSize.SetPaperName(const AValue: string);
|
|
begin
|
|
begin
|
|
- Result:=btUnknown;
|
|
|
|
|
|
+ if FPaperName = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FPaperName := AValue;
|
|
|
|
+ if (FPaperName <> '') then
|
|
|
|
+ CheckPaperSize;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.BeforePrint;
|
|
|
|
|
|
+procedure TFPReportPageSize.SetWidth(const AValue: TFPReportUnits);
|
|
|
|
+begin
|
|
|
|
+ if FWidth = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ FWidth := AValue;
|
|
|
|
+ Changed;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportPageSize.Changed;
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FPage) then
|
|
|
|
+ FPage.PageSizeChanged;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TFPReportPageSize.Create(APage: TFPReportCustomPage);
|
|
|
|
+begin
|
|
|
|
+ FPage := APage;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportPageSize.Assign(Source: TPersistent);
|
|
var
|
|
var
|
|
- i: integer;
|
|
|
|
- c: TFPReportElement;
|
|
|
|
|
|
+ S: TFPReportPageSize;
|
|
begin
|
|
begin
|
|
- inherited BeforePrint;
|
|
|
|
- if Visible = false then
|
|
|
|
- exit;
|
|
|
|
- if Assigned(FChildren) then
|
|
|
|
|
|
+ if Source is TFPReportPageSize then
|
|
begin
|
|
begin
|
|
- for i := 0 to FChildren.Count-1 do
|
|
|
|
- begin
|
|
|
|
- c := Child[i];
|
|
|
|
- c.BeforePrint;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
|
|
+ S := Source as TFPReportPageSize;
|
|
|
|
+ FPaperName := S.FPaperName;
|
|
|
|
+ FWidth := S.FWidth;
|
|
|
|
+ FHeight := S.FHeight;
|
|
|
|
+ Changed;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited Assign(Source);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.DoWriteLocalProperties(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
|
|
|
|
+{ TFPReportExporter }
|
|
|
|
+
|
|
|
|
+procedure TFPReportExporter.SetFPReport(AValue: TFPCustomReport);
|
|
begin
|
|
begin
|
|
- inherited DoWriteLocalProperties(AWriter, AOriginal);
|
|
|
|
- AWriter.WriteBoolean('UseParentFont', UseParentFont);
|
|
|
|
- if not UseParentFont then
|
|
|
|
- begin
|
|
|
|
- AWriter.WriteString('FontName', Font.Name);
|
|
|
|
- AWriter.WriteInteger('FontSize', Font.Size);
|
|
|
|
- AWriter.WriteInteger('FontColor', Font.Color);
|
|
|
|
- end;
|
|
|
|
|
|
+ if FPReport = AValue then
|
|
|
|
+ Exit;
|
|
|
|
+ if Assigned(FPReport) then
|
|
|
|
+ FPReport.RemoveFreeNotification(Self);
|
|
|
|
+ FPReport := AValue;
|
|
|
|
+ if Assigned(FPReport) then
|
|
|
|
+ FPReport.FreeNotification(Self);
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportCustomBand.Create(AOwner: TComponent);
|
|
|
|
|
|
+procedure TFPReportExporter.SetBaseFileName(AValue: string);
|
|
begin
|
|
begin
|
|
- inherited Create(AOwner);
|
|
|
|
- FVisibleOnPage := vpAll;
|
|
|
|
- FUseParentFont := True;
|
|
|
|
- FFont := nil
|
|
|
|
|
|
+ if FBaseFileName=AValue then Exit;
|
|
|
|
+ FBaseFileName:=AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPReportCustomBand.Destroy;
|
|
|
|
|
|
+procedure TFPReportExporter.Notification(AComponent: TComponent;
|
|
|
|
+ Operation: TOperation);
|
|
begin
|
|
begin
|
|
- FreeAndNil(FFont);
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
|
|
+ if (Operation=opRemove) and (AComponent=FPReport) then
|
|
|
|
+ FPReport:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.WriteElement(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
|
|
|
|
+procedure TFPReportExporter.RenderImage(aPos: TFPReportRect; var AImage: TFPCustomImage);
|
|
begin
|
|
begin
|
|
- AWriter.PushElement(GetReportBandName);
|
|
|
|
- try
|
|
|
|
- inherited WriteElement(AWriter, AOriginal);
|
|
|
|
- if Assigned(ChildBand) then
|
|
|
|
- AWriter.WriteString('ChildBand', ChildBand.Name);
|
|
|
|
- if Assigned(GetData) then
|
|
|
|
- AWriter.WriteString('Data', GetData.Name);
|
|
|
|
- AWriter.WriteString('VisibleOnPage', VisibleOnPageToString(FVisibleOnPage));
|
|
|
|
- finally
|
|
|
|
- AWriter.PopElement;
|
|
|
|
|
|
+ // Do nothing
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+TYpe
|
|
|
|
+
|
|
|
|
+ { TMyFPCompactImgRGBA8Bit }
|
|
|
|
+
|
|
|
|
+ TMyFPCompactImgRGBA8Bit = Class(TFPCompactImgRGBA8Bit)
|
|
|
|
+ procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
end;
|
|
end;
|
|
|
|
+
|
|
|
|
+{ TMyFPCompactImgRGBA8Bit }
|
|
|
|
+
|
|
|
|
+procedure TMyFPCompactImgRGBA8Bit.SetInternalColor(x, y: integer; const Value: TFPColor);
|
|
|
|
+begin
|
|
|
|
+ if (X<0) or (Y<0) or (X>=Width) or (Y>=Height) then
|
|
|
|
+ Writeln('(',X,',',Y,') not in (0,0)x(',Width-1,',',Height-1,')')
|
|
|
|
+ else
|
|
|
|
+ inherited SetInternalColor(x, y, Value);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBand.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
-var
|
|
|
|
- E: TObject;
|
|
|
|
- s: string;
|
|
|
|
|
|
+procedure TFPReportExporter.RenderUnknownElement(aBasePos: TFPReportPoint;
|
|
|
|
+ AElement: TFPReportElement; ADPI: Integer);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ C : TFPReportElementExporterCallBack;
|
|
|
|
+ IC : TFPReportImageRenderCallBack;
|
|
|
|
+ Img : TFPCustomImage;
|
|
|
|
+ H,W : Integer;
|
|
|
|
+ R : TFPReportRect;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- E := AReader.FindChild(GetReportBandName);
|
|
|
|
- if Assigned(E) then
|
|
|
|
- begin
|
|
|
|
- AReader.PushElement(E);
|
|
|
|
- try
|
|
|
|
- inherited ReadElement(AReader);
|
|
|
|
- s := AReader.ReadString('ChildBand', '');
|
|
|
|
- if s <> '' then
|
|
|
|
- Page.Report.AddReference(self.Name, s);
|
|
|
|
-// Page.Report.AddReference(self, 'ChildBand', s);
|
|
|
|
- FVisibleOnPage := StringToVisibleOnPage(AReader.ReadString('VisibleOnPage', 'vpAll'));
|
|
|
|
- FUseParentFont := AReader.ReadBoolean('UseParentFont', UseParentFont);
|
|
|
|
- if not FUseParentFont then
|
|
|
|
|
|
+ // Actually, this could be cached using propertyhash...
|
|
|
|
+ C:=gElementFactory.FindRenderer(TFPReportExporterClass(self.ClassType),TFPReportElementClass(aElement.ClassType));
|
|
|
|
+ if (C<>Nil) then
|
|
|
|
+ // There is a direct renderer
|
|
|
|
+ C(aBasePos, aElement,Self,aDPI)
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ // There is no direct renderer, try rendering to image
|
|
|
|
+ IC:=gElementFactory.FindImageRenderer(TFPReportElementClass(aElement.ClassType));
|
|
|
|
+ if Assigned(IC) then
|
|
begin
|
|
begin
|
|
- Font.Name := AReader.ReadString('FontName', Font.Name);
|
|
|
|
- Font.Size := AReader.ReadInteger('FontSize', Font.Size);
|
|
|
|
- Font.Color := AReader.ReadInteger('FontColor', Font.Color);
|
|
|
|
|
|
+ H := Round(aElement.RTLayout.Height * (aDPI / cMMperInch));
|
|
|
|
+ W := Round(aElement.RTLayout.Width * (aDPI / cMMperInch));
|
|
|
|
+ Img:=TFPCompactImgRGBA8Bit.Create(W,H);
|
|
|
|
+ try
|
|
|
|
+ IC(aElement,Img);
|
|
|
|
+ R.Left:=aBasePos.Left+AElement.RTLayout.Left;
|
|
|
|
+ R.Top:=aBasePos.Top+AElement.RTLayout.Top;
|
|
|
|
+ R.Width:=AElement.RTLayout.Width;
|
|
|
|
+ R.Height:=AElement.RTLayout.Height;
|
|
|
|
+ RenderImage(R,Img);
|
|
|
|
+ finally
|
|
|
|
+ Img.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
-
|
|
|
|
- // TODO: Read Data information
|
|
|
|
- S:=AReader.ReadString('Data','');
|
|
|
|
- if (S<>'') then
|
|
|
|
- SetDataFromName(S);
|
|
|
|
- finally
|
|
|
|
- AReader.PopElement;
|
|
|
|
end;
|
|
end;
|
|
- end;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportCustomBandWithData }
|
|
|
|
|
|
|
|
-procedure TFPReportCustomBandWithData.SetData(const AValue: TFPReportData);
|
|
|
|
|
|
+class function TFPReportExporter.DefaultConfig: TFPReportExporterConfigHandler;
|
|
begin
|
|
begin
|
|
- if FData = AValue then
|
|
|
|
- Exit;
|
|
|
|
- if Assigned(FData) then
|
|
|
|
- FData.RemoveFreeNotification(Self);
|
|
|
|
- FData := AValue;
|
|
|
|
- if Assigned(FData) then
|
|
|
|
- FData.FreeNotification(Self);
|
|
|
|
|
|
+ Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBandWithData.SaveDataToNames;
|
|
|
|
|
|
+procedure TFPReportExporter.Execute;
|
|
begin
|
|
begin
|
|
- inherited SaveDataToNames;
|
|
|
|
- if Assigned(FData) then
|
|
|
|
- FDataName:=FData.Name
|
|
|
|
- else
|
|
|
|
- FDataName:='';
|
|
|
|
|
|
+ if (FPReport.RTObjects.Count=0) and AutoRun then
|
|
|
|
+ FPreport.RunReport;
|
|
|
|
+ if FPReport.RTObjects.Count > 0 then
|
|
|
|
+ DoExecute(FPReport.RTObjects);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TFPReportExporter.SetFileName(const aFileName: String);
|
|
|
|
+begin
|
|
|
|
+ // Do nothing
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class procedure TFPReportExporter.RegisterExporter;
|
|
|
|
+begin
|
|
|
|
+ ReportExportManager.RegisterExport(Self);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBandWithData.ResolveDataName;
|
|
|
|
-
|
|
|
|
|
|
+class procedure TFPReportExporter.UnRegisterExporter;
|
|
begin
|
|
begin
|
|
- if (FDataName<>'') then
|
|
|
|
- Data:=Report.ReportData.FindReportData(FDataName)
|
|
|
|
- else
|
|
|
|
- Data:=Nil;
|
|
|
|
|
|
+ ReportExportManager.UnRegisterExport(Self);
|
|
end;
|
|
end;
|
|
-procedure TFPReportCustomBandWithData.RestoreDataFromNames;
|
|
|
|
|
|
|
|
|
|
+class function TFPReportExporter.Description: String;
|
|
begin
|
|
begin
|
|
- inherited RestoreDataFromNames;
|
|
|
|
- ResolveDataName;
|
|
|
|
|
|
+ Result:='';
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomBandWithData.GetData: TFPReportData;
|
|
|
|
|
|
+class function TFPReportExporter.Name: String;
|
|
begin
|
|
begin
|
|
- Result := FData;
|
|
|
|
|
|
+ Result:=ClassName;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBandWithData.SetDataFromName(AName: String);
|
|
|
|
|
|
+class function TFPReportExporter.DefaultExtension: String;
|
|
begin
|
|
begin
|
|
- FDataName:=AName;
|
|
|
|
- ResolveDataName;
|
|
|
|
|
|
+ Result:='';
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomBandWithData.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
|
|
|
+class function TFPReportExporter.MultiFile: Boolean;
|
|
begin
|
|
begin
|
|
- if Operation = opRemove then
|
|
|
|
- begin
|
|
|
|
- if AComponent = FData then
|
|
|
|
- FData := nil;
|
|
|
|
- end;
|
|
|
|
- inherited Notification(AComponent, Operation);
|
|
|
|
|
|
+ Result:=False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportCustomBandWithData.Create(AOwner: TComponent);
|
|
|
|
|
|
+function TFPReportExporter.ShowConfig: Boolean;
|
|
begin
|
|
begin
|
|
- FData := nil;
|
|
|
|
- inherited Create(AOwner);
|
|
|
|
|
|
+ Result:=ReportExportManager.ConfigExporter(Self);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportCustomGroupFooterBand }
|
|
|
|
|
|
+{ TFPReportPaperSize }
|
|
|
|
|
|
-procedure TFPReportCustomGroupFooterBand.SetGroupHeader(const AValue: TFPReportCustomGroupHeaderBand);
|
|
|
|
|
|
+constructor TFPReportPaperSize.Create(const AWidth, AHeight: TFPReportUnits);
|
|
begin
|
|
begin
|
|
- if FGroupHeader = AValue then
|
|
|
|
- Exit;
|
|
|
|
- if Assigned(FGroupHeader) then
|
|
|
|
- begin
|
|
|
|
- FGroupHeader.FGroupFooter := nil;
|
|
|
|
- FGroupHeader.RemoveFreeNotification(Self);
|
|
|
|
- end;
|
|
|
|
- FGroupHeader := AValue;
|
|
|
|
- if Assigned(FGroupHeader) then
|
|
|
|
- begin
|
|
|
|
- FGroupHeader.FGroupFooter := Self;
|
|
|
|
- FGroupHeader.FreeNotification(Self);
|
|
|
|
- end;
|
|
|
|
|
|
+ FWidth := AWidth;
|
|
|
|
+ FHeight := AHeight;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportCustomGroupFooterBand.GetReportBandName: string;
|
|
|
|
|
|
+{ TFPReportFont }
|
|
|
|
+
|
|
|
|
+procedure TFPReportFont.SetFontName(const avalue: string);
|
|
begin
|
|
begin
|
|
- Result := 'GroupFooterBand';
|
|
|
|
|
|
+ FFontName := AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomGroupFooterBand.DoWriteLocalProperties(AWriter: TFPReportStreamer; AOriginal: TFPReportElement);
|
|
|
|
|
|
+procedure TFPReportFont.SetFontSize(const avalue: integer);
|
|
begin
|
|
begin
|
|
- inherited DoWriteLocalProperties(AWriter, AOriginal);
|
|
|
|
- if Assigned(GroupHeader) then
|
|
|
|
- AWriter.WriteString('GroupHeader', GroupHeader.Name);
|
|
|
|
|
|
+ FFontSize := AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomGroupFooterBand.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
|
|
|
+procedure TFPReportFont.SetFontColor(const avalue: TFPReportColor);
|
|
begin
|
|
begin
|
|
- if (Operation = opRemove) and (AComponent = FGroupHeader) then
|
|
|
|
- FGroupHeader := nil;
|
|
|
|
- inherited Notification(AComponent, Operation);
|
|
|
|
|
|
+ FFontColor := AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportCustomGroupFooterBand.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
-var
|
|
|
|
- s: string;
|
|
|
|
-// c: TFPReportElement;
|
|
|
|
|
|
+constructor TFPReportFont.Create;
|
|
begin
|
|
begin
|
|
-// c := nil;
|
|
|
|
- inherited ReadElement(AReader);
|
|
|
|
- s := AReader.ReadString('GroupHeader', '');
|
|
|
|
- if s = '' then
|
|
|
|
- Exit;
|
|
|
|
- // TODO: recursively search Page.Report for the GroupHeader
|
|
|
|
- //c := Page.Report.FindComponent(s);
|
|
|
|
- //if Assigned(c) then
|
|
|
|
- // FGroupHeader := TFPReportCustomGroupHeaderBand(c);
|
|
|
|
|
|
+ inherited Create;
|
|
|
|
+ FFontName := cDefaultFont;
|
|
|
|
+ FFontColor := clBlack;
|
|
|
|
+ FFontSize := 10;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportCustomGroupFooterBand.ReportBandType: TFPReportBandType;
|
|
|
|
|
|
+procedure TFPReportFont.Assign(Source: TPersistent);
|
|
|
|
+var
|
|
|
|
+ o: TFPReportFont;
|
|
begin
|
|
begin
|
|
- Result:=btGroupFooter;
|
|
|
|
|
|
+ //inherited Assign(Source);
|
|
|
|
+ if (Source = nil) or not (Source is TFPReportFont) then
|
|
|
|
+ ReportError(SErrCantAssignReportFont);
|
|
|
|
+ o := TFPReportFont(Source);
|
|
|
|
+ FFontName := o.Name;
|
|
|
|
+ FFontSize := o.Size;
|
|
|
|
+ FFontColor := o.Color;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+{ TFPReportPaperManager }
|
|
|
|
|
|
-{ TFPReportImageItem }
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperHeight(AIndex: integer): TFPReportUnits;
|
|
|
|
+begin
|
|
|
|
+ Result := TFPReportPaperSize(FPaperSizes.Objects[AIndex]).Height;
|
|
|
|
+end;
|
|
|
|
|
|
-function TFPReportImageItem.GetHeight: Integer;
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperHeightByName(AName: string): TFPReportUnits;
|
|
begin
|
|
begin
|
|
- If Assigned(FImage) then
|
|
|
|
- Result:=FImage.Height
|
|
|
|
- else
|
|
|
|
- Result:=FHeight;
|
|
|
|
|
|
+ Result := GetPaperByName(AName).Height;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImageItem.GetStreamed: TBytes;
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperCount: integer;
|
|
begin
|
|
begin
|
|
- if Length(FStreamed)=0 then
|
|
|
|
- CreateStreamedData;
|
|
|
|
- Result:=FStreamed;
|
|
|
|
|
|
+ Result := FPaperSizes.Count;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImageItem.GetWidth: Integer;
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperName(AIndex: integer): string;
|
|
begin
|
|
begin
|
|
- If Assigned(FImage) then
|
|
|
|
- Result:=FImage.Width
|
|
|
|
- else
|
|
|
|
- Result:=FWidth;
|
|
|
|
|
|
+ Result := FPaperSizes[AIndex];
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.SetImage(AValue: TFPCustomImage);
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperWidth(AIndex: integer): TFPReportUnits;
|
|
begin
|
|
begin
|
|
- if FImage=AValue then Exit;
|
|
|
|
- FImage:=AValue;
|
|
|
|
- SetLength(FStreamed,0);
|
|
|
|
|
|
+ Result := TFPReportPaperSize(FPaperSizes.Objects[AIndex]).Width;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.SetStreamed(AValue: TBytes);
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperWidthByName(AName: string): TFPReportUnits;
|
|
begin
|
|
begin
|
|
- If AValue=FStreamed then exit;
|
|
|
|
- SetLength(FStreamed,0);
|
|
|
|
- FStreamed:=AValue;
|
|
|
|
|
|
+ Result := GetPaperByName(AName).Width;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.LoadPNGFromStream(AStream: TStream);
|
|
|
|
|
|
+function TFPReportPaperManager.FindPaper(const AName: string): TFPReportPaperSize;
|
|
var
|
|
var
|
|
- PNGReader: TFPReaderPNG;
|
|
|
|
|
|
+ I: integer;
|
|
begin
|
|
begin
|
|
- if not Assigned(AStream) then
|
|
|
|
- Exit;
|
|
|
|
-
|
|
|
|
- { we use Image property here so it frees any previous image }
|
|
|
|
- if Assigned(FImage) then
|
|
|
|
- FreeAndNil(FImage);
|
|
|
|
- FImage := TFPCompactImgRGBA8Bit.Create(0, 0);
|
|
|
|
- try
|
|
|
|
- PNGReader := TFPReaderPNG.Create;
|
|
|
|
- try
|
|
|
|
- FImage.LoadFromStream(AStream, PNGReader); // auto size image
|
|
|
|
- finally
|
|
|
|
- PNGReader.Free;
|
|
|
|
- end;
|
|
|
|
- except
|
|
|
|
- FreeAndNil(FImage);
|
|
|
|
- end;
|
|
|
|
|
|
+ I := IndexOfPaper(AName);
|
|
|
|
+ if (I = -1) then
|
|
|
|
+ Result := nil
|
|
|
|
+ else
|
|
|
|
+ Result := TFPReportPaperSize(FPaperSizes.Objects[i]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportImageItem.Create(ACollection: TCollection);
|
|
|
|
|
|
+function TFPReportPaperManager.GetPaperByname(const AName: string): TFPReportPaperSize;
|
|
begin
|
|
begin
|
|
- inherited Create(ACollection);
|
|
|
|
- FOwnsImage := True;
|
|
|
|
|
|
+ Result := FindPaper(AName);
|
|
|
|
+ if Result = nil then
|
|
|
|
+ ReportError(SErrUnknownPaper, [AName]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPReportImageItem.Destroy;
|
|
|
|
|
|
+constructor TFPReportPaperManager.Create(AOwner: TComponent);
|
|
begin
|
|
begin
|
|
- if FOwnsImage then
|
|
|
|
- FreeAndNil(FImage);
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FPaperSizes := TStringList.Create;
|
|
|
|
+ FPaperSizes.Sorted := True;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.CreateStreamedData;
|
|
|
|
-Var
|
|
|
|
- X, Y: Integer;
|
|
|
|
- C: TFPColor;
|
|
|
|
- MS: TMemoryStream;
|
|
|
|
- Str: TStream;
|
|
|
|
- CWhite: TFPColor; // white color
|
|
|
|
|
|
+destructor TFPReportPaperManager.Destroy;
|
|
|
|
+var
|
|
|
|
+ I: integer;
|
|
begin
|
|
begin
|
|
- FillMem(@CWhite, SizeOf(CWhite), $FF);
|
|
|
|
- FWidth:=Image.Width;
|
|
|
|
- FHeight:=Image.Height;
|
|
|
|
- Str := nil;
|
|
|
|
- MS := TMemoryStream.Create;
|
|
|
|
- try
|
|
|
|
- Str := MS;
|
|
|
|
- for Y:=0 to FHeight-1 do
|
|
|
|
- for X:=0 to FWidth-1 do
|
|
|
|
- begin
|
|
|
|
- C:=Image.Colors[x,y];
|
|
|
|
- if C.alpha < $FFFF then // remove alpha channel - assume white background
|
|
|
|
- C := AlphaBlend(CWhite, C);
|
|
|
|
-
|
|
|
|
- Str.WriteByte(C.Red shr 8);
|
|
|
|
- Str.WriteByte(C.Green shr 8);
|
|
|
|
- Str.WriteByte(C.blue shr 8);
|
|
|
|
- end;
|
|
|
|
- if Str<>MS then
|
|
|
|
- Str.Free;
|
|
|
|
- Str := nil;
|
|
|
|
- SetLength(FStreamed, MS.Size);
|
|
|
|
- MS.Position := 0;
|
|
|
|
- if MS.Size>0 then
|
|
|
|
- MS.ReadBuffer(FStreamed[0], MS.Size);
|
|
|
|
- finally
|
|
|
|
- Str.Free;
|
|
|
|
- MS.Free;
|
|
|
|
|
|
+ if Assigned(FPaperSizes) then
|
|
|
|
+ begin
|
|
|
|
+ for I := 0 to FPaperSizes.Count - 1 do
|
|
|
|
+ FPaperSizes.Objects[i].Free;
|
|
|
|
+ FreeAndNil(FPaperSizes);
|
|
end;
|
|
end;
|
|
|
|
+ inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImageItem.WriteImageStream(AStream: TStream): UInt64;
|
|
|
|
|
|
+procedure TFPReportPaperManager.Clear;
|
|
var
|
|
var
|
|
- Img: TBytes;
|
|
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- Img := StreamedData;
|
|
|
|
- Result := Length(Img);
|
|
|
|
- AStream.WriteBuffer(Img[0],Result);
|
|
|
|
|
|
+ for i := 0 to FPaperSizes.Count-1 do
|
|
|
|
+ if Assigned(FPaperSizes.Objects[i]) then
|
|
|
|
+ FPaperSizes.Objects[i].Free;
|
|
|
|
+ FPaperSizes.Clear;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImageItem.Equals(AImage: TFPCustomImage): boolean;
|
|
|
|
-var
|
|
|
|
- x, y: Integer;
|
|
|
|
|
|
+function TFPReportPaperManager.IndexOfPaper(const AName: string): integer;
|
|
begin
|
|
begin
|
|
- Result := True;
|
|
|
|
- for x := 0 to Image.Width-1 do
|
|
|
|
- for y := 0 to Image.Height-1 do
|
|
|
|
- if Image.Pixels[x, y] <> AImage.Pixels[x, y] then
|
|
|
|
- begin
|
|
|
|
- Result := False;
|
|
|
|
- Exit;
|
|
|
|
- end;
|
|
|
|
|
|
+ if not Assigned(FPaperSizes) then
|
|
|
|
+ Result := -1
|
|
|
|
+ else
|
|
|
|
+ Result := FPaperSizes.IndexOf(AName);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.WriteElement(AWriter: TFPReportStreamer);
|
|
|
|
|
|
+procedure TFPReportPaperManager.RegisterPaper(const AName: string; const AWidth, AHeight: TFPReportUnits);
|
|
var
|
|
var
|
|
- ms: TMemoryStream;
|
|
|
|
- png: TFPWriterPNG;
|
|
|
|
|
|
+ I: integer;
|
|
|
|
+ S: TFPReportPaperSize;
|
|
begin
|
|
begin
|
|
- if Assigned(Image) then
|
|
|
|
|
|
+ I := FPaperSizes.IndexOf(AName);
|
|
|
|
+ if (I = -1) then
|
|
begin
|
|
begin
|
|
- ms := TMemoryStream.Create;
|
|
|
|
- try
|
|
|
|
- png := TFPWriterPNG.create;
|
|
|
|
- png.Indexed := False;
|
|
|
|
- Image.SaveToStream(ms, png);
|
|
|
|
- ms.Position := 0;
|
|
|
|
- AWriter.WriteStream('ImageData', ms);
|
|
|
|
- finally
|
|
|
|
- png.Free;
|
|
|
|
- ms.Free;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
|
|
+ S := TFPReportPaperSize.Create(AWidth, AHeight);
|
|
|
|
+ FPaperSizes.AddObject(AName, S);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ ReportError(SErrDuplicatePaperName, [AName]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportImageItem.ReadElement(AReader: TFPReportStreamer);
|
|
|
|
-var
|
|
|
|
- ms: TMemoryStream;
|
|
|
|
|
|
+{ Got details from Wikipedia [https://simple.wikipedia.org/wiki/Paper_size] }
|
|
|
|
+procedure TFPReportPaperManager.RegisterStandardSizes;
|
|
begin
|
|
begin
|
|
- ms := TMemoryStream.Create;
|
|
|
|
- try
|
|
|
|
- if AReader.ReadStream('ImageData', ms) then
|
|
|
|
- begin
|
|
|
|
- ms.Position := 0;
|
|
|
|
- LoadPNGFromStream(ms);
|
|
|
|
- end;
|
|
|
|
- finally
|
|
|
|
- ms.Free;
|
|
|
|
- end;
|
|
|
|
|
|
+ // As per TFPReportUnits, size is specified in millimetres.
|
|
|
|
+ RegisterPaper('A3', 297, 420);
|
|
|
|
+ RegisterPaper('A4', 210, 297);
|
|
|
|
+ RegisterPaper('A5', 148, 210);
|
|
|
|
+ RegisterPaper('Letter', 216, 279);
|
|
|
|
+ RegisterPaper('Legal', 216, 356);
|
|
|
|
+ RegisterPaper('Ledger', 279, 432);
|
|
|
|
+ RegisterPaper('DL', 220, 110);
|
|
|
|
+ RegisterPaper('B5', 176, 250);
|
|
|
|
+ RegisterPaper('C5', 162, 229);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportImages }
|
|
|
|
-
|
|
|
|
-function TFPReportImages.GetImg(AIndex: Integer): TFPReportImageItem;
|
|
|
|
|
|
+procedure TFPReportPaperManager.GetRegisteredSizes(var AList: TStringList);
|
|
|
|
+var
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- Result := Items[AIndex] as TFPReportImageItem;
|
|
|
|
|
|
+ if not Assigned(AList) then
|
|
|
|
+ Exit;
|
|
|
|
+ AList.Clear;
|
|
|
|
+ for i := 0 to FPaperSizes.Count - 1 do
|
|
|
|
+ AList.Add(PaperNames[i]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.GetReportOwner: TFPCustomReport;
|
|
|
|
|
|
+procedure DoneReporting;
|
|
begin
|
|
begin
|
|
- Result:=Owner as TFPCustomReport;
|
|
|
|
|
|
+ if Assigned(uPaperManager) then
|
|
|
|
+ FreeAndNil(uPaperManager);
|
|
|
|
+ TFPReportCustomCheckbox.ImgFalse.Free;
|
|
|
|
+ TFPReportCustomCheckbox.ImgTrue.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+{ TFPTextBlockList }
|
|
|
|
|
|
-constructor TFPReportImages.Create(AOwner: TFPCustomReport; AItemClass: TCollectionItemClass);
|
|
|
|
|
|
+function TFPTextBlockList.GetItem(AIndex: Integer): TFPTextBlock;
|
|
begin
|
|
begin
|
|
- inherited Create(aOwner,AItemClass);
|
|
|
|
|
|
+ Result := TFPTextBlock(inherited GetItem(AIndex));
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.AddImageItem: TFPReportImageItem;
|
|
|
|
|
|
+procedure TFPTextBlockList.SetItem(AIndex: Integer; AObject: TFPTextBlock);
|
|
begin
|
|
begin
|
|
- Result := Add as TFPReportImageItem;
|
|
|
|
|
|
+ inherited SetItem(AIndex, AObject);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.AddFromStream(const AStream: TStream;
|
|
|
|
- Handler: TFPCustomImageReaderClass; KeepImage: Boolean): Integer;
|
|
|
|
-var
|
|
|
|
- I: TFPCustomImage;
|
|
|
|
- IP: TFPReportImageItem;
|
|
|
|
- Reader: TFPCustomImageReader;
|
|
|
|
|
|
+{ TFPReportDataField }
|
|
|
|
+
|
|
|
|
+function TFPReportDataField.GetValue: variant;
|
|
begin
|
|
begin
|
|
- IP := AddImageItem;
|
|
|
|
- I := TFPCompactImgRGBA8Bit.Create(0,0);
|
|
|
|
- Reader := Handler.Create;
|
|
|
|
- try
|
|
|
|
- I.LoadFromStream(AStream, Reader);
|
|
|
|
- finally
|
|
|
|
- Reader.Free;
|
|
|
|
- end;
|
|
|
|
- IP.Image := I;
|
|
|
|
- if Not KeepImage then
|
|
|
|
- begin
|
|
|
|
- IP.CreateStreamedData;
|
|
|
|
- IP.FImage := Nil; // not through property, that would clear the image
|
|
|
|
- I.Free;
|
|
|
|
- end;
|
|
|
|
- Result := Count-1;
|
|
|
|
|
|
+ Result := Null;
|
|
|
|
+ if Assigned(Collection) then
|
|
|
|
+ TFPReportDatafields(Collection).ReportData.DoGetValue(FieldName, Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.AddFromFile(const AFileName: string; KeepImage: Boolean): Integer;
|
|
|
|
-
|
|
|
|
- {$IF NOT (FPC_FULLVERSION >= 30101)}
|
|
|
|
- function FindReaderFromExtension(extension: String): TFPCustomImageReaderClass;
|
|
|
|
- var
|
|
|
|
- s: string;
|
|
|
|
- r: integer;
|
|
|
|
|
|
+procedure TFPReportDataField.Assign(Source: TPersistent);
|
|
|
|
+var
|
|
|
|
+ F: TFPReportDataField;
|
|
|
|
+begin
|
|
|
|
+ if Source is TFPReportDataField then
|
|
begin
|
|
begin
|
|
- extension := lowercase (extension);
|
|
|
|
- if (extension <> '') and (extension[1] = '.') then
|
|
|
|
- system.delete (extension,1,1);
|
|
|
|
- with ImageHandlers do
|
|
|
|
- begin
|
|
|
|
- r := count-1;
|
|
|
|
- s := extension + ';';
|
|
|
|
- while (r >= 0) do
|
|
|
|
- begin
|
|
|
|
- Result := ImageReader[TypeNames[r]];
|
|
|
|
- if (pos(s,{$if (FPC_FULLVERSION = 20604)}Extentions{$else}Extensions{$endif}[TypeNames[r]]+';') <> 0) then
|
|
|
|
- Exit;
|
|
|
|
- dec (r);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- Result := nil;
|
|
|
|
- end;
|
|
|
|
|
|
+ F := Source as TFPReportDataField;
|
|
|
|
+ FDisplayWidth := F.FDisplayWidth;
|
|
|
|
+ FFieldKind := F.FFieldKind;
|
|
|
|
+ FFieldName := F.FFieldName;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+end;
|
|
|
|
|
|
- function FindReaderFromFileName(const filename: String): TFPCustomImageReaderClass;
|
|
|
|
- begin
|
|
|
|
- Result := FindReaderFromExtension(ExtractFileExt(filename));
|
|
|
|
- end;
|
|
|
|
- {$ENDIF}
|
|
|
|
|
|
+{ TFPReportDataFields }
|
|
|
|
|
|
-var
|
|
|
|
- FS: TFileStream;
|
|
|
|
|
|
+function TFPReportDataFields.GetF(AIndex: integer): TFPReportDataField;
|
|
begin
|
|
begin
|
|
- FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
|
|
|
- try
|
|
|
|
- Result := AddFromStream(FS,
|
|
|
|
- {$IF (FPC_FULLVERSION >= 30101)}TFPCustomImage.{$ENDIF}FindReaderFromFileName(AFileName), KeepImage);
|
|
|
|
- finally
|
|
|
|
- FS.Free;
|
|
|
|
- end;
|
|
|
|
|
|
+ Result := TFPReportDataField(Items[AIndex]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.AddFromData(const AImageData: Pointer; const AImageDataSize: LongWord): integer;
|
|
|
|
-var
|
|
|
|
- s: TMemoryStream;
|
|
|
|
|
|
+procedure TFPReportDataFields.SetF(AIndex: integer; const AValue: TFPReportDataField);
|
|
begin
|
|
begin
|
|
- s := TMemoryStream.Create;
|
|
|
|
- try
|
|
|
|
- s.Write(AImageData^, AImageDataSize);
|
|
|
|
- s.Position := 0;
|
|
|
|
- Result := AddFromStream(s, TFPReaderPNG, True);
|
|
|
|
- finally
|
|
|
|
- s.Free;
|
|
|
|
- end;
|
|
|
|
|
|
+ Items[AIndex] := AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.GetIndexFromID(const AID: integer): integer;
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
|
|
+function TFPReportDataFields.AddField(AFieldName: string; AFieldKind: TFPReportFieldKind): TFPReportDataField;
|
|
begin
|
|
begin
|
|
- result := -1;
|
|
|
|
- if AID<0 then
|
|
|
|
- exit;
|
|
|
|
- for i := 0 to Count-1 do
|
|
|
|
- begin
|
|
|
|
- if Images[i].ID = AID then
|
|
|
|
- begin
|
|
|
|
- Result := i;
|
|
|
|
- Exit;
|
|
|
|
- end;
|
|
|
|
|
|
+ Result := Add as TFPReportDataField;
|
|
|
|
+ try
|
|
|
|
+ Result.FieldName := AFieldName;
|
|
|
|
+ Result.FieldKind := AFieldKind;
|
|
|
|
+ except
|
|
|
|
+ Result.Free;
|
|
|
|
+ raise;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.GetImageFromID(const AID: integer): TFPCustomImage;
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- II : TFPReportImageItem;
|
|
|
|
-
|
|
|
|
|
|
+function TFPReportDataFields.IndexOfField(const AFieldName: string): integer;
|
|
begin
|
|
begin
|
|
- II:=GetImageItemFromID(AID);
|
|
|
|
- if II<>Nil then
|
|
|
|
- Result:=II.Image
|
|
|
|
- else
|
|
|
|
- Result:=Nil;
|
|
|
|
|
|
+ Result := Count - 1;
|
|
|
|
+ while (Result >= 0) and (CompareText(AFieldName, GetF(Result).FieldName) <> 0) do
|
|
|
|
+ Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportImages.GetImageItemFromID(const AID: integer): TFPReportImageItem;
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+function TFPReportDataFields.FindField(const AFieldName: string): TFPReportDataField;
|
|
|
|
+var
|
|
|
|
+ I: integer;
|
|
begin
|
|
begin
|
|
- I:=GetIndexFromID(AID);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Result:=Images[I]
|
|
|
|
|
|
+ I := IndexOfField(AFieldName);
|
|
|
|
+ if (I = -1) then
|
|
|
|
+ Result := nil
|
|
else
|
|
else
|
|
- Result:=Nil;
|
|
|
|
|
|
+ Result := GetF(I);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportPageSize }
|
|
|
|
-
|
|
|
|
-procedure TFPReportPageSize.SetHeight(const AValue: TFPReportUnits);
|
|
|
|
|
|
+function TFPReportDataFields.FindField(const AFieldName: string; const AFieldKind: TFPReportFieldKind): TFPReportDataField;
|
|
|
|
+var
|
|
|
|
+ lIndex: integer;
|
|
begin
|
|
begin
|
|
- if FHeight = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FHeight := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ lIndex := Count - 1;
|
|
|
|
+ while (lIndex >= 0) and (not SameText(AFieldName, GetF(lIndex).FieldName)) and (GetF(lIndex).FieldKind <> AFieldKind) do
|
|
|
|
+ Dec(lIndex);
|
|
|
|
+
|
|
|
|
+ if (lIndex = -1) then
|
|
|
|
+ Result := nil
|
|
|
|
+ else
|
|
|
|
+ Result := GetF(lIndex);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPageSize.CheckPaperSize;
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
|
|
+function TFPReportDataFields.FieldByName(const AFieldName: string): TFPReportDataField;
|
|
begin
|
|
begin
|
|
- I := PaperManager.IndexOfPaper(FPaperName);
|
|
|
|
- if (I <> -1) then
|
|
|
|
|
|
+ Result := FindField(AFieldName);
|
|
|
|
+ if (Result = nil) then
|
|
begin
|
|
begin
|
|
- FWidth := PaperManager.PaperWidth[I];
|
|
|
|
- FHeight := PaperManager.PaperHeight[I];
|
|
|
|
- Changed;
|
|
|
|
|
|
+ if Assigned(ReportData) then
|
|
|
|
+ ReportError(SErrUnknownField, [ReportData.Name, AFieldName])
|
|
|
|
+ else
|
|
|
|
+ ReportError(SErrUnknownField, ['', AFieldName]);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPageSize.SetPaperName(const AValue: string);
|
|
|
|
|
|
+{ TFPReportData }
|
|
|
|
+
|
|
|
|
+procedure TFPReportData.SetDataFields(const AValue: TFPReportDataFields);
|
|
begin
|
|
begin
|
|
- if FPaperName = AValue then
|
|
|
|
|
|
+ if (FDataFields = AValue) then
|
|
Exit;
|
|
Exit;
|
|
- FPaperName := AValue;
|
|
|
|
- if (FPaperName <> '') then
|
|
|
|
- CheckPaperSize;
|
|
|
|
|
|
+ FDataFields.Assign(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPageSize.SetWidth(const AValue: TFPReportUnits);
|
|
|
|
|
|
+function TFPReportData.GetFieldCount: integer;
|
|
begin
|
|
begin
|
|
- if FWidth = AValue then
|
|
|
|
- Exit;
|
|
|
|
- FWidth := AValue;
|
|
|
|
- Changed;
|
|
|
|
|
|
+ Result := FDatafields.Count;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPageSize.Changed;
|
|
|
|
|
|
+function TFPReportData.GetFieldName(Index: integer): string;
|
|
begin
|
|
begin
|
|
- if Assigned(FPage) then
|
|
|
|
- FPage.PageSizeChanged;
|
|
|
|
|
|
+ Result := FDatafields[Index].FieldName;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportPageSize.Create(APage: TFPReportCustomPage);
|
|
|
|
|
|
+function TFPReportData.GetFieldType(AFieldName: string): TFPReportFieldKind;
|
|
begin
|
|
begin
|
|
- FPage := APage;
|
|
|
|
|
|
+ Result := FDatafields.FieldByName(AFieldName).FieldKind;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPageSize.Assign(Source: TPersistent);
|
|
|
|
-var
|
|
|
|
- S: TFPReportPageSize;
|
|
|
|
|
|
+function TFPReportData.GetFieldValue(AFieldName: string): variant;
|
|
begin
|
|
begin
|
|
- if Source is TFPReportPageSize then
|
|
|
|
- begin
|
|
|
|
- S := Source as TFPReportPageSize;
|
|
|
|
- FPaperName := S.FPaperName;
|
|
|
|
- FWidth := S.FWidth;
|
|
|
|
- FHeight := S.FHeight;
|
|
|
|
- Changed;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- inherited Assign(Source);
|
|
|
|
|
|
+ Result := varNull;
|
|
|
|
+ DoGetValue(AFieldName, Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportExporter }
|
|
|
|
|
|
+function TFPReportData.GetFieldWidth(AFieldName: string): integer;
|
|
|
|
+begin
|
|
|
|
+ Result := FDataFields.FieldByName(AFieldName).DisplayWidth;
|
|
|
|
+end;
|
|
|
|
|
|
-procedure TFPReportExporter.SetFPReport(AValue: TFPCustomReport);
|
|
|
|
|
|
+function TFPReportData.CreateDataFields: TFPReportDataFields;
|
|
begin
|
|
begin
|
|
- if FPReport = AValue then
|
|
|
|
- Exit;
|
|
|
|
- if Assigned(FPReport) then
|
|
|
|
- FPReport.RemoveFreeNotification(Self);
|
|
|
|
- FPReport := AValue;
|
|
|
|
- if Assigned(FPReport) then
|
|
|
|
- FPReport.FreeNotification(Self);
|
|
|
|
|
|
+ Result := TFPReportDataFields.Create(TFPReportDataField);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.SetBaseFileName(AValue: string);
|
|
|
|
|
|
+procedure TFPReportData.DoGetValue(const AFieldName: string; var AValue: variant);
|
|
begin
|
|
begin
|
|
- if FBaseFileName=AValue then Exit;
|
|
|
|
- FBaseFileName:=AValue;
|
|
|
|
|
|
+ AValue := Null;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.Notification(AComponent: TComponent;
|
|
|
|
- Operation: TOperation);
|
|
|
|
|
|
+procedure TFPReportData.DoInitDataFields;
|
|
begin
|
|
begin
|
|
- inherited Notification(AComponent, Operation);
|
|
|
|
- if (Operation=opRemove) and (AComponent=FPReport) then
|
|
|
|
- FPReport:=Nil;
|
|
|
|
|
|
+ // Do nothing.
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.RenderImage(aPos: TFPReportRect; var AImage: TFPCustomImage);
|
|
|
|
|
|
+procedure TFPReportData.DoOpen;
|
|
begin
|
|
begin
|
|
// Do nothing
|
|
// Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-TYpe
|
|
|
|
-
|
|
|
|
- { TMyFPCompactImgRGBA8Bit }
|
|
|
|
-
|
|
|
|
- TMyFPCompactImgRGBA8Bit = Class(TFPCompactImgRGBA8Bit)
|
|
|
|
- procedure SetInternalColor (x, y: integer; const Value: TFPColor); override;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-{ TMyFPCompactImgRGBA8Bit }
|
|
|
|
-
|
|
|
|
-procedure TMyFPCompactImgRGBA8Bit.SetInternalColor(x, y: integer; const Value: TFPColor);
|
|
|
|
|
|
+procedure TFPReportData.DoFirst;
|
|
begin
|
|
begin
|
|
- if (X<0) or (Y<0) or (X>=Width) or (Y>=Height) then
|
|
|
|
- Writeln('(',X,',',Y,') not in (0,0)x(',Width-1,',',Height-1,')')
|
|
|
|
- else
|
|
|
|
- inherited SetInternalColor(x, y, Value);
|
|
|
|
|
|
+ // Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.RenderUnknownElement(aBasePos: TFPReportPoint;
|
|
|
|
- AElement: TFPReportElement; ADPI: Integer);
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- C : TFPReportElementExporterCallBack;
|
|
|
|
- IC : TFPReportImageRenderCallBack;
|
|
|
|
- Img : TFPCustomImage;
|
|
|
|
- H,W : Integer;
|
|
|
|
- R : TFPReportRect;
|
|
|
|
-
|
|
|
|
|
|
+procedure TFPReportData.DoNext;
|
|
begin
|
|
begin
|
|
- // Actually, this could be cached using propertyhash...
|
|
|
|
- C:=gElementFactory.FindRenderer(TFPReportExporterClass(self.ClassType),TFPReportElementClass(aElement.ClassType));
|
|
|
|
- if (C<>Nil) then
|
|
|
|
- // There is a direct renderer
|
|
|
|
- C(aBasePos, aElement,Self,aDPI)
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- // There is no direct renderer, try rendering to image
|
|
|
|
- IC:=gElementFactory.FindImageRenderer(TFPReportElementClass(aElement.ClassType));
|
|
|
|
- if Assigned(IC) then
|
|
|
|
- begin
|
|
|
|
- H := Round(aElement.RTLayout.Height * (aDPI / cMMperInch));
|
|
|
|
- W := Round(aElement.RTLayout.Width * (aDPI / cMMperInch));
|
|
|
|
- Img:=TFPCompactImgRGBA8Bit.Create(W,H);
|
|
|
|
- try
|
|
|
|
- IC(aElement,Img);
|
|
|
|
- R.Left:=aBasePos.Left+AElement.RTLayout.Left;
|
|
|
|
- R.Top:=aBasePos.Top+AElement.RTLayout.Top;
|
|
|
|
- R.Width:=AElement.RTLayout.Width;
|
|
|
|
- R.Height:=AElement.RTLayout.Height;
|
|
|
|
- RenderImage(R,Img);
|
|
|
|
- finally
|
|
|
|
- Img.Free;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
|
|
+ // Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-
|
|
|
|
-class function TFPReportExporter.DefaultConfig: TFPReportExporterConfigHandler;
|
|
|
|
|
|
+procedure TFPReportData.DoClose;
|
|
begin
|
|
begin
|
|
- Result:=Nil;
|
|
|
|
|
|
+ // Do nothing
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.Execute;
|
|
|
|
|
|
+function TFPReportData.DoEOF: boolean;
|
|
begin
|
|
begin
|
|
- if (FPReport.RTObjects.Count=0) and AutoRun then
|
|
|
|
- FPreport.RunReport;
|
|
|
|
- if FPReport.RTObjects.Count > 0 then
|
|
|
|
- DoExecute(FPReport.RTObjects);
|
|
|
|
|
|
+ Result := False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportExporter.SetFileName(const aFileName: String);
|
|
|
|
|
|
+constructor TFPReportData.Create(AOwner: TComponent);
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ FDatafields := CreateDataFields;
|
|
|
|
+ FDatafields.FReportData := Self;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class procedure TFPReportExporter.RegisterExporter;
|
|
|
|
|
|
+destructor TFPReportData.Destroy;
|
|
begin
|
|
begin
|
|
- ReportExportManager.RegisterExport(Self);
|
|
|
|
|
|
+ FreeAndNil(FDatafields);
|
|
|
|
+ inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class procedure TFPReportExporter.UnRegisterExporter;
|
|
|
|
|
|
+procedure TFPReportData.InitFieldDefs;
|
|
begin
|
|
begin
|
|
- ReportExportManager.UnRegisterExport(Self);
|
|
|
|
|
|
+ if FIsOpened then
|
|
|
|
+ ReportError(SErrInitFieldsNotAllowedAfterOpen);
|
|
|
|
+ DoInitDataFields;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportExporter.Description: String;
|
|
|
|
|
|
+procedure TFPReportData.Open;
|
|
begin
|
|
begin
|
|
- Result:='';
|
|
|
|
|
|
+ if Assigned(FOnOpen) then
|
|
|
|
+ FOnOpen(Self);
|
|
|
|
+ DoOpen;
|
|
|
|
+ InitFieldDefs;
|
|
|
|
+ FIsOpened := True;
|
|
|
|
+ FRecNo := 1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportExporter.Name: String;
|
|
|
|
|
|
+procedure TFPReportData.First;
|
|
begin
|
|
begin
|
|
- Result:=ClassName;
|
|
|
|
|
|
+ if Assigned(FOnFirst) then
|
|
|
|
+ FOnFirst(Self);
|
|
|
|
+ DoFirst;
|
|
|
|
+ FRecNo := 1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportExporter.DefaultExtension: String;
|
|
|
|
|
|
+procedure TFPReportData.Next;
|
|
begin
|
|
begin
|
|
- Result:='';
|
|
|
|
|
|
+ Inc(FRecNo);
|
|
|
|
+ if Assigned(FOnNext) then
|
|
|
|
+ FOnNext(Self);
|
|
|
|
+ DoNext;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportExporter.MultiFile: Boolean;
|
|
|
|
|
|
+procedure TFPReportData.Close;
|
|
begin
|
|
begin
|
|
- Result:=False;
|
|
|
|
|
|
+ if Assigned(FOnClose) then
|
|
|
|
+ FOnClose(Self);
|
|
|
|
+ DoClose;
|
|
|
|
+ FIsOpened := False;
|
|
|
|
+ FRecNo := -1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportExporter.ShowConfig: Boolean;
|
|
|
|
|
|
+function TFPReportData.EOF: boolean;
|
|
begin
|
|
begin
|
|
- Result:=ReportExportManager.ConfigExporter(Self);
|
|
|
|
|
|
+ Result := False;
|
|
|
|
+ if Assigned(FOnGetEOF) then
|
|
|
|
+ FOnGetEOF(Self, Result);
|
|
|
|
+ if not Result then
|
|
|
|
+ Result := DoEOF;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportPaperSize }
|
|
|
|
-
|
|
|
|
-constructor TFPReportPaperSize.Create(const AWidth, AHeight: TFPReportUnits);
|
|
|
|
|
|
+procedure TFPReportData.GetFieldList(List: TStrings);
|
|
|
|
+var
|
|
|
|
+ I: integer;
|
|
begin
|
|
begin
|
|
- FWidth := AWidth;
|
|
|
|
- FHeight := AHeight;
|
|
|
|
|
|
+ List.BeginUpdate;
|
|
|
|
+ try
|
|
|
|
+ List.Clear;
|
|
|
|
+ for I := 0 to FDataFields.Count - 1 do
|
|
|
|
+ List.add(FDataFields[I].FieldName);
|
|
|
|
+ finally
|
|
|
|
+ List.EndUpdate;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportFont }
|
|
|
|
-
|
|
|
|
-procedure TFPReportFont.SetFontName(const avalue: string);
|
|
|
|
|
|
+function TFPReportData.IndexOfField(const AFieldName: string): Integer;
|
|
begin
|
|
begin
|
|
- FFontName := AValue;
|
|
|
|
|
|
+ Result:= FDataFields.IndexOfField(AFieldName);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportFont.SetFontSize(const avalue: integer);
|
|
|
|
|
|
+function TFPReportData.HasField(const AFieldName: string): boolean;
|
|
begin
|
|
begin
|
|
- FFontSize := AValue;
|
|
|
|
|
|
+ Result := FDataFields.IndexOfField(AFieldName) <> -1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportFont.SetFontColor(const avalue: TFPReportColor);
|
|
|
|
|
|
+
|
|
|
|
+{ TFPReportClassMapping }
|
|
|
|
+
|
|
|
|
+function TFPReportClassMapping.IndexOfExportRenderer(
|
|
|
|
+ AClass: TFPReportExporterClass): Integer;
|
|
begin
|
|
begin
|
|
- FFontColor := AValue;
|
|
|
|
|
|
+ Result:=Length(FRenderers)-1;
|
|
|
|
+ While (Result>=0) and (FRenderers[Result].aClass<>AClass) do
|
|
|
|
+ Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportFont.Create;
|
|
|
|
|
|
+constructor TFPReportClassMapping.Create(const AMappingName: string; AElementClass: TFPReportElementClass);
|
|
begin
|
|
begin
|
|
- inherited Create;
|
|
|
|
- FFontName := cDefaultFont;
|
|
|
|
- FFontColor := clBlack;
|
|
|
|
- FFontSize := 10;
|
|
|
|
|
|
+ FMappingName := AMappingName;
|
|
|
|
+ FReportElementClass := AElementClass;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportFont.Assign(Source: TPersistent);
|
|
|
|
-var
|
|
|
|
- o: TFPReportFont;
|
|
|
|
|
|
+function TFPReportClassMapping.AddRenderer(aExporterClass: TFPReportExporterClass; aCallback: TFPReportElementExporterCallBack ): TFPReportElementExporterCallBack;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- //inherited Assign(Source);
|
|
|
|
- if (Source = nil) or not (Source is TFPReportFont) then
|
|
|
|
- ReportError(SErrCantAssignReportFont);
|
|
|
|
- o := TFPReportFont(Source);
|
|
|
|
- FFontName := o.Name;
|
|
|
|
- FFontSize := o.Size;
|
|
|
|
- FFontColor := o.Color;
|
|
|
|
|
|
+ Result:=nil;
|
|
|
|
+ I:=IndexOfExportRenderer(aExporterClass);
|
|
|
|
+ if (I=-1) then
|
|
|
|
+ begin
|
|
|
|
+ I:=Length(FRenderers);
|
|
|
|
+ SetLength(FRenderers,I+1);
|
|
|
|
+ FRenderers[i].aClass:=aExporterClass;
|
|
|
|
+ FRenderers[i].aCallback:=Nil;
|
|
|
|
+ end;
|
|
|
|
+ Result:=FRenderers[i].aCallback;
|
|
|
|
+ FRenderers[i].aCallback:=aCallback;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportPaperManager }
|
|
|
|
|
|
+function TFPReportClassMapping.FindRenderer(aClass: TFPReportExporterClass): TFPReportElementExporterCallBack;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperHeight(AIndex: integer): TFPReportUnits;
|
|
|
|
begin
|
|
begin
|
|
- Result := TFPReportPaperSize(FPaperSizes.Objects[AIndex]).Height;
|
|
|
|
|
|
+ I:=IndexOfExportRenderer(aClass);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Result:=FRenderers[I].aCallback
|
|
|
|
+ else
|
|
|
|
+ Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperHeightByName(AName: string): TFPReportUnits;
|
|
|
|
|
|
+{ TFPReportElementFactory }
|
|
|
|
+
|
|
|
|
+function TFPReportElementFactory.GetM(Aindex : integer): TFPReportClassMapping;
|
|
begin
|
|
begin
|
|
- Result := GetPaperByName(AName).Height;
|
|
|
|
|
|
+ Result:=TFPReportClassMapping(FList[AIndex]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperCount: integer;
|
|
|
|
|
|
+function TFPReportElementFactory.IndexOfElementName(const AElementName: string): Integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := FPaperSizes.Count;
|
|
|
|
|
|
+ Result:=Flist.Count-1;
|
|
|
|
+ While (Result>=0) and not SameText(Mappings[Result].MappingName, AElementName) do
|
|
|
|
+ Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperName(AIndex: integer): string;
|
|
|
|
|
|
+function TFPReportElementFactory.IndexOfElementClass(const AElementClass: TFPReportElementClass): Integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := FPaperSizes[AIndex];
|
|
|
|
|
|
+ Result:=Flist.Count-1;
|
|
|
|
+ While (Result>=0) and (Mappings[Result].ReportElementClass<>AElementClass) do
|
|
|
|
+ Dec(Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperWidth(AIndex: integer): TFPReportUnits;
|
|
|
|
|
|
+constructor TFPReportElementFactory.Create;
|
|
begin
|
|
begin
|
|
- Result := TFPReportPaperSize(FPaperSizes.Objects[AIndex]).Width;
|
|
|
|
|
|
+ FList := TFPObjectList.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperWidthByName(AName: string): TFPReportUnits;
|
|
|
|
|
|
+destructor TFPReportElementFactory.Destroy;
|
|
begin
|
|
begin
|
|
- Result := GetPaperByName(AName).Width;
|
|
|
|
|
|
+ FList.Free;
|
|
|
|
+ inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.FindPaper(const AName: string): TFPReportPaperSize;
|
|
|
|
-var
|
|
|
|
- I: integer;
|
|
|
|
|
|
+function TFPReportElementFactory.FindRenderer(aClass: TFPReportExporterClass;
|
|
|
|
+ AElement: TFPReportElementClass): TFPReportElementExporterCallBack;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- I := IndexOfPaper(AName);
|
|
|
|
- if (I = -1) then
|
|
|
|
- Result := nil
|
|
|
|
- else
|
|
|
|
- Result := TFPReportPaperSize(FPaperSizes.Objects[i]);
|
|
|
|
|
|
+ Result:=nil;
|
|
|
|
+ I:=IndexOfElementClass(aElement);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Result:=Mappings[i].FindRenderer(aClass);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.GetPaperByname(const AName: string): TFPReportPaperSize;
|
|
|
|
|
|
+function TFPReportElementFactory.FindImageRenderer(
|
|
|
|
+ AElement: TFPReportElementClass): TFPReportImageRenderCallBack;
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := FindPaper(AName);
|
|
|
|
- if Result = nil then
|
|
|
|
- ReportError(SErrUnknownPaper, [AName]);
|
|
|
|
|
|
+ Result:=nil;
|
|
|
|
+ I:=IndexOfElementClass(aElement);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Result:=Mappings[i].ImageRenderCallback;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportPaperManager.Create(AOwner: TComponent);
|
|
|
|
|
|
+function TFPReportElementFactory.RegisterImageRenderer(AElement: TFPReportElementClass; ARenderer: TFPReportImageRenderCallBack
|
|
|
|
+ ): TFPReportImageRenderCallBack;
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
begin
|
|
begin
|
|
- inherited Create(AOwner);
|
|
|
|
- FPaperSizes := TStringList.Create;
|
|
|
|
- FPaperSizes.Sorted := True;
|
|
|
|
|
|
+ Result:=nil;
|
|
|
|
+ I:=IndexOfElementClass(aElement);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ begin
|
|
|
|
+ Result:=Mappings[i].ImageRenderCallback;
|
|
|
|
+ Mappings[i].ImageRenderCallback:=ARenderer;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPReportPaperManager.Destroy;
|
|
|
|
-var
|
|
|
|
- I: integer;
|
|
|
|
|
|
+function TFPReportElementFactory.RegisterElementRenderer(AElement: TFPReportElementClass; ARenderClass: TFPReportExporterClass;
|
|
|
|
+ ARenderer: TFPReportElementExporterCallBack): TFPReportElementExporterCallBack;
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
begin
|
|
begin
|
|
- if Assigned(FPaperSizes) then
|
|
|
|
- begin
|
|
|
|
- for I := 0 to FPaperSizes.Count - 1 do
|
|
|
|
- FPaperSizes.Objects[i].Free;
|
|
|
|
- FreeAndNil(FPaperSizes);
|
|
|
|
- end;
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ Result:=nil;
|
|
|
|
+ I:=IndexOfElementClass(aElement);
|
|
|
|
+ if (I<>-1) then
|
|
|
|
+ Result:=Mappings[i].AddRenderer(aRenderClass,ARenderer);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPaperManager.Clear;
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
|
|
+procedure TFPReportElementFactory.RegisterEditorClass(const AElementName: string; AEditorClass: TFPReportElementEditorClass);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- for i := 0 to FPaperSizes.Count-1 do
|
|
|
|
- if Assigned(FPaperSizes.Objects[i]) then
|
|
|
|
- FPaperSizes.Objects[i].Free;
|
|
|
|
- FPaperSizes.Clear;
|
|
|
|
|
|
+ I:=IndexOfElementName(aElementName);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Mappings[i].EditorClass:=AEditorClass
|
|
|
|
+ else
|
|
|
|
+ Raise EReportError.CreateFmt(SErrUnknownElementName,[AElementName]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportPaperManager.IndexOfPaper(const AName: string): integer;
|
|
|
|
|
|
+procedure TFPReportElementFactory.RegisterEditorClass(AReportElementClass: TFPReportElementClass;
|
|
|
|
+ AEditorClass: TFPReportElementEditorClass);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- if not Assigned(FPaperSizes) then
|
|
|
|
- Result := -1
|
|
|
|
|
|
+ I:=IndexOfElementClass(aReportElementClass);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Mappings[i].EditorClass:=AEditorClass
|
|
else
|
|
else
|
|
- Result := FPaperSizes.IndexOf(AName);
|
|
|
|
|
|
+ if AReportElementClass<>Nil then
|
|
|
|
+ Raise EReportError.CreateFmt(SErrUnknownElementClass,[AReportElementClass.ClassName])
|
|
|
|
+ else
|
|
|
|
+ Raise EReportError.CreateFmt(SErrUnknownElementClass,['Nil']);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPaperManager.RegisterPaper(const AName: string; const AWidth, AHeight: TFPReportUnits);
|
|
|
|
-var
|
|
|
|
- I: integer;
|
|
|
|
- S: TFPReportPaperSize;
|
|
|
|
|
|
+procedure TFPReportElementFactory.UnRegisterEditorClass(const AElementName: string; AEditorClass: TFPReportElementEditorClass);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- I := FPaperSizes.IndexOf(AName);
|
|
|
|
- if (I = -1) then
|
|
|
|
- begin
|
|
|
|
- S := TFPReportPaperSize.Create(AWidth, AHeight);
|
|
|
|
- FPaperSizes.AddObject(AName, S);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- ReportError(SErrDuplicatePaperName, [AName]);
|
|
|
|
|
|
+ I:=IndexOfElementName(aElementName);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ if Mappings[i].EditorClass=AEditorClass then
|
|
|
|
+ Mappings[i].EditorClass:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ Got details from Wikipedia [https://simple.wikipedia.org/wiki/Paper_size] }
|
|
|
|
-procedure TFPReportPaperManager.RegisterStandardSizes;
|
|
|
|
|
|
+procedure TFPReportElementFactory.UnRegisterEditorClass(AReportElementClass: TFPReportElementClass;
|
|
|
|
+ AEditorClass: TFPReportElementEditorClass);
|
|
|
|
+Var
|
|
|
|
+ I : integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // As per TFPReportUnits, size is specified in millimetres.
|
|
|
|
- RegisterPaper('A3', 297, 420);
|
|
|
|
- RegisterPaper('A4', 210, 297);
|
|
|
|
- RegisterPaper('A5', 148, 210);
|
|
|
|
- RegisterPaper('Letter', 216, 279);
|
|
|
|
- RegisterPaper('Legal', 216, 356);
|
|
|
|
- RegisterPaper('Ledger', 279, 432);
|
|
|
|
- RegisterPaper('DL', 220, 110);
|
|
|
|
- RegisterPaper('B5', 176, 250);
|
|
|
|
- RegisterPaper('C5', 162, 229);
|
|
|
|
|
|
+ I:=IndexOfElementClass(aReportElementClass);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ if Mappings[i].EditorClass=AEditorClass then
|
|
|
|
+ Mappings[i].EditorClass:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportPaperManager.GetRegisteredSizes(var AList: TStringList);
|
|
|
|
|
|
+procedure TFPReportElementFactory.RegisterClass(const AElementName: string; AReportElementClass: TFPReportElementClass);
|
|
var
|
|
var
|
|
i: integer;
|
|
i: integer;
|
|
begin
|
|
begin
|
|
- if not Assigned(AList) then
|
|
|
|
- Exit;
|
|
|
|
- AList.Clear;
|
|
|
|
- for i := 0 to FPaperSizes.Count - 1 do
|
|
|
|
- AList.Add(PaperNames[i]);
|
|
|
|
|
|
+ I:=IndexOfElementName(AElementName);
|
|
|
|
+ if I<>-1 then exit;
|
|
|
|
+ FList.Add(TFPReportClassMapping.Create(AElementName, AReportElementClass));
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure DoneReporting;
|
|
|
|
|
|
+function TFPReportElementFactory.CreateInstance(const AElementName: string; AOwner: TComponent): TFPReportElement;
|
|
|
|
+var
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- if Assigned(uPaperManager) then
|
|
|
|
- FreeAndNil(uPaperManager);
|
|
|
|
- TFPReportCustomCheckbox.ImgFalse.Free;
|
|
|
|
- TFPReportCustomCheckbox.ImgTrue.Free;
|
|
|
|
|
|
+ Result := nil;
|
|
|
|
+ for i := 0 to FList.Count - 1 do
|
|
|
|
+ begin
|
|
|
|
+ if SameText(Mappings[I].MappingName, AElementName) then
|
|
|
|
+ begin
|
|
|
|
+ Result := Mappings[I].ReportElementClass.Create(AOwner);
|
|
|
|
+ Break; //==>
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if Result = nil then
|
|
|
|
+ ReportError(SErrRegisterUnknownElement, [AElementName]);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPTextBlockList }
|
|
|
|
-
|
|
|
|
-function TFPTextBlockList.GetItem(AIndex: Integer): TFPTextBlock;
|
|
|
|
|
|
+function TFPReportElementFactory.FindEditorClassForInstance(AInstance: TFPReportElement): TFPReportElementEditorClass;
|
|
begin
|
|
begin
|
|
- Result := TFPTextBlock(inherited GetItem(AIndex));
|
|
|
|
|
|
+ if AInstance<>Nil then
|
|
|
|
+ Result:=FindEditorClassForInstance(TFPReportElementClass(Ainstance.ClassType))
|
|
|
|
+ else
|
|
|
|
+ Result:=Nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPTextBlockList.SetItem(AIndex: Integer; AObject: TFPTextBlock);
|
|
|
|
-begin
|
|
|
|
- inherited SetItem(AIndex, AObject);
|
|
|
|
-end;
|
|
|
|
|
|
+function TFPReportElementFactory.FindEditorClassForInstance(AClass: TFPReportElementClass): TFPReportElementEditorClass;
|
|
|
|
|
|
-{ TFPReportDataField }
|
|
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
|
|
-function TFPReportDataField.GetValue: variant;
|
|
|
|
begin
|
|
begin
|
|
- Result := Null;
|
|
|
|
- if Assigned(Collection) then
|
|
|
|
- TFPReportDatafields(Collection).ReportData.DoGetValue(FieldName, Result);
|
|
|
|
|
|
+ I:=IndexOfElementClass(AClass);
|
|
|
|
+ if I<>-1 then
|
|
|
|
+ Result:=Mappings[I].EditorClass
|
|
|
|
+ else
|
|
|
|
+ Result:=nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportDataField.Assign(Source: TPersistent);
|
|
|
|
|
|
+procedure TFPReportElementFactory.AssignReportElementTypes(AStrings: TStrings);
|
|
var
|
|
var
|
|
- F: TFPReportDataField;
|
|
|
|
|
|
+ i: integer;
|
|
begin
|
|
begin
|
|
- if Source is TFPReportDataField then
|
|
|
|
- begin
|
|
|
|
- F := Source as TFPReportDataField;
|
|
|
|
- FDisplayWidth := F.FDisplayWidth;
|
|
|
|
- FFieldKind := F.FFieldKind;
|
|
|
|
- FFieldName := F.FFieldName;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- inherited Assign(Source);
|
|
|
|
|
|
+ AStrings.Clear;
|
|
|
|
+ for i := 0 to FList.Count - 1 do
|
|
|
|
+ AStrings.Add(Mappings[I].MappingName);
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportDataFields }
|
|
|
|
|
|
+{ TFPReportCustomDataHeaderBand }
|
|
|
|
|
|
-function TFPReportDataFields.GetF(AIndex: integer): TFPReportDataField;
|
|
|
|
|
|
+function TFPReportCustomDataHeaderBand.GetReportBandName: string;
|
|
begin
|
|
begin
|
|
- Result := TFPReportDataField(Items[AIndex]);
|
|
|
|
|
|
+ Result := 'DataHeaderBand';
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportDataFields.SetF(AIndex: integer; const AValue: TFPReportDataField);
|
|
|
|
|
|
+class function TFPReportCustomDataHeaderBand.ReportBandType: TFPReportBandType;
|
|
begin
|
|
begin
|
|
- Items[AIndex] := AValue;
|
|
|
|
|
|
+ Result:=btDataHeader;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportDataFields.AddField(AFieldName: string; AFieldKind: TFPReportFieldKind): TFPReportDataField;
|
|
|
|
|
|
+{ TFPReportCustomDataFooterBand }
|
|
|
|
+
|
|
|
|
+function TFPReportCustomDataFooterBand.GetReportBandName: string;
|
|
begin
|
|
begin
|
|
- Result := Add as TFPReportDataField;
|
|
|
|
- try
|
|
|
|
- Result.FieldName := AFieldName;
|
|
|
|
- Result.FieldKind := AFieldKind;
|
|
|
|
- except
|
|
|
|
- Result.Free;
|
|
|
|
- raise;
|
|
|
|
- end;
|
|
|
|
|
|
+ Result := 'DataFooterBand';
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportDataFields.IndexOfField(const AFieldName: string): integer;
|
|
|
|
|
|
+class function TFPReportCustomDataFooterBand.ReportBandType: TFPReportBandType;
|
|
begin
|
|
begin
|
|
- Result := Count - 1;
|
|
|
|
- while (Result >= 0) and (CompareText(AFieldName, GetF(Result).FieldName) <> 0) do
|
|
|
|
- Dec(Result);
|
|
|
|
|
|
+ Result:=btDataFooter;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportDataFields.FindField(const AFieldName: string): TFPReportDataField;
|
|
|
|
|
|
+{ ---------------------------------------------------------------------
|
|
|
|
+ TFPReportLayouter
|
|
|
|
+ ---------------------------------------------------------------------}
|
|
|
|
+
|
|
|
|
+procedure TFPReportLayouter.RemoveTitleBandFromHeaderList;
|
|
var
|
|
var
|
|
- I: integer;
|
|
|
|
|
|
+ idx: integer;
|
|
|
|
+ lBand: TFPReportCustomBand;
|
|
begin
|
|
begin
|
|
- I := IndexOfField(AFieldName);
|
|
|
|
- if (I = -1) then
|
|
|
|
- Result := nil
|
|
|
|
- else
|
|
|
|
- Result := GetF(I);
|
|
|
|
|
|
+ idx := FHeaderList.Find(TFPReportCustomTitleBand, lBand);
|
|
|
|
+ if idx > -1 then
|
|
|
|
+ FHeaderList.Delete(idx);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportDataFields.FindField(const AFieldName: string; const AFieldKind: TFPReportFieldKind): TFPReportDataField;
|
|
|
|
|
|
+procedure TFPReportLayouter.RemoveColumnFooterFromFooterList;
|
|
var
|
|
var
|
|
- lIndex: integer;
|
|
|
|
|
|
+ idx: integer;
|
|
|
|
+ lBand: TFPReportCustomBand;
|
|
begin
|
|
begin
|
|
- lIndex := Count - 1;
|
|
|
|
- while (lIndex >= 0) and (not SameText(AFieldName, GetF(lIndex).FieldName)) and (GetF(lIndex).FieldKind <> AFieldKind) do
|
|
|
|
- Dec(lIndex);
|
|
|
|
-
|
|
|
|
- if (lIndex = -1) then
|
|
|
|
- Result := nil
|
|
|
|
- else
|
|
|
|
- Result := GetF(lIndex);
|
|
|
|
|
|
+ idx := FFooterList.Find(TFPReportCustomColumnFooterBand, lBand);
|
|
|
|
+ if idx > -1 then
|
|
|
|
+ FFooterList.Delete(idx);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportDataFields.FieldByName(const AFieldName: string): TFPReportDataField;
|
|
|
|
|
|
+procedure TFPReportLayouter.UpdateSpaceRemaining(const ABand: TFPReportCustomBand; const AUpdateYPos: boolean = True);
|
|
begin
|
|
begin
|
|
- Result := FindField(AFieldName);
|
|
|
|
- if (Result = nil) then
|
|
|
|
- begin
|
|
|
|
- if Assigned(ReportData) then
|
|
|
|
- ReportError(SErrUnknownField, [ReportData.Name, AFieldName])
|
|
|
|
- else
|
|
|
|
- ReportError(SErrUnknownField, ['', AFieldName]);
|
|
|
|
- end;
|
|
|
|
|
|
+ FSpaceLeft := FSpaceLeft - ABand.RTLayout.Height;
|
|
|
|
+ if AUpdateYPos then
|
|
|
|
+ FLastYPos := FLastYPos + ABand.RTLayout.Height;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportData }
|
|
|
|
|
|
+procedure TFPReportLayouter.CommonRuntimeBandProcessing(const aBand: TFPReportCustomBand);
|
|
|
|
|
|
-procedure TFPReportData.SetDataFields(const AValue: TFPReportDataFields);
|
|
|
|
begin
|
|
begin
|
|
- if (FDataFields = AValue) then
|
|
|
|
- Exit;
|
|
|
|
- FDataFields.Assign(AValue);
|
|
|
|
|
|
+ aBand.PrepareObjects;
|
|
|
|
+ FRTBand:=FRTCurBand;
|
|
|
|
+ FRTBand.RecalcLayout;
|
|
|
|
+ FRTBand.BeforePrint;
|
|
|
|
+ FRTBand.RTLayout.Top := FLastYPos;
|
|
|
|
+ FRTBand.RTLayout.Left := FLastXPos;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.GetFieldCount: integer;
|
|
|
|
-begin
|
|
|
|
- Result := FDatafields.Count;
|
|
|
|
-end;
|
|
|
|
|
|
+{ Result of True means ADsgnBand must be skipped. Result of False means ADsgnBand
|
|
|
|
+ must be rendered (ie: not skipped). }
|
|
|
|
+
|
|
|
|
+function TFPReportLayouter.MaybeSkipBand(const ADsgnBand: TFPReportCustomBand): boolean;
|
|
|
|
|
|
-function TFPReportData.GetFieldName(Index: integer): string;
|
|
|
|
begin
|
|
begin
|
|
- Result := FDatafields[Index].FieldName;
|
|
|
|
|
|
+ Result := True;
|
|
|
|
+ if ADsgnBand.VisibleOnPage = vpAll then
|
|
|
|
+ begin
|
|
|
|
+ // do nothing special
|
|
|
|
+ end
|
|
|
|
+ else if (PageNumberPerDesignerPage = 1) then
|
|
|
|
+ begin // first page rules
|
|
|
|
+ if (ADsgnBand.VisibleOnPage in [vpFirstOnly, vpFirstAndLastOnly]) then
|
|
|
|
+ begin
|
|
|
|
+ // do nothing special
|
|
|
|
+ end
|
|
|
|
+ else if (ADsgnBand.VisibleOnPage in [vpNotOnFirst, vpLastOnly, vpNotOnFirstAndLast]) then
|
|
|
|
+ Exit; // user asked to skip this band
|
|
|
|
+ end
|
|
|
|
+ else if (PageNumberPerDesignerPage > 1) then
|
|
|
|
+ begin // multi-page rules
|
|
|
|
+ if ADsgnBand.VisibleOnPage in [vpFirstOnly] then
|
|
|
|
+ Exit // user asked to skip this band
|
|
|
|
+ else if ADsgnBand.VisibleOnPage in [vpNotOnFirst] then
|
|
|
|
+ begin
|
|
|
|
+ // do nothing special
|
|
|
|
+ end
|
|
|
|
+ else if (not IsFirstPass) then
|
|
|
|
+ begin // last page rules
|
|
|
|
+ if (ADsgnBand.VisibleOnPage in [vpLastOnly, vpFirstAndLastOnly]) and (PageNumberPerDesignerPage < PerDesignerPageCount[PageIdx]) then
|
|
|
|
+ Exit
|
|
|
|
+ else if (ADsgnBand.VisibleOnPage in [vpNotOnLast, vpFirstOnly, vpNotOnFirstAndLast]) and (PageNumberPerDesignerPage = PerDesignerPageCount[PageIdx]) then
|
|
|
|
+ Exit; // user asked to skip this band
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ Result := False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.GetFieldType(AFieldName: string): TFPReportFieldKind;
|
|
|
|
|
|
+{ Result of True means ADsgnBand must be skipped. Result of False means aBand
|
|
|
|
+ must be rendered (ie: not skipped). }
|
|
|
|
+function TFPReportLayouter.ShowPageHeaderBand(const aBand: TFPReportCustomBand) : boolean;
|
|
begin
|
|
begin
|
|
- Result := FDatafields.FieldByName(AFieldName).FieldKind;
|
|
|
|
|
|
+ Result := True;
|
|
|
|
+ if not (aBand is TFPReportCustomPageHeaderBand) then
|
|
|
|
+ Exit;
|
|
|
|
+ if MaybeSkipBand(aBand as TFPReportCustomPageHeaderBand) then
|
|
|
|
+ Exit;
|
|
|
|
+ CommonRuntimeBandProcessing(aBand);
|
|
|
|
+ Result := False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.GetFieldValue(AFieldName: string): variant;
|
|
|
|
|
|
+function TFPReportLayouter.ShowColumnHeaderBand(const aBand: TFPReportCustomBand): boolean;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lBand: TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := varNull;
|
|
|
|
- DoGetValue(AFieldName, Result);
|
|
|
|
|
|
+ Result := False;
|
|
|
|
+ CommonRuntimeBandProcessing(aBand);
|
|
|
|
+ { Only once we show the first column header do we take into account
|
|
|
|
+ the column footer. }
|
|
|
|
+ lBand := Pages[PageIdx].FindBand(TFPReportCustomColumnFooterBand);
|
|
|
|
+ FFooterList.Add(lBand);
|
|
|
|
+ UpdateSpaceRemaining(aBand,false);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.GetFieldWidth(AFieldName: string): integer;
|
|
|
|
|
|
+procedure TFPReportLayouter.HandleHeaderBands;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I : Integer;
|
|
|
|
+ lBand: TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := FDataFields.FieldByName(AFieldName).DisplayWidth;
|
|
|
|
|
|
+ { Show all header bands }
|
|
|
|
+ for I := 0 to FHeaderList.Count - 1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := FHeaderList[I];
|
|
|
|
+ if lBand is TFPReportCustomPageHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ if ShowPageHeaderBand(lBand) then
|
|
|
|
+ Continue;
|
|
|
|
+ end
|
|
|
|
+ else if lBand is TFPReportCustomColumnHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ if ShowColumnHeaderBand(lBand) then
|
|
|
|
+ Continue;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ CommonRuntimeBandProcessing(lBand);
|
|
|
|
+ UpdateSpaceRemaining(FRTBand);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.CreateDataFields: TFPReportDataFields;
|
|
|
|
|
|
+procedure TFPReportLayouter.HandleFooterBands;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result := TFPReportDataFields.Create(TFPReportDataField);
|
|
|
|
|
|
+ { Show footer band if it exists }
|
|
|
|
+ lBand := FFooterList.Find(TFPReportCustomPageFooterBand);
|
|
|
|
+ if Assigned(lBand) then
|
|
|
|
+ ShowFooterBand(TFPReportCustomPageFooterBand(lBand));
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoGetValue(const AFieldName: string; var AValue: variant);
|
|
|
|
|
|
+Procedure TFPReportLayouter.ShowColumnFooterBand(APage: TFPReportCustomPage; ABand: TFPReportCustomColumnFooterBand);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lBandCount: integer;
|
|
|
|
+ lOverflowBand: TFPReportCustomBand;
|
|
|
|
+ lFooterBand : TFPReportCustomColumnFooterBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- AValue := Null;
|
|
|
|
|
|
+ lBandCount := FRTPage.BandCount - 1;
|
|
|
|
+ lOverflowBand := FRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
|
|
|
|
+ CommonRuntimeBandProcessing(ABand);
|
|
|
|
+ lFooterBand := TFPReportCustomColumnFooterBand(FRTBand);
|
|
|
|
+ if FPageFooterYPos = -1 then
|
|
|
|
+ FRTBand.RTLayout.Top := (APage.RTLayout.Top + APage.RTLayout.Height) - FRTBand.RTLayout.Height
|
|
|
|
+ else
|
|
|
|
+ FRTBand.RTLayout.Top := FPageFooterYPos - FRTBand.RTLayout.Height;
|
|
|
|
+ if lFooterBand.FooterPosition = fpAfterLast then
|
|
|
|
+ begin
|
|
|
|
+ if FNewColumn or FOverflowed then
|
|
|
|
+ { take height of overflowed band into account }
|
|
|
|
+ FRTBand.RTLayout.Top := FLastYPos - lOverflowBand.RTLayout.Height
|
|
|
|
+ else
|
|
|
|
+ FRTBand.RTLayout.Top := FLastYPos;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoInitDataFields;
|
|
|
|
|
|
+function TFPReportLayouter.NoSpaceRemaining: boolean;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // Do nothing.
|
|
|
|
|
|
+ Result:=FSpaceLeft <= 0;
|
|
|
|
+ if Result then
|
|
|
|
+ begin
|
|
|
|
+ if FMultiColumn and (FCurrentColumn < Pages[PageIdx].ColumnCount) then
|
|
|
|
+ begin
|
|
|
|
+ FNewColumn := True;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ FOverflowed := True;
|
|
|
|
+ FNewPage := True;
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoOpen;
|
|
|
|
|
|
+
|
|
|
|
+procedure TFPReportLayouter.StartNewColumn;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lIdx: integer;
|
|
|
|
+ lBandCount: integer;
|
|
|
|
+ lBand: TFPReportCustomBand;
|
|
|
|
+ lOverflowBand: TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ if Assigned(FLastDsgnDataBand) then
|
|
|
|
+ report.ClearDataBandLastTextValues(FLastDsgnDataBand);
|
|
|
|
+ if FMultiColumn and (FFooterList.Find(TFPReportCustomColumnFooterBand) <> nil) then
|
|
|
|
+ lBandCount := FRTPage.BandCount - 2 // skip over the ColumnFooter band
|
|
|
|
+ else
|
|
|
|
+ lBandCount := FRTPage.BandCount - 1;
|
|
|
|
+ lOverflowBand := FRTPage.Bands[lBandCount]; { store reference to band that caused the new column }
|
|
|
|
+ FSpaceLeft := Pages[PageIdx].Layout.Height; // original designer page
|
|
|
|
+ FRTPage := TFPReportCustomPage(RTObjects[RTCurPageIdx]);
|
|
|
|
+ FLastYPos := FRTPage.RTLayout.Top;
|
|
|
|
+ FLastXPos := FLastXPos + lOverflowBand.RTLayout.Width + Pages[PageIdx].ColumnGap;
|
|
|
|
+ { Adjust starting Y-Pos based on bands in lHeaderList. }
|
|
|
|
+ for lIdx := 0 to FHeaderList.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := FHeaderList[lIdx];
|
|
|
|
+ if lBand is TFPReportCustomPageHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ if MaybeSkipBand(lBand) then
|
|
|
|
+ Continue;
|
|
|
|
+ end
|
|
|
|
+ else if lBand is TFPReportCustomColumnHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ if ShowColumnHeaderBand(lBand) then
|
|
|
|
+ Continue;
|
|
|
|
+ end;
|
|
|
|
+ UpdateSpaceRemaining(lBand,True);
|
|
|
|
+ end;
|
|
|
|
+ inc(FCurrentColumn);
|
|
|
|
+ { If footer band exists, reduce available space }
|
|
|
|
+ lBand := FRTPage.FindBand(TFPReportCustomPageFooterBand);
|
|
|
|
+ if Assigned(lBand) then
|
|
|
|
+ UpdateSpaceRemaining(lBand, False);
|
|
|
|
+
|
|
|
|
+ if NoSpaceRemaining then
|
|
|
|
+ Exit;
|
|
|
|
+ { Fix position of last band that caused the new column }
|
|
|
|
+ lOverflowBand.RTLayout.Left := FLastXPos;
|
|
|
|
+ lOverflowBand.RTLayout.Top := FLastYPos;
|
|
|
|
+ { Adjust the next starting point of the next data band. }
|
|
|
|
+ UpdateSpaceRemaining(lOverflowBand);
|
|
|
|
+ FNewColumn := False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoFirst;
|
|
|
|
|
|
+procedure TFPReportLayouter.HandleOverflowed;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lPrevRTPage: TFPReportCustomPage;
|
|
|
|
+ lOverflowBand: TFPReportCustomBand;
|
|
|
|
+ lBandCount: integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ FOverflowed := False;
|
|
|
|
+ lPrevRTPage := TFPReportCustomPage(RTObjects[RTCurPageIdx-1]);
|
|
|
|
+ if FMultiColumn and (FFooterList.Find(TFPReportCustomColumnFooterBand) <> nil) then
|
|
|
|
+ lBandCount := lPrevRTPage.BandCount - 2 // skip over the ColumnFooter band
|
|
|
|
+ else
|
|
|
|
+ lBandCount := lPrevRTPage.BandCount - 1;
|
|
|
|
+ lOverflowBand := lPrevRTPage.Bands[lBandCount]; // get the last band - the one that didn't fit
|
|
|
|
+ lPrevRTPage.RemoveChild(lOverflowBand);
|
|
|
|
+ FRTPage.AddChild(lOverflowBand);
|
|
|
|
+
|
|
|
|
+ { Fix position of last band that caused the overflow }
|
|
|
|
+ lOverflowBand.RTLayout.Top := FLastYPos;
|
|
|
|
+ lOverflowBand.RTLayout.Left := FLastXPos;
|
|
|
|
+ UpdateSpaceRemaining(lOverflowBand);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoNext;
|
|
|
|
|
|
+procedure TFPReportLayouter.ShowFooterBand(aBand: TFPReportCustomPageFooterBand);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ FPageFooterYPos := -1;
|
|
|
|
+ if MaybeSkipBand(aBand) then
|
|
|
|
+ Exit;
|
|
|
|
+ aBand.PrepareObjects;
|
|
|
|
+ FRTBand := FRTCurBand;
|
|
|
|
+ FRTBand.RecalcLayout;
|
|
|
|
+ FRTBand.BeforePrint;
|
|
|
|
+ FRTBand.RTLayout.Top := (FRTPage.RTLayout.Top + FRTPage.RTLayout.Height) - FRTBand.RTLayout.Height;
|
|
|
|
+ FPageFooterYPos := FRTBand.RTLayout.Top;
|
|
|
|
+ // We don't adjust lLastYPos because this is a page footer
|
|
|
|
+ UpdateSpaceRemaining(FRTBand, False);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.DoClose;
|
|
|
|
|
|
+procedure TFPReportLayouter.PopulateHeaderList(APage: TFPReportCustomPage);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- // Do nothing
|
|
|
|
|
|
+ FHeaderList.Clear;
|
|
|
|
+ FHeaderList.Add(APage.FindBand(TFPReportCustomPageHeaderBand));
|
|
|
|
+ FHeaderList.Add(APage.FindBand(TFPReportCustomTitleBand));
|
|
|
|
+ if FMultiColumn then
|
|
|
|
+ FHeaderList.Add(Pages[PageIdx].FindBand(TFPReportColumnHeaderBand));
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.DoEOF: boolean;
|
|
|
|
|
|
+function TFPReportLayouter.GetPerDesignerPageCount(Index : Cardinal): Cardinal;
|
|
begin
|
|
begin
|
|
- Result := False;
|
|
|
|
|
|
+ Result:=Report.FPerDesignerPageCount[Index];
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportData.Create(AOwner: TComponent);
|
|
|
|
|
|
+Procedure TFPReportLayouter.InitRTCurPageIdx;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- inherited Create(AOwner);
|
|
|
|
- FDatafields := CreateDataFields;
|
|
|
|
- FDatafields.FReportData := Self;
|
|
|
|
|
|
+ Report.FRTCurPageIdx:=-1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPReportData.Destroy;
|
|
|
|
|
|
+function TFPReportLayouter.GetRTCurPageIdx: Integer;
|
|
begin
|
|
begin
|
|
- FreeAndNil(FDatafields);
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ Result:=Report.FRTCurPageIdx;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.InitFieldDefs;
|
|
|
|
|
|
+function TFPReportLayouter.GetRTObjects: TFPList;
|
|
begin
|
|
begin
|
|
- if FIsOpened then
|
|
|
|
- ReportError(SErrInitFieldsNotAllowedAfterOpen);
|
|
|
|
- DoInitDataFields;
|
|
|
|
|
|
+ Result:=Report.RTObjects;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.Open;
|
|
|
|
|
|
+procedure TFPReportLayouter.SetGetPerDesignerPageCount(Index : Cardinal; AValue: Cardinal);
|
|
begin
|
|
begin
|
|
- if Assigned(FOnOpen) then
|
|
|
|
- FOnOpen(Self);
|
|
|
|
- DoOpen;
|
|
|
|
- InitFieldDefs;
|
|
|
|
- FIsOpened := True;
|
|
|
|
- FRecNo := 1;
|
|
|
|
|
|
+ Report.FPerDesignerPageCount[Index]:=AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.First;
|
|
|
|
|
|
+
|
|
|
|
+procedure TFPReportLayouter.SetPageNumberPerDesignerPage(aValue: Integer);
|
|
begin
|
|
begin
|
|
- if Assigned(FOnFirst) then
|
|
|
|
- FOnFirst(Self);
|
|
|
|
- DoFirst;
|
|
|
|
- FRecNo := 1;
|
|
|
|
|
|
+ Report.FPageNumberPerDesignerPage:=aValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.Next;
|
|
|
|
|
|
+procedure TFPReportLayouter.SetPageCount(aCount: Integer);
|
|
begin
|
|
begin
|
|
- Inc(FRecNo);
|
|
|
|
- if Assigned(FOnNext) then
|
|
|
|
- FOnNext(Self);
|
|
|
|
- DoNext;
|
|
|
|
|
|
+ Report.FPageCount:=aCount;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.Close;
|
|
|
|
|
|
+function TFPReportLayouter.GetPage(AIndex: integer): TFPReportCustomPage;
|
|
begin
|
|
begin
|
|
- if Assigned(FOnClose) then
|
|
|
|
- FOnClose(Self);
|
|
|
|
- DoClose;
|
|
|
|
- FIsOpened := False;
|
|
|
|
- FRecNo := -1;
|
|
|
|
|
|
+ Result:=Report.Pages[AIndex];
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.EOF: boolean;
|
|
|
|
|
|
+function TFPReportLayouter.FRTCurBand: TFPReportCustomBand;
|
|
begin
|
|
begin
|
|
- Result := False;
|
|
|
|
- if Assigned(FOnGetEOF) then
|
|
|
|
- FOnGetEOF(Self, Result);
|
|
|
|
- if not Result then
|
|
|
|
- Result := DoEOF;
|
|
|
|
|
|
+ Result:=Report.FRTCurBand;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportData.GetFieldList(List: TStrings);
|
|
|
|
-var
|
|
|
|
- I: integer;
|
|
|
|
|
|
+function TFPReportLayouter.GetPageNumberPerDesignerPage: Integer;
|
|
begin
|
|
begin
|
|
- List.BeginUpdate;
|
|
|
|
- try
|
|
|
|
- List.Clear;
|
|
|
|
- for I := 0 to FDataFields.Count - 1 do
|
|
|
|
- List.add(FDataFields[I].FieldName);
|
|
|
|
- finally
|
|
|
|
- List.EndUpdate;
|
|
|
|
- end;
|
|
|
|
|
|
+ Result:=Report.FPageNumberPerDesignerPage;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.IndexOfField(const AFieldName: string): Integer;
|
|
|
|
|
|
+function TFPReportLayouter.IsFirstPass: Boolean;
|
|
begin
|
|
begin
|
|
- Result:= FDataFields.IndexOfField(AFieldName);
|
|
|
|
|
|
+ Result:=Report.IsFirstPass;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportData.HasField(const AFieldName: string): boolean;
|
|
|
|
|
|
+procedure TFPReportLayouter.PopulateFooterList(APage: TFPReportCustomPage);
|
|
begin
|
|
begin
|
|
- Result := FDataFields.IndexOfField(AFieldName) <> -1;
|
|
|
|
|
|
+ FFooterList.Clear;
|
|
|
|
+ FFooterList.Add(APage.FindBand(TFPReportCustomPageFooterBand));
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TFPReportLayouter.IncPageNumber;
|
|
|
|
|
|
-{ TFPReportClassMapping }
|
|
|
|
-
|
|
|
|
-function TFPReportClassMapping.IndexOfExportRenderer(
|
|
|
|
- AClass: TFPReportExporterClass): Integer;
|
|
|
|
begin
|
|
begin
|
|
- Result:=Length(FRenderers)-1;
|
|
|
|
- While (Result>=0) and (FRenderers[Result].aClass<>AClass) do
|
|
|
|
- Dec(Result);
|
|
|
|
|
|
+ Inc(Report.FPageNumber);
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportClassMapping.Create(const AMappingName: string; AElementClass: TFPReportElementClass);
|
|
|
|
|
|
+procedure TFPReportLayouter.InitPageNumber;
|
|
begin
|
|
begin
|
|
- FMappingName := AMappingName;
|
|
|
|
- FReportElementClass := AElementClass;
|
|
|
|
|
|
+ Report.FPageNumber:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportClassMapping.AddRenderer(aExporterClass: TFPReportExporterClass; aCallback: TFPReportElementExporterCallBack ): TFPReportElementExporterCallBack;
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+procedure TFPReportLayouter.IncPageNumberPerDesignerPage;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=nil;
|
|
|
|
- I:=IndexOfExportRenderer(aExporterClass);
|
|
|
|
- if (I=-1) then
|
|
|
|
- begin
|
|
|
|
- I:=Length(FRenderers);
|
|
|
|
- SetLength(FRenderers,I+1);
|
|
|
|
- FRenderers[i].aClass:=aExporterClass;
|
|
|
|
- FRenderers[i].aCallback:=Nil;
|
|
|
|
- end;
|
|
|
|
- Result:=FRenderers[i].aCallback;
|
|
|
|
- FRenderers[i].aCallback:=aCallback;
|
|
|
|
|
|
+ inc(Report.FPageNumberPerDesignerPage);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportClassMapping.FindRenderer(aClass: TFPReportExporterClass): TFPReportElementExporterCallBack;
|
|
|
|
|
|
+procedure TFPReportLayouter.StartNewPage;
|
|
|
|
|
|
-Var
|
|
|
|
- I : Integer;
|
|
|
|
|
|
+begin
|
|
|
|
+ if Assigned(FLastDsgnDataBand) then
|
|
|
|
+ report.ClearDataBandLastTextValues(FLastDsgnDataBand);
|
|
|
|
+ FSpaceLeft := Pages[PageIdx].Layout.Height; // original designer page
|
|
|
|
+ Pages[PageIdx].PrepareObjects; // creates a new page object
|
|
|
|
+ //not needed here, it's done in TFPReportCustomPage.PrepareObjects: FRTCurPageIdx := RTObjects.Count-1;
|
|
|
|
+ FRTPage := TFPReportCustomPage(RTObjects[RTCurPageIdx]);
|
|
|
|
+ FLastYPos := FRTPage.RTLayout.Top;
|
|
|
|
+ FLastXPos := FRTPage.RTLayout.Left;
|
|
|
|
+ IncPageNumber;
|
|
|
|
+ FCurrentColumn := 1;
|
|
|
|
+ FNewColumn := False;
|
|
|
|
+ if IsFirstPass then
|
|
|
|
+ PerDesignerPageCount[PageIdx] := PerDesignerPageCount[PageIdx] + 1;
|
|
|
|
+ if (PageNumberPerDesignerPage = 1) then
|
|
|
|
+ RemoveTitleBandFromHeaderList;
|
|
|
|
+ IncPageNumberPerDesignerPage;
|
|
|
|
+ HandleHeaderBands;
|
|
|
|
+ HandleFooterBands;
|
|
|
|
+ FNewPage := False;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+Procedure TFPReportLayouter.CheckRemaining(CheckMulticolumn : Boolean = True);
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfExportRenderer(aClass);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Result:=FRenderers[I].aCallback
|
|
|
|
- else
|
|
|
|
- Result:=Nil;
|
|
|
|
|
|
+ if NoSpaceRemaining then
|
|
|
|
+ begin
|
|
|
|
+ if CheckMulticolumn and FMultiColumn then
|
|
|
|
+ begin
|
|
|
|
+ FCurrentRTColumnFooterBand := TFPReportCustomColumnFooterBand(FFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
+ if Assigned(FCurrentRTColumnFooterBand) then
|
|
|
|
+ ShowColumnFooterBand(FRTPage, FCurrentRTColumnFooterBand);
|
|
|
|
+ end;
|
|
|
|
+ CheckNewOrOverFlow(CheckMulticolumn);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportElementFactory }
|
|
|
|
|
|
+procedure TFPReportLayouter.ShowDataBand(const aBand: TFPReportCustomDataBand);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ aChildBand: TFPReportChildBand;
|
|
|
|
+ aDataBand: TFPReportCustomBand;
|
|
|
|
|
|
-function TFPReportElementFactory.GetM(Aindex : integer): TFPReportClassMapping;
|
|
|
|
begin
|
|
begin
|
|
- Result:=TFPReportClassMapping(FList[AIndex]);
|
|
|
|
|
|
+ FLastDsgnDataBand := aBand;
|
|
|
|
+ CommonRuntimeBandProcessing(aBand);
|
|
|
|
+ if HandleBandVisibility(FRTBand,True) then
|
|
|
|
+ begin
|
|
|
|
+ aDataBand := FRTBand;
|
|
|
|
+ { process any child bands off of DataBand }
|
|
|
|
+ aChildBand := aDataBand.ChildBand;
|
|
|
|
+ while aChildBand <> nil do
|
|
|
|
+ begin
|
|
|
|
+ CommonRuntimeBandProcessing(aChildBand);
|
|
|
|
+ HandleBandVisibility(FRTBand,True);
|
|
|
|
+ aChildBand := aChildBand.ChildBand;
|
|
|
|
+ end; { while ChildBand <> nil }
|
|
|
|
+ end
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.IndexOfElementName(const AElementName: string): Integer;
|
|
|
|
|
|
+function TFPReportLayouter.HandleBandVisibility(aBand: TFPReportCustomBand; doRecalcLayout: Boolean): Boolean;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=Flist.Count-1;
|
|
|
|
- While (Result>=0) and not SameText(Mappings[Result].MappingName, AElementName) do
|
|
|
|
- Dec(Result);
|
|
|
|
|
|
+ Result:=aBand.EvaluateVisibility;
|
|
|
|
+ if Result then
|
|
|
|
+ begin
|
|
|
|
+ if DoRecalcLayout then
|
|
|
|
+ RecalcBandLayout(FRTBand);
|
|
|
|
+ UpdateSpaceRemaining(aBand);
|
|
|
|
+ CheckRemaining(True);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ // remove invisible band
|
|
|
|
+ FRTPage.RemoveChild(aBand);
|
|
|
|
+ FreeAndNil(aBand);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.IndexOfElementClass(const AElementClass: TFPReportElementClass): Integer;
|
|
|
|
|
|
+procedure TFPReportLayouter.ShowDataHeaderBand(const aBand: TFPReportCustomDataHeaderBand);
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=Flist.Count-1;
|
|
|
|
- While (Result>=0) and (Mappings[Result].ReportElementClass<>AElementClass) do
|
|
|
|
- Dec(Result);
|
|
|
|
|
|
+ if FDataHeaderPrinted then
|
|
|
|
+ Exit; // nothing further to do
|
|
|
|
+ CommonRuntimeBandProcessing(aBand);
|
|
|
|
+ if HandleBandVisibility(FRTBand,False) then
|
|
|
|
+ FDataHeaderPrinted := True;
|
|
end;
|
|
end;
|
|
|
|
|
|
-constructor TFPReportElementFactory.Create;
|
|
|
|
|
|
+procedure TFPReportLayouter.ShowDataFooterBand(const aBand: TFPReportCustomDataFooterBand);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- FList := TFPObjectList.Create;
|
|
|
|
|
|
+ CommonRuntimeBandProcessing(aBand);
|
|
|
|
+ HandleBandVisibility(FRTBand,False);
|
|
end;
|
|
end;
|
|
|
|
|
|
-destructor TFPReportElementFactory.Destroy;
|
|
|
|
|
|
+procedure TFPReportLayouter.ShowDetailBand(const AMasterBand: TFPReportCustomDataBand);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lDsgnDetailBand: TFPReportCustomDataBand;
|
|
|
|
+ lDetailBand: TFPReportCustomBand;
|
|
|
|
+ lDetailBandList: TBandList;
|
|
|
|
+ lData: TFPReportData;
|
|
|
|
+ i: integer;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- FList.Free;
|
|
|
|
- inherited Destroy;
|
|
|
|
|
|
+ if AMasterBand = nil then
|
|
|
|
+ Exit;
|
|
|
|
+ lDsgnDetailBand := nil;
|
|
|
|
+ lDetailBandList := TBandList.Create;
|
|
|
|
+ try
|
|
|
|
+ { collect bands of interest }
|
|
|
|
+ for i := 0 to Pages[PageIdx].BandCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ lDetailBand := Pages[PageIdx].Bands[i];
|
|
|
|
+ if (lDetailBand is TFPReportCustomDataBand)
|
|
|
|
+ and (TFPReportCustomDataBand(lDetailBand).MasterBand = AMasterBand)
|
|
|
|
+ and (TFPReportCustomDataBand(lDetailBand).Data <> nil) then
|
|
|
|
+ lDetailBandList.Add(lDetailBand);
|
|
|
|
+ end;
|
|
|
|
+ if lDetailBandList.Count = 0 then
|
|
|
|
+ exit; // nothing further to do
|
|
|
|
+ lDetailBandList.Sort(@SortDataBands);
|
|
|
|
+ { process Detail bands }
|
|
|
|
+ for i := 0 to lDetailBandList.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lDsgnDetailBand := TFPReportCustomDataBand(lDetailBandList[i]);
|
|
|
|
+ lData := lDsgnDetailBand.Data;
|
|
|
|
+ if not lData.IsOpened then
|
|
|
|
+ begin
|
|
|
|
+ lData.Open;
|
|
|
|
+ Report.InitializeExpressionVariables(Pages[PageIdx], lData);
|
|
|
|
+ Report.CacheMemoExpressions(PageIdx, lData);
|
|
|
|
+ end;
|
|
|
|
+ lData.First;
|
|
|
|
+ if (not lData.EOF) and (lDsgnDetailBand.HeaderBand <> nil) then
|
|
|
|
+ ShowDataHeaderBand(lDsgnDetailBand.HeaderBand);
|
|
|
|
+ while not lData.EOF do
|
|
|
|
+ begin
|
|
|
|
+ If Report.TwoPass and IsFirstPass then
|
|
|
|
+ Report.Variables.BuildAggregates;
|
|
|
|
+ inc(FDataLevelStack);
|
|
|
|
+ ShowDataBand(lDsgnDetailBand);
|
|
|
|
+ ShowDetailBand(lDsgnDetailBand);
|
|
|
|
+ dec(FDataLevelStack);
|
|
|
|
+ lData.Next;
|
|
|
|
+ end; { while not lData.EOF }
|
|
|
|
+ FDataHeaderPrinted := False;
|
|
|
|
+ CheckNewOrOverFlow;
|
|
|
|
+ // only print if we actually had data
|
|
|
|
+ if (lData.RecNo > 1) and (lDsgnDetailBand.FooterBand <> nil) then
|
|
|
|
+ ShowDataFooterBand(lDsgnDetailBand.FooterBand);
|
|
|
|
+ lDsgnDetailBand := nil;
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ lDetailBandList.Free;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.FindRenderer(aClass: TFPReportExporterClass;
|
|
|
|
- AElement: TFPReportElementClass): TFPReportElementExporterCallBack;
|
|
|
|
|
|
+Procedure TFPReportLayouter.PrepareGroupHeaderBand(aBand : TFPReportCustomGroupHeaderBand);
|
|
|
|
|
|
Var
|
|
Var
|
|
- I : Integer;
|
|
|
|
|
|
+ CurrGroup : String;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=nil;
|
|
|
|
- I:=IndexOfElementClass(aElement);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Result:=Mappings[i].FindRenderer(aClass);
|
|
|
|
|
|
+ // Writeln('Found group with expr: ',TFPReportCustomGroupHeaderBand(lDsgnBand).GroupCondition);
|
|
|
|
+ CurrGroup := aBand.Evaluate;
|
|
|
|
+ // Writeln('Group new ? "',lLastGroupCondition,'" <> "', CurrGroup,'"');
|
|
|
|
+ if (FLastGroupCondition = CurrGroup) then
|
|
|
|
+ Exit;
|
|
|
|
+ FNewGroupHeader := True;
|
|
|
|
+ { process group footer }
|
|
|
|
+ if Assigned(aBand.GroupFooter) then
|
|
|
|
+ begin
|
|
|
|
+ Report.FRTUseLastValues:=true;
|
|
|
|
+ try
|
|
|
|
+ lBand := aBand.GroupFooter;
|
|
|
|
+ CommonRuntimeBandProcessing(lBand);
|
|
|
|
+ finally
|
|
|
|
+ Report.FRTUseLastValues:=false;
|
|
|
|
+ end;
|
|
|
|
+ UpdateSpaceRemaining(FRTBand);
|
|
|
|
+ if NoSpaceRemaining then
|
|
|
|
+ CheckNewOrOverFlow;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.FindImageRenderer(
|
|
|
|
- AElement: TFPReportElementClass): TFPReportImageRenderCallBack;
|
|
|
|
|
|
+Procedure TFPReportLayouter.HandleGroupBands;
|
|
|
|
+
|
|
Var
|
|
Var
|
|
I : Integer;
|
|
I : Integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=nil;
|
|
|
|
- I:=IndexOfElementClass(aElement);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Result:=Mappings[i].ImageRenderCallback;
|
|
|
|
|
|
+ if FLastGroupCondition = '' then
|
|
|
|
+ FNewGroupHeader := True
|
|
|
|
+ else
|
|
|
|
+ for I := 0 to Report.FBands.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[i]);
|
|
|
|
+ if lBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
+ PrepareGroupHeaderBand(lBand as TFPReportCustomGroupHeaderBand);
|
|
|
|
+ end;
|
|
|
|
+ if not FNewGroupHeader then
|
|
|
|
+ Exit;
|
|
|
|
+ for i := 0 to Report.FBands.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[i]);
|
|
|
|
+ if lBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ if Assigned(FLastDsgnDataBand) then
|
|
|
|
+ Report.ClearDataBandLastTextValues(FLastDsgnDataBand);
|
|
|
|
+ CommonRuntimeBandProcessing(lBand);
|
|
|
|
+ FLastGroupCondition := TFPReportGroupHeaderBand(FRTBand).GroupConditionValue;
|
|
|
|
+ if Not lBand.EvaluateVisibility then
|
|
|
|
+ begin
|
|
|
|
+ FRTPage.RemoveChild(FRTBand);
|
|
|
|
+ FRTBand.Free;
|
|
|
|
+ Continue; { process next band }
|
|
|
|
+ end;
|
|
|
|
+ UpdateSpaceRemaining(FRTBand);
|
|
|
|
+ if NoSpaceRemaining then
|
|
|
|
+ Break; { break out of FOR loop }
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ FNewGroupHeader := False;
|
|
|
|
+ FDataHeaderPrinted := False;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.RegisterImageRenderer(AElement: TFPReportElementClass; ARenderer: TFPReportImageRenderCallBack
|
|
|
|
- ): TFPReportImageRenderCallBack;
|
|
|
|
|
|
+Procedure TFPReportLayouter.HandleDatabands;
|
|
|
|
+
|
|
Var
|
|
Var
|
|
- I : Integer;
|
|
|
|
|
|
+ D : TFPReportCustomDataBand;
|
|
|
|
+ i : Integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result:=nil;
|
|
|
|
- I:=IndexOfElementClass(aElement);
|
|
|
|
- if I<>-1 then
|
|
|
|
|
|
+ for I := 0 to Report.FBands.Count-1 do
|
|
begin
|
|
begin
|
|
- Result:=Mappings[i].ImageRenderCallback;
|
|
|
|
- Mappings[i].ImageRenderCallback:=ARenderer;
|
|
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[I]);
|
|
|
|
+ if (lBand is TFPReportCustomDataBand) then
|
|
|
|
+ begin
|
|
|
|
+ inc(FDataLevelStack);
|
|
|
|
+ D:=TFPReportCustomDataBand(lBand);
|
|
|
|
+ if D.HeaderBand <> nil then
|
|
|
|
+ ShowDataHeaderBand(D.HeaderBand);
|
|
|
|
+ ShowDataBand(D);
|
|
|
|
+ ShowDetailBand(D);
|
|
|
|
+ dec(FDataLevelStack);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.RegisterElementRenderer(AElement: TFPReportElementClass; ARenderClass: TFPReportExporterClass;
|
|
|
|
- ARenderer: TFPReportElementExporterCallBack): TFPReportElementExporterCallBack;
|
|
|
|
|
|
+procedure TFPReportLayouter.HandleGroupFooters;
|
|
|
|
+
|
|
Var
|
|
Var
|
|
I : Integer;
|
|
I : Integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- Result:=nil;
|
|
|
|
- I:=IndexOfElementClass(aElement);
|
|
|
|
- if (I<>-1) then
|
|
|
|
- Result:=Mappings[i].AddRenderer(aRenderClass,ARenderer);
|
|
|
|
|
|
+ for I := 0 to Report.FBands.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[I]);
|
|
|
|
+ if lBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ lBand:=(lBand as TFPReportCustomGroupHeaderBand).GroupFooter;
|
|
|
|
+ { We are allowed to use design Layout.Height instead of RTLayout.Height
|
|
|
|
+ because this band appears outside the data loop, thus memos will not
|
|
|
|
+ grow. Height of the band is as it was at design time. }
|
|
|
|
+ if lBand.Layout.Height > FSpaceLeft then
|
|
|
|
+ StartNewPage;
|
|
|
|
+ CommonRuntimeBandProcessing(lBand);
|
|
|
|
+ UpdateSpaceRemaining(FRTBand);
|
|
|
|
+ Break;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.RegisterEditorClass(const AElementName: string; AEditorClass: TFPReportElementEditorClass);
|
|
|
|
-
|
|
|
|
-Var
|
|
|
|
- I : integer;
|
|
|
|
|
|
+Procedure TFPReportLayouter.ClearBandList;
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfElementName(aElementName);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Mappings[i].EditorClass:=AEditorClass
|
|
|
|
- else
|
|
|
|
- Raise EReportError.CreateFmt(SErrUnknownElementName,[AElementName]);
|
|
|
|
|
|
+ Report.FBands.Clear;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.RegisterEditorClass(AReportElementClass: TFPReportElementClass;
|
|
|
|
- AEditorClass: TFPReportElementEditorClass);
|
|
|
|
|
|
+Procedure TFPReportLayouter.InitBandList(aPage : TFPReportCustomPage; aDataLoop : TFPReportData);
|
|
|
|
|
|
Var
|
|
Var
|
|
- I : integer;
|
|
|
|
|
|
+ I : Integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfElementClass(aReportElementClass);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Mappings[i].EditorClass:=AEditorClass
|
|
|
|
- else
|
|
|
|
- if AReportElementClass<>Nil then
|
|
|
|
- Raise EReportError.CreateFmt(SErrUnknownElementClass,[AReportElementClass.ClassName])
|
|
|
|
|
|
+ // Create a list of band that need to be printed as page headers
|
|
|
|
+ PopulateHeaderList(aPage);
|
|
|
|
+ // Create a list of bands that need to be printed as page footers
|
|
|
|
+ PopulateFooterList(aPage);
|
|
|
|
+ // find Bands of interest
|
|
|
|
+ ClearBandList;
|
|
|
|
+ for I := 0 to aPage.BandCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := aPage.Bands[I];
|
|
|
|
+ if (lBand is TFPReportCustomDataBand) then
|
|
|
|
+ begin
|
|
|
|
+ if TFPReportCustomDataBand(lBand).Data = aDataLoop then
|
|
|
|
+ begin
|
|
|
|
+ { Do a quick sanity check - we may not have more than one master data band }
|
|
|
|
+ if FFoundDataBand then
|
|
|
|
+ ReportError(SErrMultipleDataBands);
|
|
|
|
+ Report.FBands.Add(lBand);
|
|
|
|
+ FFoundDataBand := True;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ continue; // it's a databand but not for the current data loop
|
|
|
|
+ end
|
|
else
|
|
else
|
|
- Raise EReportError.CreateFmt(SErrUnknownElementClass,['Nil']);
|
|
|
|
-end;
|
|
|
|
|
|
+ begin
|
|
|
|
+ if (lBand is TFPReportCustomGroupHeaderBand) and (TFPReportCustomGroupHeaderBand(lBand).GroupHeader <> nil) then
|
|
|
|
+ continue; // this is not the toplevel GroupHeader Band.
|
|
|
|
+ if lBand is TFPReportCustomGroupFooterBand then
|
|
|
|
+ continue; // we will get the Footer from the GroupHeaderBand.FooterBand property
|
|
|
|
+ Report.FBands.Add(aPage.Bands[I]); { all non-data bands are of interest }
|
|
|
|
+ end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.UnRegisterEditorClass(const AElementName: string; AEditorClass: TFPReportElementEditorClass);
|
|
|
|
|
|
+ if lBand is TFPReportCustomGroupHeaderBand then
|
|
|
|
+ begin
|
|
|
|
+ FHasGroupBand := True;
|
|
|
|
+ if Assigned(TFPReportCustomGroupHeaderBand(lBand).GroupFooter) then
|
|
|
|
+ FHasGroupFooter := True;
|
|
|
|
+ end
|
|
|
|
+ else if lBand is TFPReportCustomSummaryBand then
|
|
|
|
+ FHasReportSummaryBand := True;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
-Var
|
|
|
|
- I : integer;
|
|
|
|
|
|
+Procedure TFPReportLayouter.CheckNewOrOverFlow(CheckMulticolumn: Boolean = True);
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfElementName(aElementName);
|
|
|
|
- if I<>-1 then
|
|
|
|
- if Mappings[i].EditorClass=AEditorClass then
|
|
|
|
- Mappings[i].EditorClass:=nil;
|
|
|
|
|
|
+ if CheckMulticolumn and FNewColumn then
|
|
|
|
+ StartNewColumn;
|
|
|
|
+ if FNewPage then
|
|
|
|
+ StartNewPage;
|
|
|
|
+ { handle overflowed bands. Remove from old page, add to new page }
|
|
|
|
+ if FOverflowed then
|
|
|
|
+ HandleOverflowed;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.UnRegisterEditorClass(AReportElementClass: TFPReportElementClass;
|
|
|
|
- AEditorClass: TFPReportElementEditorClass);
|
|
|
|
|
|
+Procedure TFPReportLayouter.RunDataLoop(lPageIdx : Integer; lPageData : TFPReportData);
|
|
|
|
+
|
|
Var
|
|
Var
|
|
I : integer;
|
|
I : integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfElementClass(aReportElementClass);
|
|
|
|
- if I<>-1 then
|
|
|
|
- if Mappings[i].EditorClass=AEditorClass then
|
|
|
|
- Mappings[i].EditorClass:=nil;
|
|
|
|
|
|
+ if not lPageData.IsOpened then
|
|
|
|
+ lPageData.Open;
|
|
|
|
+ if IsFirstPass then
|
|
|
|
+ begin
|
|
|
|
+ Report.InitializeExpressionVariables(Pages[lPageIdx], lPageData);
|
|
|
|
+ Report.CacheMemoExpressions(lPageIdx, lPageData);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Report.Variables.InitSecondPass;
|
|
|
|
+ lPageData.First;
|
|
|
|
+ InitBandList(Pages[lPageIdx],lPageData);
|
|
|
|
+ while not lPageData.EOF do
|
|
|
|
+ begin
|
|
|
|
+ if Report.TwoPass and IsFirstPass then
|
|
|
|
+ Report.Variables.BuildAggregates;
|
|
|
|
+ CheckNewOrOverFlow(True);
|
|
|
|
+ if FHasGroupBand then
|
|
|
|
+ HandleGroupBands;
|
|
|
|
+ { handle overflow possibly caused by Group Band just processed. }
|
|
|
|
+ if FOverflowed then
|
|
|
|
+ Continue;
|
|
|
|
+ HandleDataBands;
|
|
|
|
+ lPageData.Next;
|
|
|
|
+ end;
|
|
|
|
+ if not (Report.TwoPass and IsFirstPass) then
|
|
|
|
+ begin
|
|
|
|
+ CheckNewOrOverFlow(True);
|
|
|
|
+ // only print if we actually had data
|
|
|
|
+ if (lPageData.RecNo > 1) then
|
|
|
|
+ begin
|
|
|
|
+ for I := 0 to Report.FBands.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[I]);
|
|
|
|
+ if lBand is TFPReportCustomDataBand then
|
|
|
|
+ if TFPReportCustomDataBand(lBand).FooterBand <> nil then
|
|
|
|
+ ShowDataFooterBand(TFPReportCustomDataBand(lBand).FooterBand);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ { Process ColumnFooterBand as needed }
|
|
|
|
+ if FMultiColumn then
|
|
|
|
+ begin
|
|
|
|
+ FCurrentRTColumnFooterBand:= TFPReportCustomColumnFooterBand(FFooterList.Find(TFPReportCustomColumnFooterBand));
|
|
|
|
+ if Assigned(FCurrentRTColumnFooterBand) then
|
|
|
|
+ ShowColumnFooterBand(FRTPage, FCurrentRTColumnFooterBand);
|
|
|
|
+ end;
|
|
|
|
+ { ColumnFooter could have caused a new column or page }
|
|
|
|
+ CheckNewOrOverFlow(True);
|
|
|
|
+ if FHasGroupFooter then
|
|
|
|
+ HandleGroupFooters;
|
|
|
|
+ end;
|
|
|
|
+ lPageData.Close;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.RegisterClass(const AElementName: string; AReportElementClass: TFPReportElementClass);
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
-begin
|
|
|
|
- I:=IndexOfElementName(AElementName);
|
|
|
|
- if I<>-1 then exit;
|
|
|
|
- FList.Add(TFPReportClassMapping.Create(AElementName, AReportElementClass));
|
|
|
|
-end;
|
|
|
|
|
|
+Procedure TFPReportLayouter.InitPass(aPassIdx : Integer);
|
|
|
|
|
|
-function TFPReportElementFactory.CreateInstance(const AElementName: string; AOwner: TComponent): TFPReportElement;
|
|
|
|
-var
|
|
|
|
- i: integer;
|
|
|
|
begin
|
|
begin
|
|
- Result := nil;
|
|
|
|
- for i := 0 to FList.Count - 1 do
|
|
|
|
- begin
|
|
|
|
- if SameText(Mappings[I].MappingName, AElementName) then
|
|
|
|
- begin
|
|
|
|
- Result := Mappings[I].ReportElementClass.Create(AOwner);
|
|
|
|
- Break; //==>
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
- if Result = nil then
|
|
|
|
- ReportError(SErrRegisterUnknownElement, [AElementName]);
|
|
|
|
|
|
+ Report.FIsFirstPass := (aPassIdx = 1);
|
|
|
|
+ Report.EmptyRTObjects;
|
|
|
|
+ FHeaderList.Clear;
|
|
|
|
+ FFooterList.Clear;
|
|
|
|
+ ClearBandList;
|
|
|
|
+ InitRTCurPageIdx;
|
|
|
|
+ FOverflowed := False;
|
|
|
|
+ FHasGroupBand := False;
|
|
|
|
+ FHasGroupFooter := False;
|
|
|
|
+ FHasReportSummaryBand := False;
|
|
|
|
+ FDataHeaderPrinted := False;
|
|
|
|
+ FLastGroupCondition := '';
|
|
|
|
+ InitPageNumber;
|
|
|
|
+ FDataLevelStack := 0;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.FindEditorClassForInstance(AInstance: TFPReportElement): TFPReportElementEditorClass;
|
|
|
|
|
|
+Procedure TFPReportLayouter.InitDesignPage(aPageIdx : integer);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- if AInstance<>Nil then
|
|
|
|
- Result:=FindEditorClassForInstance(TFPReportElementClass(Ainstance.ClassType))
|
|
|
|
- else
|
|
|
|
- Result:=Nil;
|
|
|
|
|
|
+ FPageIdx:=aPageIdx;
|
|
|
|
+ FNewPage := True;
|
|
|
|
+ FNewGroupHeader := True;
|
|
|
|
+ FCurrentColumn := 1;
|
|
|
|
+ FMultiColumn := Pages[aPageIdx].ColumnCount > 1;
|
|
|
|
+ FNewColumn := False;
|
|
|
|
+ FPageFooterYPos := -1;
|
|
|
|
+ PageNumberPerDesignerPage := 0;
|
|
|
|
+ FFoundDataBand := False;
|
|
|
|
+ FLastDsgnDataBand := nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TFPReportElementFactory.FindEditorClassForInstance(AClass: TFPReportElementClass): TFPReportElementEditorClass;
|
|
|
|
|
|
+Procedure TFPReportLayouter.HandleReportSummaries;
|
|
|
|
|
|
Var
|
|
Var
|
|
- I : Integer;
|
|
|
|
|
|
+ I : integer;
|
|
|
|
+ lBand : TFPReportCustomBand;
|
|
|
|
|
|
begin
|
|
begin
|
|
- I:=IndexOfElementClass(AClass);
|
|
|
|
- if I<>-1 then
|
|
|
|
- Result:=Mappings[I].EditorClass
|
|
|
|
- else
|
|
|
|
- Result:=nil;
|
|
|
|
|
|
+ for I:=0 to Report.FBands.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[I]);
|
|
|
|
+ if lBand is TFPReportCustomSummaryBand then
|
|
|
|
+ begin
|
|
|
|
+ { We are allowed to use design Layout.Height instead of RTLayout.Height
|
|
|
|
+ because this band appears outside the data loop, thus memos will not
|
|
|
|
+ grow. Height of the band is as it was at design time. }
|
|
|
|
+ if (TFPReportCustomSummaryBand(lBand).StartNewPage) or (lBand.Layout.Height > FSpaceLeft) then
|
|
|
|
+ StartNewPage;
|
|
|
|
+ { Restore reference to lDsgnBand and SummaryBand, because StartNewPage
|
|
|
|
+ could have changed the value of lDsgnBand. }
|
|
|
|
+ lBand := TFPReportCustomBand(Report.FBands[I]);
|
|
|
|
+ CommonRuntimeBandProcessing(lBand);
|
|
|
|
+ UpdateSpaceRemaining(FRTBand);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TFPReportElementFactory.AssignReportElementTypes(AStrings: TStrings);
|
|
|
|
|
|
+procedure TFPReportLayouter.RecalcBandLayout(ABand: TFPReportCustomBand);
|
|
|
|
+
|
|
var
|
|
var
|
|
i: integer;
|
|
i: integer;
|
|
|
|
+ e: TFPReportElement;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- AStrings.Clear;
|
|
|
|
- for i := 0 to FList.Count - 1 do
|
|
|
|
- AStrings.Add(Mappings[I].MappingName);
|
|
|
|
|
|
+ for i := ABand.ChildCount-1 downto 0 do
|
|
|
|
+ begin
|
|
|
|
+ e := ABand.Child[i];
|
|
|
|
+ if not e.EvaluateVisibility then
|
|
|
|
+ begin
|
|
|
|
+ ABand.RemoveChild(e);
|
|
|
|
+ FreeAndNil(e);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportCustomDataHeaderBand }
|
|
|
|
|
|
+Procedure TFPReportLayouter.DoExecute;
|
|
|
|
|
|
-function TFPReportCustomDataHeaderBand.GetReportBandName: string;
|
|
|
|
-begin
|
|
|
|
- Result := 'DataHeaderBand';
|
|
|
|
-end;
|
|
|
|
|
|
+Var
|
|
|
|
+ lPageIdx : Integer;
|
|
|
|
+ lPassIdx : Integer;
|
|
|
|
+ lPageData: TFPReportData;
|
|
|
|
+ aPassCount : Integer;
|
|
|
|
|
|
-class function TFPReportCustomDataHeaderBand.ReportBandType: TFPReportBandType;
|
|
|
|
begin
|
|
begin
|
|
- Result:=btDataHeader;
|
|
|
|
|
|
+ if Report.TwoPass then
|
|
|
|
+ aPassCount := 2
|
|
|
|
+ else
|
|
|
|
+ aPassCount := 1;
|
|
|
|
+ // Pass loop
|
|
|
|
+ for lPassIdx := 1 to aPassCount do
|
|
|
|
+ begin
|
|
|
|
+ InitPass(lPassIdx);
|
|
|
|
+ // Design page loop
|
|
|
|
+ for lPageIdx := 0 to Report.PageCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ lPageData:=Pages[lPageIdx].Data;
|
|
|
|
+ Report.FPageData:=lPagedata;
|
|
|
|
+ InitDesignPage(lPageIdx);
|
|
|
|
+ if Assigned(lPageData) then
|
|
|
|
+ RunDataLoop(lPageIdx,lPageData);
|
|
|
|
+ if FHasReportSummaryBand then
|
|
|
|
+ HandleReportSummaries;
|
|
|
|
+ end;
|
|
|
|
+ SetPageCount(RTObjects.Count);
|
|
|
|
+ end;
|
|
|
|
+ // DoProcessPass only substitutes cPageCountMarker by FPageCount.
|
|
|
|
+ // It is pointless to do so if we're doing 2 passes anyway
|
|
|
|
+ if Report.UsePageCountMarker then
|
|
|
|
+ Report.DoProcessTwoPass;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TFPReportCustomDataFooterBand }
|
|
|
|
|
|
+procedure TFPReportLayouter.Execute(aReport: TFPCustomReport);
|
|
|
|
|
|
-function TFPReportCustomDataFooterBand.GetReportBandName: string;
|
|
|
|
begin
|
|
begin
|
|
- Result := 'DataFooterBand';
|
|
|
|
|
|
+ FHeaderList := Nil;
|
|
|
|
+ FFooterList := Nil;
|
|
|
|
+ FmyReport:=AReport;
|
|
|
|
+ try
|
|
|
|
+ FHeaderList := TBandList.Create;
|
|
|
|
+ FFooterList := TBandList.Create;
|
|
|
|
+ DoExecute;
|
|
|
|
+ finally
|
|
|
|
+ FreeAndNil(FHeaderList);
|
|
|
|
+ FreeAndNil(FFooterList);
|
|
|
|
+ FMyReport:=Nil; // Don't free :)
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TFPReportCustomDataFooterBand.ReportBandType: TFPReportBandType;
|
|
|
|
-begin
|
|
|
|
- Result:=btDataFooter;
|
|
|
|
-end;
|
|
|
|
|
|
|
|
{ A function borrowed from fpGUI Toolkit. }
|
|
{ A function borrowed from fpGUI Toolkit. }
|
|
function fpgDarker(const AColor: TFPReportColor; APercent: Byte): TFPReportColor;
|
|
function fpgDarker(const AColor: TFPReportColor; APercent: Byte): TFPReportColor;
|