diff --git a/.github/meta.yml b/.github/meta.yml new file mode 100644 index 0000000..6b0f159 --- /dev/null +++ b/.github/meta.yml @@ -0,0 +1,5 @@ +# GitHub Repository metadata +url: vcl-dashboards-non-interactive-export +website: https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards +description: Generate DevExpress VCL Dashboards in backend and service applications. +tags: [vcl, pdf, dashboards, backend, service, cli, console] diff --git a/.gitignore b/.gitignore index 9db64f6..3ea9af4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,8 @@ -# Uncomment these types if you want even more clean repository. But be careful. -# It can make harm to an existing project source. Read explanations below. -# -# Resource files are binaries containing manifest, project icon and version info. -# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. -#*.res -# -# Type library file (binary). In old Delphi versions it should be stored. -# Since Delphi 2009 it is produced from .ridl file and can safely be ignored. -#*.tlb -# -# Diagram Portfolio file. Used by the diagram editor up to Delphi 7. -# Uncomment this if you are not using diagrams or use newer Delphi version. -#*.ddp -# -# Visual LiveBindings file. Added in Delphi XE2. -# Uncomment this if you are not using LiveBindings Designer. -#*.vlb -# -# Deployment Manager configuration file for your project. Added in Delphi XE2. -# Uncomment this if it is not mobile development and you do not use remote debug feature. -#*.deployproj -# -# C++ object files produced when C/C++ Output file generation is configured. -# Uncomment this if you are not using external objects (zlib library for example). -#*.obj -# - # Default Delphi compiler directories # Content of this directories are generated with each Compile/Construct of a project. -# Most of the time, files here have not there place in a code repository. -#Win32/ -#Win64/ -#OSX64/ -#OSXARM64/ -#Android/ -#Android64/ -#iOSDevice64/ -#Linux64/ +Win32/ +Win64/ +Win64x/ # Delphi compiler-generated binaries (safe to delete) *.exe @@ -61,6 +27,7 @@ *.cfg *.hpp *Resource.rc +*.rsp # Delphi local files (user-specific info) *.local @@ -75,8 +42,46 @@ __history/ __recovery/ *.~* + +# ------------------------------------------------------------ +# C++Builder specific +# ------------------------------------------------------------ + +# C++Builder compiler outputs +*.obj +*.hpp +*.ilc +*.ild +*.ilf +*.ils +*.map +*.tds + +# Precompiled headers +*.pch + +# C++Builder packages and libraries +*.bpl +*.bpi +*.lib +*.a +*.dll +*.so + +# C++Builder intermediate / cache files +*.cbproj.local +*.cbproj.identcache +*.cbproj.user +*.cbtemp + + # Castalia statistics file (since XE7 Castalia is distributed with Delphi) *.stat # Boss dependency manager vendor folder https://github.com/HashLoad/boss modules/ + +# Output files +*.pdf +*.docx +*.zip diff --git a/Delphi/ConsoleDashboards.dpr b/Delphi/ConsoleDashboards.dpr new file mode 100644 index 0000000..72b7d78 --- /dev/null +++ b/Delphi/ConsoleDashboards.dpr @@ -0,0 +1,78 @@ +program ConsoleDashboards; + +{$APPTYPE CONSOLE} + +{$R *.res} + +uses + System.SysUtils, System.Classes, dxBackend, dxBackend.Bundled, + dxBackend.ConnectionString.SQL, dxDashboard; +var + ACountryName: string; + +procedure ExportDashboardToPdf(const ACountryName: string); +var + AManager: TdxBackendDataConnectionManager; + AConnection: TdxBackendDatabaseSQLConnection; + ADashboard: TdxDashboard; + AStream: TMemoryStream; + AOutputFileName: string; +begin + // Step 1: Create a dashboard instance and load the dashboard layout + ADashboard := TdxDashboard.Create(nil); + try + ADashboard.Name := 'Country Sales'; + ADashboard.Layout.LoadFromFile('CountrySalesDashboard.xml'); + + // Step 2: Create a data connection manager and set up the database connection + AManager := TdxBackendDataConnectionManager.Create(nil); + try + AConnection := TdxBackendDatabaseSQLConnection(AManager.DataConnections.Add(TdxBackendDatabaseSQLConnection)); + + // Assign a database name matching the name specified in the dashboard layout + AConnection.DisplayName := 'NWindConnectionString'; + // Assign a connection string required to use the local SQLite database + AConnection.ConnectionString := 'XpoProvider=SQLite; Data Source=nwind.db; Mode=ReadOnly'; + AConnection.Active := True; + + // Step 3: Define Dashboard Parameter Values + ADashboard.LoadParametersFromDashboard; + // Set the "CountryDashboardParameter" value in the dashboard layout + ADashboard.Parameters['CountryDashboardParameter'].Value := ACountryName; + ADashboard.ApplyParametersToState; + + // Step 4: Export the dashboard to PDF + AStream := TMemoryStream.Create; + try + // Export the dashboard to a memory stream in the PDF format + ADashboard.ExportTo(TdxDashboardExportFormat.PDF, AStream); + // Save memory stream content to a file + AOutputFileName := 'Sales_' + ACountryName + '.pdf'; + AStream.SaveToFile(AOutputFileName); + Writeln('Dashboard saved to: ', AOutputFileName); + finally + AStream.Free; + end; + finally + AManager.Free; + end; + finally + ADashboard.Free; + end; +end; + +begin + if ParamCount < 1 then + begin + Writeln('Error: CountryName parameter is required. For example: ConsoleDashboards.exe USA'); + Halt(1); // Exit with error code 1 + end; + + ACountryName := ParamStr(1); // Read the first parameter as CountryName + try + ExportDashboardToPdf(ACountryName); + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; +end. diff --git a/Delphi/ConsoleDashboards.dproj b/Delphi/ConsoleDashboards.dproj new file mode 100644 index 0000000..9ced3b1 --- /dev/null +++ b/Delphi/ConsoleDashboards.dproj @@ -0,0 +1,1119 @@ + + + {80C6AE61-4BFA-472B-81E9-EF92ED4837F3} + 20.3 + None + True + Debug + Win32 + ConsoleDashboards + 1 + Console + ConsoleDashboards.dpr + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) + ConsoleDashboards + + + dxBackendRS37;vclwinx;DataSnapServer;dxComnRS37;fmx;dxDockingRS37;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;dxCoreRS37;dxServerModeRS37;IndyProtocols;cxPivotGridRS37;vclx;Skia.Package.RTL;dxPScxTLLnkRS37;dbxcds;vcledge;dxSpreadSheetConditionalFormattingDialogsRS37;dxEMFRS37;dxReportsRS37;dxPSCoreRS37;dxPSPrVwRibbonRS37;DBXFirebirdDriver;cxIBXAdaptersRS37;dxRichEditDocumentModelRS37;FireDACSqliteDriver;DbxClientDriver;dxPSdxDBTVLnkRS37;soapmidas;dxDashboardsRS37;dxPScxExtCommonRS37;dbexpress;inet;vcltouch;cxSchedulerWebServiceStorageRS37;FireDACDBXDriver;fmxdae;dxTabbedMDIRS37;CustomIPTransport;FireDACMSSQLDriver;dxFireDACEMFRS37;cxGridRS37;dxSpellCheckerRS37;cxFireDACAdaptersRS37;dxorgcRS37;IndySystem;dxBarRS37;dxCloudServiceLibraryRS37;dxPScxPCProdRS37;ibxbindings;dxPSRichEditControlLnkRS37;dxGDIPlusRS37;vclFireDAC;cxADOAdaptersRS37;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;dxBarDBNavRS37;dxPDFViewerRS37;dxmdsRS37;dxPSdxOCLnkRS37;bindcompdbx;rtl;FireDACMySQLDriver;SmartCoreAIVCL;dxADOEMFRS37;DBXSqliteDriver;dxPSdxDBOCLnkRS37;DBXSybaseASEDriver;cxSchedulerTreeBrowserRS37;dxChartControlRS37;SmartCoreAIFMX;cxGridEMFRS37;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;dxNavBarRS37;dxSpreadSheetCoreConditionalFormattingDialogsRS37;xmlrtl;dxPScxGridLnkRS37;dxADOServerModeRS37;ibxpress;dxWizardControlRS37;dsnap;FireDACDb2Driver;dxPScxSchedulerLnkRS37;DBXOracleDriver;DBXInformixDriver;vclib;dxHttpIndyRequestRS37;fmxobj;bindcompvclsmp;DataSnapNativeClient;dxTileControlRS37;dxSpreadSheetReportDesignerRS37;dxGaugeControlRS37;dxOrgChartAdvancedCustomizeFormRS37;DatasnapConnectorsFreePascal;dxPSdxMapControlLnkRS37;cxVerticalGridRS37;dxBarExtItemsRS37;cxLibraryRS37;dxdborRS37;dxSpreadSheetRS37;cxSchedulerGridRS37;emshosting;dxFlowChartAdvancedCustomizeFormRS37;dxPSdxLCLnkRS37;FireDACCommonDriver;IndyIPClient;bindcompvclwinx;dxPSLnksRS37;emsedge;bindcompfmx;cxTreeListRS37;dxFlowChartRS37;inetdb;ibmonitor;cxPivotGridChartRS37;dxFireDACServerModeRS37;FireDACASADriver;vclactnband;dxMapControlRS37;fmxFireDAC;FireDACInfxDriver;DBXMySQLDriver;VclSmp;DataSnapCommon;fmxase;cxSchedulerRibbonStyleEventEditorRS37;DBXOdbcDriver;SmartCoreAI;dbrtl;dxPScxCommonRS37;FireDACOracleDriver;Skia.Package.FMX;dxPSdxSpreadSheetLnkRS37;dxPSdxChartControlLnkRS37;FireDACMSAccDriver;dxRichEditControlRS37;dxPsPrVwAdvRS37;dxPSdxPDFViewerLnkRS37;DataSnapIndy10ServerTransport;dxDBXServerModeRS37;cxSchedulerRS37;cxExportRS37;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;dxRichEditControlCoreRS37;FireDACTDataDriver;Skia.Package.VCL;dxPScxPivotGridLnkRS37;vcldb;dxBarExtDBItemsRS37;dxPSdxFCLnkRS37;bindcomp;inetstn;dxFlowChartLayoutsRS37;IndyCore;RESTBackendComponents;dxRibbonRS37;dxSpreadSheetCoreRS37;dxGanttControlRS37;dxPScxVGridLnkRS37;dxPSdxGaugeControlLnkRS37;FireDACADSDriver;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;dxSkinsCoreRS37;dxdbtrRS37;DBXDb2Driver;dxRichEditCoreRS37;cxTreeListdxBarPopupMenuRS37;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;dxRibbonCustomizationFormRS37;tethering;dxtrmdRS37;bindcompvcl;cxPivotGridOLAPRS37;dxFlowChartDesignerRS37;CloudService;DBXSybaseASADriver;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + .\ + (None) + none + USA + + + dxBackendRS37;vclwinx;DataSnapServer;dxComnRS37;fmx;dxDockingRS37;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;dxCoreRS37;dxServerModeRS37;IndyProtocols;cxPivotGridRS37;vclx;dxPScxTLLnkRS37;dbxcds;vcledge;dxSpreadSheetConditionalFormattingDialogsRS37;dxEMFRS37;dxReportsRS37;dxPSCoreRS37;dxPSPrVwRibbonRS37;DBXFirebirdDriver;cxIBXAdaptersRS37;dxRichEditDocumentModelRS37;FireDACSqliteDriver;DbxClientDriver;dxPSdxDBTVLnkRS37;soapmidas;dxDashboardsRS37;dxPScxExtCommonRS37;dbexpress;inet;vcltouch;cxSchedulerWebServiceStorageRS37;FireDACDBXDriver;fmxdae;dxTabbedMDIRS37;CustomIPTransport;FireDACMSSQLDriver;dxFireDACEMFRS37;cxGridRS37;dxSpellCheckerRS37;cxFireDACAdaptersRS37;dxorgcRS37;IndySystem;dxBarRS37;dxCloudServiceLibraryRS37;dxPScxPCProdRS37;ibxbindings;dxPSRichEditControlLnkRS37;dxGDIPlusRS37;vclFireDAC;cxADOAdaptersRS37;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;dxBarDBNavRS37;dxPDFViewerRS37;dxmdsRS37;dxPSdxOCLnkRS37;bindcompdbx;rtl;FireDACMySQLDriver;SmartCoreAIVCL;dxADOEMFRS37;DBXSqliteDriver;dxPSdxDBOCLnkRS37;DBXSybaseASEDriver;cxSchedulerTreeBrowserRS37;dxChartControlRS37;SmartCoreAIFMX;cxGridEMFRS37;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;dxNavBarRS37;dxSpreadSheetCoreConditionalFormattingDialogsRS37;xmlrtl;dxPScxGridLnkRS37;dxADOServerModeRS37;ibxpress;dxWizardControlRS37;dsnap;FireDACDb2Driver;dxPScxSchedulerLnkRS37;DBXOracleDriver;DBXInformixDriver;vclib;dxHttpIndyRequestRS37;fmxobj;bindcompvclsmp;DataSnapNativeClient;dxTileControlRS37;dxSpreadSheetReportDesignerRS37;dxGaugeControlRS37;dxOrgChartAdvancedCustomizeFormRS37;DatasnapConnectorsFreePascal;dxPSdxMapControlLnkRS37;cxVerticalGridRS37;dxBarExtItemsRS37;cxLibraryRS37;dxdborRS37;dxSpreadSheetRS37;cxSchedulerGridRS37;emshosting;dxFlowChartAdvancedCustomizeFormRS37;dxPSdxLCLnkRS37;FireDACCommonDriver;IndyIPClient;bindcompvclwinx;dxPSLnksRS37;emsedge;bindcompfmx;cxTreeListRS37;dxFlowChartRS37;inetdb;ibmonitor;cxPivotGridChartRS37;dxFireDACServerModeRS37;FireDACASADriver;vclactnband;dxMapControlRS37;fmxFireDAC;FireDACInfxDriver;DBXMySQLDriver;VclSmp;DataSnapCommon;fmxase;cxSchedulerRibbonStyleEventEditorRS37;DBXOdbcDriver;SmartCoreAI;dbrtl;dxPScxCommonRS37;FireDACOracleDriver;dxPSdxSpreadSheetLnkRS37;dxPSdxChartControlLnkRS37;FireDACMSAccDriver;dxRichEditControlRS37;dxPsPrVwAdvRS37;dxPSdxPDFViewerLnkRS37;DataSnapIndy10ServerTransport;dxDBXServerModeRS37;cxSchedulerRS37;cxExportRS37;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;dxRichEditControlCoreRS37;FireDACTDataDriver;Skia.Package.VCL;dxPScxPivotGridLnkRS37;vcldb;dxBarExtDBItemsRS37;dxPSdxFCLnkRS37;bindcomp;inetstn;dxFlowChartLayoutsRS37;IndyCore;RESTBackendComponents;dxRibbonRS37;dxSpreadSheetCoreRS37;dxGanttControlRS37;dxPScxVGridLnkRS37;dxPSdxGaugeControlLnkRS37;FireDACADSDriver;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;dxSkinsCoreRS37;dxdbtrRS37;DBXDb2Driver;dxRichEditCoreRS37;cxTreeListdxBarPopupMenuRS37;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;dxRibbonCustomizationFormRS37;tethering;dxtrmdRS37;bindcompvcl;cxPivotGridOLAPRS37;dxFlowChartDesignerRS37;CloudService;DBXSybaseASADriver;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage) + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DEBUG;$(DCC_Define) + true + false + true + true + true + true + true + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + + + false + + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + + Delphi.Personality.12 + Application + + + + ConsoleDashboards.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + true + + + + + true + + + + + ConsoleDashboards.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + False + + + 12 + + + + + + del /q *.pdf + False + + False + + False + + diff --git a/Delphi/ConsoleDashboards.res b/Delphi/ConsoleDashboards.res new file mode 100644 index 0000000..447d5c1 Binary files /dev/null and b/Delphi/ConsoleDashboards.res differ diff --git a/Delphi/CountrySalesDashboard.xml b/Delphi/CountrySalesDashboard.xml new file mode 100644 index 0000000..9aafacf --- /dev/null +++ b/Delphi/CountrySalesDashboard.xml @@ -0,0 +1,107 @@ + + + + <DataSources> + <SqlDataSource Name="SQL Data Source" ComponentName="sqlDataSource1"> + <Connection Name="NWindConnectionString" FromAppConfig="true" /> + <Query Type="SelectQuery" Name="Invoices"> + <Parameter Name="CountryFilter" Type="DevExpress.DataAccess.Expression">(System.String)(?CountryDashboardParameter )</Parameter> + <Tables> + <Table Name="Invoices" /> + </Tables> + <Columns> + <AllColumns Table="Invoices" /> + </Columns> + <Filter>[Invoices.Country] = ?CountryFilter</Filter> + </Query> + <ConnectionOptions CloseConnection="true" /> + <CalculatedFields> + <CalculatedField Name="Price" Expression="ToDouble( [ExtendedPrice] ) " DataType="Auto" DataMember="Invoices" /> + <CalculatedField Name="Calculated Field 1" Expression="ToDouble( [Invoices.ExtendedPrice] ) " DataType="Auto" /> + </CalculatedFields> + </SqlDataSource> + </DataSources> + <Parameters> + <Parameter Name="CountryDashboardParameter" Value="France" Visible="false" /> + </Parameters> + <Items> + <Chart ComponentName="chartDashboardItem1" Name="Chart 1" ShowCaption="false" DataSource="sqlDataSource1" DataMember="Invoices"> + <DataItems> + <Dimension DataMember="OrderDate" DateTimeGroupInterval="MonthYear" DefaultId="DataItem1" /> + <Measure DataMember="Price" DefaultId="DataItem0"> + <NumericFormat FormatType="Currency" /> + </Measure> + </DataItems> + <Arguments> + <Argument DefaultId="DataItem1" /> + </Arguments> + <Panes> + <Pane Name="Pane 1"> + <Series> + <Simple SeriesType="Spline"> + <Value DefaultId="DataItem0" /> + <PointLabelOptions ContentType="Value" /> + </Simple> + </Series> + </Pane> + </Panes> + </Chart> + <Card ComponentName="cardDashboardItem1" Name="Card 1" ShowCaption="false" DataSource="sqlDataSource1" DataMember="Invoices"> + <DataItems> + <Measure DataMember="ExtendedPrice" DefaultId="DataItem0" /> + <Dimension DataMember="CustomerName" DefaultId="DataItem1" /> + </DataItems> + <SeriesDimensions> + <SeriesDimension DefaultId="DataItem1" /> + </SeriesDimensions> + <Card> + <ActualValue DefaultId="DataItem0" /> + <AbsoluteVariationNumericFormat /> + <PercentVariationNumericFormat /> + <PercentOfTargetNumericFormat /> + <LayoutTemplate Type="Stretched"> + <TopValue Visible="true" ValueType="ActualValue" DimensionIndex="0" /> + <MainValue Visible="true" ValueType="Title" DimensionIndex="0" /> + <SubValue Visible="true" ValueType="Subtitle" DimensionIndex="0" /> + <BottomValue1 Visible="true" ValueType="PercentVariation" DimensionIndex="0" /> + <BottomValue2 Visible="true" ValueType="AbsoluteVariation" DimensionIndex="0" /> + <DeltaIndicator Visible="true" /> + <Sparkline Visible="true" /> + </LayoutTemplate> + </Card> + </Card> + <Grid ComponentName="gridDashboardItem1" Name="Grid 1" ShowCaption="false" DataSource="sqlDataSource1" DataMember="Invoices"> + <DataItems> + <Dimension DataMember="Address" DefaultId="DataItem0" /> + <Dimension DataMember="City" DefaultId="DataItem1" /> + <Measure DataMember="Price" DefaultId="DataItem2"> + <NumericFormat FormatType="Currency" /> + </Measure> + </DataItems> + <GridColumns> + <GridDimensionColumn> + <Dimension DefaultId="DataItem0" /> + </GridDimensionColumn> + <GridDimensionColumn> + <Dimension DefaultId="DataItem1" /> + </GridDimensionColumn> + <GridMeasureColumn> + <Measure DefaultId="DataItem2" /> + </GridMeasureColumn> + </GridColumns> + <GridOptions /> + <ColumnFilterOptions /> + </Grid> + </Items> + <LayoutTree> + <LayoutGroup> + <LayoutGroup Orientation="Vertical"> + <LayoutItem DashboardItem="chartDashboardItem1" Weight="124.4155844155844" /> + <LayoutGroup Weight="75.5844155844156"> + <LayoutItem DashboardItem="cardDashboardItem1" Weight="68.47030288908363" /> + <LayoutItem DashboardItem="gridDashboardItem1" Weight="131.52969711091637" /> + </LayoutGroup> + </LayoutGroup> + </LayoutGroup> + </LayoutTree> +</Dashboard> \ No newline at end of file diff --git a/Delphi/nwind.db b/Delphi/nwind.db new file mode 100644 index 0000000..b96cf97 Binary files /dev/null and b/Delphi/nwind.db differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..26fcdcd --- /dev/null +++ b/README.md @@ -0,0 +1,200 @@ +<!-- default badges list --> +![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/1140410022/25.2.5%2B) +[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) +[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) +<!-- default badges end --> + +# DevExpress VCL Dashboards — Generate Dashboards in a Backend / Service Application + +This example uses DevExpress Dashboards for Delphi/C++Builder to generate dashboards in a command line application. +The application accepts a country name parameter, queries the database for country sales data, +and exports a "sales" dashboard as a PDF file. + +This example bypasses the DevExpress Dashboard Viewer dialog and generates a dashboard +using the DevExpress Dashboards backend. +Use the approach demonstrated in this sample project to implement +Web API backends, Windows Services, workflows, and scheduled jobs. +This approach can be particularly beneficial for the following usage scenarios +(reports generated without direct user interaction): + +- Mass-export dashboards to PDF, DOCX, image, and other formats. +- Share, email, and print dashboard documents silently. +- Implement custom dashboard management UIs. + +--- + +![A PDF dashboard example generated by a command line application (demonstrates a USA sales dashboard)](./images/dashboard.png) + +--- + +## Prerequisites + +[DevExpress Dashboards Prerequisites][req] + +[req]: https://docs.devexpress.com/VCL/405773/ExpressCrossPlatformLibrary/vcl-backend/reports-dashboards-app-deployment#vcl-reportsdashboards-prerequisites + +## Test the Example + +1. Open and build the Delphi project in the RAD Studio. +2. Start a console session and navigate to the _Delphi_ project directory. +3. Run the app and specify the country name: + ```console + > ConsoleDashboards.exe France + + Dashboard saved to: Sales_France.pdf + ``` +4. Generate dashboards for other countries and compare generated PDF files. + +The sample database shipped with the example includes sales data for +Argentina, Austria, Belgium, Brazil, Canada, Denmark, Finland, France, +Germany, Ireland, Italy, Mexico, Norway, Poland, Portugal, Spain, +Sweden, Switzerland, UK, USA, and Venezuela. + +## Implementation Details + +Follow the steps below to create an application that imports a dashboard layout from a file, +binds the layout to data, and exports the generated dashboard to a PDF file. + + +### Step 1: Initialize a Dashboard and Import a Dashboard Layout + +An application requires a template dashboard layout previously created in the [Dashboard Designer][designer]. +You can [import a layout from a file][file] or [load a layout from a database][database]. +(Links refer to DevExpress VCL Reports examples that can be easily re-used with DevExpress Dashboards.) + +[designer]: https://docs.devexpress.com/VCL/405774/ExpressDashboards/getting-started/create-dashboard-using-designer-dialog +[file]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-file +[database]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-database + +This example imports a dashboard layout from the `CountrySalesDashboard.xml` file. + +**Delphi:** +```delphi +ADashboard := TdxDashboard.Create(nil); // ADashboard: TdxDashboard; +try + // Set an internal dashboard name (does not affect the exported content) + ADashboard.Name := 'Country Sales'; + // Load the dashboard layout from the specified file + ADashboard.Layout.LoadFromFile('CountrySalesDashboard.xml'); + // ... +finally + ADashboard.Free; +end; +``` + + +### Step 2: Create a Database Connection + +Create a database connection component to supply data to the dashboard. +This example uses a SQL connection component with a built-in SQLite engine to load the Northwind sample database stored in `nwind.db`. + +```delphi +// AConnection: TdxBackendDatabaseSQLConnection; +AConnection := TdxBackendDatabaseSQLConnection.Create(nil); +try + // Assign a database name matching the name specified in the dashboard layout + AConnection.DisplayName := 'NWindConnectionString'; + // Assign a connection string required to use the local SQLite database + AConnection.ConnectionString := 'XpoProvider=SQLite; Data Source=nwind.db; Mode=ReadOnly'; + // ... +finally + AConnection.Free; +end; +``` + +For detailed information on data source management and supported database engines, refer to the following help topic: +[VCL Backend: Supported Database Systems][dbms]. + +[dbms]: https://docs.devexpress.com/VCL/405703/ExpressCrossPlatformLibrary/vcl-backend/vcl-backend-supported-database-systems + +### Step 3: Define Dashboard Parameter Values + +A dashboard layout may include one or more parameters. +Parameters allow you to modify database queries and generate different dashboards +based on the same dashboard template and underlying data. +For example, `CountrySalesDashboard.xml` includes a single `CountryDashboardParameter` that filters data by country name. + +To modify parameters, load them using the `LoadParametersFromDashboard` method +and assign values to `Dashboard.Parameters` list members as follows: + +**Delphi:** +```delphi +ADashboard.LoadParametersFromDashboard; +// Set the "CountryDashboardParameter" value in the dashboard layout +ADashboard.Parameters['CountryDashboardParameter'].Value := ACountryName; +``` + + +### Step 4: Export Dashboard Content to a File + +This example exports a dashboard to a PDF file: + +**Delphi:** +```delphi +AStream := TMemoryStream.Create; // AStream: TMemoryStream; +try + // Export a dashboard to a memory stream in the PDF format + ADashboard.ExportTo(TdxDashboardExportFormat.PDF, AStream); + // Save memory stream content to a file + AStream.SaveToFile('Sales_' + ACountryName + '.pdf'); +finally + AStream.Free; +end; +``` + +### Export Multiple Dashboards + +The approach outlined in this example allows you to generate and export multiple dashboards based on the same layout and data +using a list of parameters. +You need to initialize the dashboard layout and data connection once (steps 1 and 2) +and repeat steps 3 and 4 for each parameter. + +**Delphi:** +```delphi +// ... +ADashboard.LoadParametersFromDashboard; + +for ACountryName in ACountryNameList: + ADashboard.Parameters['CountryDashboardParameter'].Value := ACountryName; + + AStream := TMemoryStream.Create; // AStream: TMemoryStream; + try + // Export a dashboard to a memory stream in the PDF format + ADashboard.ExportTo(TdxDashboardExportFormat.PDF, AStream); + // Save memory stream content to a file + AStream.SaveToFile('Sales_' + ACountryName + '.pdf'); + finally + AStream.Free; + end; +end; +``` + + +## Files to Review + +- [`Delphi/ConsoleDashboards.dpr`](./Delphi/ConsoleDashboards.dpr) generates a dashboard in non-interactive (headless) mode. +- [`CountrySalesDashboard.xml`](./CountrySalesDashboard.xml) contains a dashboard layout designed to generate a country sales dashboard. + You can open the same dashboard in the Dashboard Designer and Viewer using the [dashboard with a hidden parameter example application][example]. +- [`nwind.db`](./nwind.db) contains the Northwind sample database. + +[example]: https://github.com/DevExpress-Examples/vcl-dashboards-pass-hidden-parameters-to-custom-sql-query + +## Documentation and Examples + +- [Introduction to VCL Dashboards](https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards) +- [Tutorial: Create a dashboard using the Designer Dialog](https://docs.devexpress.com/VCL/405774/ExpressDashboards/getting-started/create-dashboard-using-designer-dialog) +- [How to store layouts in XML files (example application)](https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-file) +- [How to store layouts in a database (example application)](https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-database) +- [How to use SQLite as a data source for dashboards (as demonstrated in the current example)](https://docs.devexpress.com/VCL/405750/ExpressCrossPlatformLibrary/vcl-backend/database-engines/vcl-backend-sqlite-support) +- [API reference: `TdxDashboard` class](https://docs.devexpress.com/VCL/dxDashboard.TdxDashboard) +- [API reference: `TdxDashboard.Layout` property](https://docs.devexpress.com/VCL/dxDashboard.TdxDashboard.Layout) +- [API reference: `TdxBackendDatabaseSQLConnection` component](https://docs.devexpress.com/VCL/dxBackend.ConnectionString.SQL.TdxBackendDatabaseSQLConnection) + + +<!-- feedback --> +## Does This Example Address Your Development Requirements/Objectives? + +[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=vcl-dashboards-non-interactive-export&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=vcl-dashboards-non-interactive-export&~~~was_helpful=no) + +(you will be redirected to DevExpress.com to submit your response) +<!-- feedback end --> diff --git a/images/dashboard.png b/images/dashboard.png new file mode 100644 index 0000000..8eb5039 Binary files /dev/null and b/images/dashboard.png differ