{*******************************************************************} { } { Developer Express Visual Component Library } { ExpressPrinting System COMPONENT SUITE } { } { Copyright (C) 1998-2009 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSPRINTINGSYSTEM AND } { ALL ACCOMPANYING VCL CONTROLS AS PART OF AN } { EXECUTABLE PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {*******************************************************************} unit dxPSHFLibrary; interface uses Windows, SysUtils, Classes, Graphics, TypInfo, cxGeometry, cxClasses, cxGraphics, dxPSGlbl, dxPSUtl, dxPSImgs, dxPSRes, dxPSCore, cxDrawTextUtils, dxPrnPg, dxPSReportRenderCanvas; type TdxHFFunctionLibrary = class; TdxHFFunctionFormatObjectClass = class of TdxHFFunctionFormatObject; { TdxHFFunctionFormatObject } TdxHFFunctionFormatObject = class(TObject) private FCurrentPage: Integer; FDateFormat: string; FDateTime: TDateTime; FMachineName: string; FPageNumberFormat: TdxPageNumberFormat; FStartPageIndex: Integer; FTimeFormat: string; FTotalPages: Integer; FUserName: string; protected procedure Initialize; virtual; public constructor Create; virtual; property CurrentPage: Integer read FCurrentPage write FCurrentPage; property DateFormat: string read FDateFormat write FDateFormat; property DateTime: TDateTime read FDateTime write FDateTime; property MachineName: string read FMachineName write FMachineName; property PageNumberFormat: TdxPageNumberFormat read FPageNumberFormat write FPageNumberFormat; property StartPageIndex: Integer read FStartPageIndex write FStartPageIndex; property TimeFormat: string read FTimeFormat write FTimeFormat; property TotalPages: Integer read FTotalPages write FTotalPages; property UserName: string read FUserName write FUserName; end; { TdxHFFunctionCustomCategory } TdxHFFunctionCustomCategory = class(TObject); TdxHFFunctionCustomCategoryClass = class of TdxHFFunctionCustomCategory; TdxHFFunctionAuthenticationCategory = class(TdxHFFunctionCustomCategory); TdxHFFunctionDateTimeCategory = class(TdxHFFunctionCustomCategory); TdxHFFunctionImagesCategory = class(TdxHFFunctionCustomCategory); TdxHFFunctionPagesCategory = class(TdxHFFunctionCustomCategory); { TdxHFCustomFunction } TdxHFConvertFunction = function (const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; TdxHFCustomFunctionClass = class of TdxHFCustomFunction; TdxHFCustomFunction = class(TPersistent) private FGlyph: TcxBitmap; FHint: string; FTemplateString: string; procedure SetGlyph(Value: TcxBitmap); procedure SetTemplateString(const Value: string); protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; virtual; public constructor Create; virtual; destructor Destroy; override; procedure Assign(Source: TPersistent); override; function DoProcess(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; virtual; class function FunctionClass: TdxHFCustomFunctionClass; class function GetCategory: TdxHFFunctionCustomCategoryClass; virtual; class function GetName: string; virtual; // property Glyph: TcxBitmap read FGlyph write SetGlyph; property Hint: string read FHint write FHint; property TemplateString: string read FTemplateString write SetTemplateString; end; { TdxHFPagesFunctions } TdxHFPagesFunctions = class(TdxHFCustomFunction) public class function GetCategory: TdxHFFunctionCustomCategoryClass; override; end; { TdxHFPageNumberFunction } TdxHFPageNumberFunction = class(TdxHFPagesFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFTotalPagesFunction } TdxHFTotalPagesFunction = class(TdxHFPagesFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFPageOfPagesFunction } TdxHFPageOfPagesFunction = class(TdxHFPagesFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFAuthenticationFunctions } TdxHFAuthenticationFunctions = class(TdxHFCustomFunction) public class function GetCategory: TdxHFFunctionCustomCategoryClass; override; end; { TdxHFMachineNameFunction } TdxHFMachineNameFunction = class(TdxHFAuthenticationFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFUserNameFunction } TdxHFUserNameFunction = class(TdxHFAuthenticationFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFDateTimeFunctions } TdxHFDateTimeFunctions = class(TdxHFCustomFunction) public class function GetCategory: TdxHFFunctionCustomCategoryClass; override; end; { TdxHFDateTimeFunction } TdxHFDateTimeFunction = class(TdxHFDateTimeFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFDateFunction } TdxHFDateFunction = class(TdxHFDateTimeFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFTimeFunction } TdxHFTimeFunction = class(TdxHFDateTimeFunctions) protected function ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; override; public constructor Create; override; class function GetName: string; override; end; { TdxHFFunctionLibrary } TdxHFFunctionEnumProc = procedure(Sender: TdxHFFunctionLibrary; const AHFFunction: TdxHFCustomFunction) of object; TdxHFFunctionLibraryClass = class of TdxHFFunctionLibrary; TdxHFFunctionLibrary = class(TPersistent) private FItems: TList; function GetCount: Integer; function GetFunction(Index: Integer): TdxHFCustomFunction; function GetFunctionByClass(FunctionClass: TdxHFCustomFunctionClass): TdxHFCustomFunction; procedure SetFunction(Index: Integer; Value: TdxHFCustomFunction); procedure SetFunctionByClass(FunctionClass: TdxHFCustomFunctionClass; Value: TdxHFCustomFunction); public constructor Create; virtual; destructor Destroy; override; function Add(AFunctionClass: TdxHFCustomFunctionClass): TdxHFCustomFunction; procedure Assign(Source: TPersistent); override; procedure Clear; procedure Delete(AIndex: Integer); procedure Enumerate(AProc: TdxHFFunctionEnumProc); virtual; procedure GetFunctions(AStrings: TStrings); procedure GetFunctionsByCategory(ACategory: TdxHFFunctionCustomCategoryClass; AStrings: TStrings); function IndexOf(const ATemplateString: string): Integer; function IndexOfByName(const AFunctionName: string): Integer; function IndexOfByClass(AFunctionClass: TdxHFCustomFunctionClass): Integer; function ProcessString(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; virtual; // property Count: Integer read GetCount; property Funcs[Index: Integer]: TdxHFCustomFunction read GetFunction write SetFunction; default; property FuncsByClass[FunctionClass: TdxHFCustomFunctionClass]: TdxHFCustomFunction read GetFunctionByClass write SetFunctionByClass; end; { TdxHFReportCellBuilder } TdxHFReportCellBuilder = class(TObject) protected procedure AlignDataItems(ACell: TdxReportCell; AAlignment: TcxTextAlignY); procedure CalculateTitlePartSize(ACell: TdxReportCell; ACanvas: TdxPSReportRenderCustomCanvas); public procedure Build(ACanvas: TdxPSReportRenderCustomCanvas; AHost: TdxReportCells; const R: TRect; ATitleParts: TdxPageTitleParts; APageObject: TCustomdxPageObject; AReverseTitles: Boolean); virtual; procedure PlaceTitleParts(ACanvas: TdxPSReportRenderCustomCanvas; AHostCell: TdxReportCell; R: TRect; APageObject: TCustomdxPageObject); procedure PopulateCells(AParentCell: TdxReportCell; AHost: TdxReportCells; ATextAlignX: TcxTextAlignX; ATitlePart: TdxPageTitlePart; APageObject: TCustomdxPageObject); overload; procedure PopulateCells(AParentCell: TdxReportCell; AHost: TdxReportCells; const Source: string; ATextAlignX: TcxTextAlignX; ATextAlignY: TcxTextAlignY; APageObject: TCustomdxPageObject; AFormatObject: TdxHFFunctionFormatObject); overload; virtual; end; { TdxStandardHFFunctionLibrary } TdxStandardHFFunctionLibrary = class(TdxHFFunctionLibrary) protected procedure AddStandardFunctions; virtual; public constructor Create; override; end; const dxFunctionDelimiters: array[Boolean] of Char = ('[', ']'); dxFunctionIndexSeparator = '='; dxHFFunctionSeparator = ','; var dxHFFunctionLibrary: TdxHFFunctionLibrary = nil; dxHFFormatObject: TdxHFFunctionFormatObject = nil; function dxProcessHFString(const Source: string): string; procedure dxGetHFFunctionsList(AStrings: TStrings); procedure dxGetHFFunctionsListByCategory(ACategory: TdxHFFunctionCustomCategoryClass; AStrings: TStrings); procedure dxPSSplitAutoHFTextEntry(Source: string; var APart1, APart2, APart3: string); implementation uses Types, StrUtils, dxPgsDlg; type TdxHFFunctionPlaceInfo = packed record Index: Integer; Left, Right: Integer; Name: string; end; { TdxReportCellTitlePartText } TdxReportCellTitlePartText = class(TdxReportCellText) private FLines: TStrings; protected function GetText: string; override; procedure SetText(const Value: string); override; public constructor Create(AParent: TdxReportCell); override; destructor Destroy; override; function MeasureContentWidth(ACanvas: TdxPSReportRenderCustomCanvas): Integer; override; // property Lines: TStrings read FLines; end; { TdxHFTemplateExpander } TdxHFTemplateExpander = class(TObject) private FCursorIndex: Integer; FStr: string; function GetStrLength: Integer; procedure SetCursorIndex(AValue: Integer); public constructor Create(const AStr: string); function GetFuncInfo(var AInfo: TdxHFFunctionPlaceInfo): Boolean; procedure Replace(const AInfo: TdxHFFunctionPlaceInfo; const AValue: string); // property CursorIndex: Integer read FCursorIndex write SetCursorIndex; property Str: string read FStr; property StrLength: Integer read GetStrLength; end; function dxFormatPageNumber(ANumber: Integer; AFormat: TdxPageNumberFormat): string; begin case AFormat of pnfChars, pnfUpperChars: Result := Int2Chars(ANumber, AFormat = pnfUpperChars); pnfRoman, pnfUpperRoman: Result := Int2Roman(ANumber, AFormat = pnfUpperRoman); else Result := IntToStr(ANumber); end; end; procedure dxPSSplitAutoHFTextEntry(Source: string; var APart1, APart2, APart3: string); function DoExtract(var Source: string): string; var P: Integer; begin P := Pos(dxHFFunctionSeparator, Source); if P = 0 then begin Result := Source; P := Length(Source); end else Result := Copy(Source, 1, P - 1); Delete(Source, 1, P); Result := Trim(Result); end; begin APart1 := ''; APart2 := ''; APart3 := ''; APart1 := DoExtract(Source); if Source <> '' then APart2 := DoExtract(Source); if Source <> '' then APart3 := DoExtract(Source); end; function dxProcessHFString(const Source: string): string; begin if Assigned(dxHFFunctionLibrary) then Result := dxHFFunctionLibrary.ProcessString(Source, dxHFFormatObject) else Result := Source; end; procedure dxGetHFFunctionsList(AStrings: TStrings); begin if Assigned(dxHFFunctionLibrary) then dxHFFunctionLibrary.GetFunctions(AStrings); end; procedure dxGetHFFunctionsListByCategory( ACategory: TdxHFFunctionCustomCategoryClass; AStrings: TStrings); begin if Assigned(dxHFFunctionLibrary) then dxHFFunctionLibrary.GetFunctionsByCategory(ACategory, AStrings); end; { TdxHFReportCellBuilder } procedure TdxHFReportCellBuilder.AlignDataItems( ACell: TdxReportCell; AAlignment: TcxTextAlignY); var ADataItem: TAbstractdxReportCellData; I: Integer; begin for I := 0 to ACell.DataItemCount - 1 do begin ADataItem := ACell.DataItems[I]; case AAlignment of taBottom: ADataItem.Top := ACell.Height - ADataItem.Height; taCenterY: ADataItem.Top := (ACell.Height - ADataItem.Height) div 2; else ADataItem.Top := 0; end; end; end; procedure TdxHFReportCellBuilder.Build(ACanvas: TdxPSReportRenderCustomCanvas; AHost: TdxReportCells; const R: TRect; ATitleParts: TdxPageTitleParts; APageObject: TCustomdxPageObject; AReverseTitles: Boolean); const ReverseTitlesMap: array[Boolean, TdxPageTitlePart] of TdxPageTitlePart = ((tpLeft, tpCenter, tpRight), (tpRight, tpCenter, tpLeft)); TextAlignMap: array[TdxPageTitlePart] of TcxTextAlignX = (taLeft, taCenterX, taRight); var ACell: TdxReportCell; AIndex: TdxPageTitlePart; begin for AIndex := Low(TdxPageTitlePart) to High(TdxPageTitlePart) do begin ACell := AHost.Cells.AddCell; ACell.ClipChildren := True; if AIndex in ATitleParts then begin PopulateCells(ACell, AHost, TextAlignMap[AIndex], ReverseTitlesMap[AReverseTitles, AIndex], APageObject); end; CalculateTitlePartSize(ACell, ACanvas); end; PlaceTitleParts(ACanvas, AHost.Cells, R, APageObject); end; procedure TdxHFReportCellBuilder.CalculateTitlePartSize( ACell: TdxReportCell; ACanvas: TdxPSReportRenderCustomCanvas); var ADataItem: TAbstractdxReportCellData; I, AWidth, AHeight: Integer; begin AWidth := 0; AHeight := 0; for I := 0 to ACell.DataItemCount - 1 do begin ADataItem := ACell.DataItems[I]; ADataItem.Width := ADataItem.MeasureWidth(ACanvas); ADataItem.Height := ADataItem.MeasureHeight(ACanvas); ADataItem.Offset(AWidth, 0); Inc(AWidth, ADataItem.Width); AHeight := Max(AHeight, ADataItem.Height); end; ACell.Height := AHeight; ACell.Width := AWidth; end; procedure TdxHFReportCellBuilder.PlaceTitleParts( ACanvas: TdxPSReportRenderCustomCanvas; AHostCell: TdxReportCell; R: TRect; APageObject: TCustomdxPageObject); function CalculateTitlePartPosition( AWidth: Integer; ATitlePart: TdxPageTitlePart; var R: TRect): TRect; begin case ATitlePart of tpRight: begin Result := cxRect(R.Right - AWidth, R.Top, R.Right, R.Bottom); Result.Left := Max(Result.Left, R.Left); R.Right := Result.Left; end; tpCenter: begin Result := cxRectCenter(R, AWidth, cxRectHeight(R)); Result.Right := Min(Result.Right, R.Right); Result.Left := Max(Result.Left, R.Left); R := cxNullRect; end; else begin Result := cxRect(R.Left, R.Top, R.Left + AWidth, R.Bottom); R.Left := Result.Right; end; end; end; procedure PlaceTitlePart(APartCell: TdxReportCell; ATitlePart: TdxPageTitlePart); begin APartCell.BoundsRect := CalculateTitlePartPosition(APartCell.Width, ATitlePart, R); AlignDataItems(APartCell, APageObject.TextAlignY[ATitlePart]); end; begin AHostCell.BoundsRect := cxRectOffset(R, R.TopLeft, False); PlaceTitlePart(AHostCell.Cells[0], tpLeft); PlaceTitlePart(AHostCell.Cells[2], tpRight); PlaceTitlePart(AHostCell.Cells[1], tpCenter); end; procedure TdxHFReportCellBuilder.PopulateCells(AParentCell: TdxReportCell; AHost: TdxReportCells; ATextAlignX: TcxTextAlignX; ATitlePart: TdxPageTitlePart; APageObject: TCustomdxPageObject); begin PopulateCells(AParentCell, AHost, APageObject.Titles[ATitlePart].Text, ATextAlignX, APageObject.TextAlignY[ATitlePart], APageObject, dxHFFormatObject); end; procedure TdxHFReportCellBuilder.PopulateCells(AParentCell: TdxReportCell; AHost: TdxReportCells; const Source: string; ATextAlignX: TcxTextAlignX; ATextAlignY: TcxTextAlignY; APageObject: TCustomdxPageObject; AFormatObject: TdxHFFunctionFormatObject); procedure AddTextCell(const AText: string); var ATextCell: TdxReportCellTitlePartText; begin if AText <> '' then begin ATextCell := TdxReportCellTitlePartText(AParentCell.AddDataItem(TdxReportCellTitlePartText)); ATextCell.FontIndex := AHost.GetIndexByFont(APageObject.Font); ATextCell.TextAlignX := ATextAlignX; ATextCell.TextAlignY := ATextAlignY; ATextCell.Text := AText; end; end; procedure AddImageCell(AImageIndex: Integer); begin // todo end; var AExpander: TdxHFTemplateExpander; AFuncInfo: TdxHFFunctionPlaceInfo; AFunction: TdxHFCustomFunction; AIndex, ATextOffset: Integer; begin ATextOffset := 1; AExpander := TdxHFTemplateExpander.Create(Source); try while AExpander.GetFuncInfo(AFuncInfo) do begin AIndex := dxHFFunctionLibrary.IndexOf(AFuncInfo.Name); if AIndex >= 0 then begin AFunction := dxHFFunctionLibrary.Funcs[AIndex]; if AFunction.GetCategory.InheritsFrom(TdxHFFunctionImagesCategory) then begin AddTextCell(Copy(AExpander.Str, ATextOffset, AFuncInfo.Left - ATextOffset)); AddImageCell(AFuncInfo.Index); ATextOffset := AFuncInfo.Right + 1; end else AExpander.Replace(AFuncInfo, AFunction.DoProcess(AFuncInfo.Name, AFormatObject)); end; end; AddTextCell(Copy(AExpander.Str, ATextOffset, AExpander.StrLength - ATextOffset + 1)); finally AExpander.Free; end; end; { TdxHFFunctionFormatObject } constructor TdxHFFunctionFormatObject.Create; begin inherited Create; Initialize; end; procedure TdxHFFunctionFormatObject.Initialize; begin FDateTime := Now; FCurrentPage := 1; FDateFormat := LongDateFormat; FMachineName := dxPSUtl.GetMachineName; FPageNumberFormat := pnfNumeral; FTimeFormat := LongTimeFormat; FTotalPages := 1; FUserName := dxPSUtl.GetUserName; end; { TdxHFCustomFunction } constructor TdxHFCustomFunction.Create; begin inherited Create; FGlyph := TcxBitmap.Create; end; destructor TdxHFCustomFunction.Destroy; begin FreeAndNil(FGlyph); inherited Destroy; end; procedure TdxHFCustomFunction.Assign(Source: TPersistent); begin if Source is TdxHFCustomFunction then begin TemplateString := TdxHFCustomFunction(Source).TemplateString; Glyph := TdxHFCustomFunction(Source).Glyph; Hint := TdxHFCustomFunction(Source).Hint; end else inherited Assign(Source); end; class function TdxHFCustomFunction.FunctionClass: TdxHFCustomFunctionClass; begin Result := TdxHFCustomFunctionClass(GetTypeData(ClassInfo)^.ClassType); end; function TdxHFCustomFunction.DoProcess(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin if AFormatObject <> nil then Result := ConvertFunc(Source, AFormatObject) else Result := Source; end; procedure TdxHFCustomFunction.SetTemplateString(const Value: string); begin FTemplateString := Value; if Length(FTemplateString) > 0 then begin if FTemplateString[1] <> dxFunctionDelimiters[False] then FTemplateString := dxFunctionDelimiters[False] + FTemplateString; if FTemplateString[Length(FTemplateString)] <> dxFunctionDelimiters[True] then FTemplateString := FTemplateString + dxFunctionDelimiters[True]; end; end; procedure TdxHFCustomFunction.SetGlyph(Value: TcxBitmap); begin Glyph.Assign(Value); end; class function TdxHFCustomFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameUnknown); end; class function TdxHFCustomFunction.GetCategory: TdxHFFunctionCustomCategoryClass; begin Result := TdxHFFunctionCustomCategory; end; function TdxHFCustomFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := Source; end; { TdxHFPagesFunctions } class function TdxHFPagesFunctions.GetCategory: TdxHFFunctionCustomCategoryClass; begin Result := TdxHFFunctionPagesCategory; end; { TdxHFPageNumberFunction } constructor TdxHFPageNumberFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_PAGENUMBER); Hint := cxGetResourceString(@sdxHFFunctionHintPageNumber); TemplateString := cxGetResourceString(@sdxHFFunctionTemplatePageNumber); end; function TdxHFPageNumberFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := dxFormatPageNumber( AFormatObject.StartPageIndex + AFormatObject.CurrentPage - 1, AFormatObject.PageNumberFormat); end; class function TdxHFPageNumberFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNamePageNumber); end; { TdxHFTotalPagesFunction } constructor TdxHFTotalPagesFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_TOTALPAGES); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateTotalPages); Hint := cxGetResourceString(@sdxHFFunctionHintTotalPages); end; function TdxHFTotalPagesFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := dxFormatPageNumber( AFormatObject.StartPageIndex + AFormatObject.TotalPages - 1, AFormatObject.PageNumberFormat); end; class function TdxHFTotalPagesFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameTotalPages); end; { TdxHFPageOfPagesFunction } constructor TdxHFPageOfPagesFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_PAGENUMBEROFPAGES); TemplateString := cxGetResourceString(@sdxHFFunctionTemplatePageOfPages); Hint := cxGetResourceString(@sdxHFFunctionHintPageOfPages); end; function TdxHFPageOfPagesFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := dxFormatPageNumber( AFormatObject.CurrentPage + AFormatObject.StartPageIndex - 1, AFormatObject.PageNumberFormat) + ' ' + cxGetResourceString(@sdxOf) + ' ' + dxFormatPageNumber( AFormatObject.TotalPages + AFormatObject.StartPageIndex - 1, AFormatObject.PageNumberFormat); end; class function TdxHFPageOfPagesFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNamePageOfPages); end; { TdxHFAuthenticationFunctions } class function TdxHFAuthenticationFunctions.GetCategory: TdxHFFunctionCustomCategoryClass; begin Result := TdxHFFunctionAuthenticationCategory; end; { TdxHFMachineNameFunction } constructor TdxHFMachineNameFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_MACHINENAME); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateMachineName); Hint := cxGetResourceString(@sdxHFFunctionHintMachineName); end; function TdxHFMachineNameFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := AFormatObject.MachineName end; class function TdxHFMachineNameFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameMachineName); end; { TdxHFMachineNameFunction } constructor TdxHFUserNameFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_USERNAME); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateUserName); Hint := cxGetResourceString(@sdxHFFunctionHintUserName); end; function TdxHFUserNameFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := AFormatObject.UserName end; class function TdxHFUserNameFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameUserName); end; { TdxHFDateTimeFunctions } class function TdxHFDateTimeFunctions.GetCategory: TdxHFFunctionCustomCategoryClass; begin Result := TdxHFFunctionDateTimeCategory; end; { TdxHFDateTimeFunction } constructor TdxHFDateTimeFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_DATETIME); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateDateTime); Hint := cxGetResourceString(@sdxHFFunctionHintDateTime); end; function TdxHFDateTimeFunction.ConvertFunc( const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := GetFormatedDate(AFormatObject.DateTime, AFormatObject.DateFormat) + ' ' + GetFormatedTime(AFormatObject.DateTime, AFormatObject.TimeFormat); end; class function TdxHFDateTimeFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameDateTime); end; { TdxHFDateFunction } constructor TdxHFDateFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_DATE); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateDate); Hint := cxGetResourceString(@sdxHFFunctionHintDate); end; function TdxHFDateFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := GetFormatedDate(AFormatObject.DateTime, AFormatObject.DateFormat); end; class function TdxHFDateFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameDate); end; { TdxHFTimeFunction } constructor TdxHFTimeFunction.Create; begin inherited Create; Bitmap_LoadFromResourceName(Glyph, IDB_DXPSFUNCTION_TIME); TemplateString := cxGetResourceString(@sdxHFFunctionTemplateTime); Hint := cxGetResourceString(@sdxHFFunctionHintTime); end; function TdxHFTimeFunction.ConvertFunc(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; begin Result := GetFormatedTime(AFormatObject.DateTime, AFormatObject.TimeFormat); end; class function TdxHFTimeFunction.GetName: string; begin Result := cxGetResourceString(@sdxHFFunctionNameTime); end; { TdxHFFunctionLibrary } constructor TdxHFFunctionLibrary.Create; begin inherited Create; FItems := TList.Create; end; destructor TdxHFFunctionLibrary.Destroy; begin Clear; FreeAndNil(FItems); inherited Destroy; end; procedure TdxHFFunctionLibrary.Assign(Source: TPersistent); begin if Source is TdxHFFunctionLibrary then FItems.Assign(TdxHFFunctionLibrary(Source).FItems) else inherited Assign(Source); end; function TdxHFFunctionLibrary.Add(AFunctionClass: TdxHFCustomFunctionClass): TdxHFCustomFunction; begin Result := AFunctionClass.Create; FItems.Add(Result); end; procedure TdxHFFunctionLibrary.Clear; begin while Count > 0 do Delete(Count - 1); end; procedure TdxHFFunctionLibrary.Delete(AIndex: Integer); var AFunction: TdxHFCustomFunction; begin AFunction := Funcs[AIndex]; FItems.Delete(AIndex); FreeAndNil(AFunction); end; function TdxHFFunctionLibrary.IndexOf(const ATemplateString: string): Integer; begin for Result := 0 to Count - 1 do begin if dxSameText(Funcs[Result].TemplateString, ATemplateString) then Exit; end; Result := -1; end; function TdxHFFunctionLibrary.IndexOfByName(const AFunctionName: string): Integer; begin for Result := 0 to Count - 1 do begin if dxSameText(Funcs[Result].GetName, AFunctionName) then Exit; end; Result := -1; end; function TdxHFFunctionLibrary.IndexOfByClass(AFunctionClass: TdxHFCustomFunctionClass): Integer; begin for Result := 0 to Count - 1 do begin if Funcs[Result].FunctionClass = AFunctionClass then Exit; end; Result := -1; end; procedure TdxHFFunctionLibrary.GetFunctions(AStrings: TStrings); begin GetFunctionsByCategory(nil, AStrings); end; procedure TdxHFFunctionLibrary.GetFunctionsByCategory( ACategory: TdxHFFunctionCustomCategoryClass; AStrings: TStrings); var AFunction: TdxHFCustomFunction; I: Integer; begin AStrings.BeginUpdate; try for I := 0 to Count - 1 do begin AFunction := Funcs[I]; if (AFunction.GetCategory = ACategory) or (ACategory = nil) then AStrings.AddObject(AFunction.TemplateString, AFunction); end; finally AStrings.EndUpdate; end; end; procedure TdxHFFunctionLibrary.Enumerate(AProc: TdxHFFunctionEnumProc); var I: Integer; begin if Assigned(AProc) then begin for I := 0 to Count - 1 do AProc(Self, Funcs[I]); end; end; function TdxHFFunctionLibrary.ProcessString(const Source: string; const AFormatObject: TdxHFFunctionFormatObject): string; var AExpander: TdxHFTemplateExpander; AFuncInfo: TdxHFFunctionPlaceInfo; AIndex: Integer; begin AExpander := TdxHFTemplateExpander.Create(Source); try while AExpander.GetFuncInfo(AFuncInfo) do begin AIndex := IndexOf(AFuncInfo.Name); if AIndex >= 0 then begin AExpander.Replace(AFuncInfo, Funcs[AIndex].DoProcess(AFuncInfo.Name, AFormatObject)); end; end; Result := AExpander.Str; finally AExpander.Free; end; end; function TdxHFFunctionLibrary.GetCount: Integer; begin Result := FItems.Count; end; function TdxHFFunctionLibrary.GetFunction(Index: Integer): TdxHFCustomFunction; begin Result := TdxHFCustomFunction(FItems.Items[Index]); end; function TdxHFFunctionLibrary.GetFunctionByClass( FunctionClass: TdxHFCustomFunctionClass): TdxHFCustomFunction; var AIndex: Integer; begin AIndex := IndexOfByClass(FunctionClass); if AIndex >= 0 then Result := Funcs[AIndex] else Result := nil; end; procedure TdxHFFunctionLibrary.SetFunction(Index: Integer; Value: TdxHFCustomFunction); begin Funcs[Index].Assign(Value); end; procedure TdxHFFunctionLibrary.SetFunctionByClass( FunctionClass: TdxHFCustomFunctionClass; Value: TdxHFCustomFunction); var AIndex: Integer; begin AIndex := IndexOfByClass(FunctionClass); if AIndex <> -1 then Funcs[AIndex] := Value; end; { TdxStdHFFunctionLibrary } constructor TdxStandardHFFunctionLibrary.Create; begin inherited Create; AddStandardFunctions; end; procedure TdxStandardHFFunctionLibrary.AddStandardFunctions; begin Add(TdxHFPageNumberFunction); Add(TdxHFTotalPagesFunction); Add(TdxHFPageOfPagesFunction); Add(TdxHFDateTimeFunction); Add(TdxHFDateFunction); Add(TdxHFTimeFunction); Add(TdxHFUserNameFunction); Add(TdxHFMachineNameFunction); end; { TdxHFTemplateExpander } constructor TdxHFTemplateExpander.Create(const AStr: string); begin inherited Create; FCursorIndex := 1; FStr := AStr; end; procedure TdxHFTemplateExpander.Replace( const AInfo: TdxHFFunctionPlaceInfo; const AValue: string); begin Delete(FStr, AInfo.Left, AInfo.Right - AInfo.Left + 1); if AValue <> '' then Insert(' ' + AValue + ' ', FStr, AInfo.Left); CursorIndex := AInfo.Left + Length(AValue) + 2; end; function TdxHFTemplateExpander.GetStrLength: Integer; begin Result := Length(FStr); end; function TdxHFTemplateExpander.GetFuncInfo(var AInfo: TdxHFFunctionPlaceInfo): Boolean; function FindPart(AFinishPart: Boolean; var APosition: Integer): Boolean; begin APosition := PosEx(dxFunctionDelimiters[AFinishPart], Str, CursorIndex); Result := APosition > 0; if Result then CursorIndex := APosition; end; var AIndexPos, AIndexLength: Integer; begin Result := False; ZeroMemory(@AInfo, SizeOf(AInfo)); if CursorIndex <= StrLength then begin Result := FindPart(False, AInfo.Left) and FindPart(True, AInfo.Right); if Result then begin AInfo.Name := Copy(Str, AInfo.Left, AInfo.Right - AInfo.Left + 1); AIndexPos := Pos(dxFunctionIndexSeparator, AInfo.Name); if AIndexPos > 0 then begin AIndexLength := Length(AInfo.Name) - AIndexPos - 1; AInfo.Index := StrToIntDef(Copy(AInfo.Name, AIndexPos + 1, AIndexLength), 0); Delete(AInfo.Name, AIndexPos, AIndexLength + 1); end; CursorIndex := AInfo.Right + 1; end; end; end; procedure TdxHFTemplateExpander.SetCursorIndex(AValue: Integer); begin FCursorIndex := Max(Min(AValue, StrLength), 1); end; { TdxReportCellTitlePartText } constructor TdxReportCellTitlePartText.Create(AParent: TdxReportCell); begin inherited Create(AParent); FLines := TStringList.Create; EndEllipsis := False; Multiline := True; CellSides := []; end; destructor TdxReportCellTitlePartText.Destroy; begin FreeAndNil(FLines); inherited Destroy; end; function TdxReportCellTitlePartText.MeasureContentWidth( ACanvas: TdxPSReportRenderCustomCanvas): Integer; var I: Integer; begin Result := 0; for I := 0 to Lines.Count - 1 do Result := Max(Result, Renderer.CalcTextWidth(ACanvas, Lines[I], Font)); Inc(Result, 2 * Renderer.LineThickness * dxTextSpace); end; function TdxReportCellTitlePartText.GetText: string; begin Result := Lines.Text; end; procedure TdxReportCellTitlePartText.SetText(const Value: string); begin Lines.Text := Value; end; initialization dxHFFunctionLibrary := TdxStandardHFFunctionLibrary.Create; dxHFFormatObject := TdxHFFunctionFormatObject.Create; finalization FreeAndNil(dxHFFormatObject); FreeAndNil(dxHFFunctionLibrary); end.