Commit cb166633 authored by Jesus's avatar Jesus
Browse files

LazReport: Support for nogui-cgi or otherwise console and web applications.

git-svn-id: trunk@63892 -
parent 58d2132e
......@@ -2944,6 +2944,25 @@ components/lazreport/samples/enduser_reports/test_lr_formstorage/project1.res -t
components/lazreport/samples/enduser_reports/test_lr_formstorage/unit1.lfm svneol=native#text/plain
components/lazreport/samples/enduser_reports/test_lr_formstorage/unit1.pas svneol=native#text/pascal
components/lazreport/samples/index.txt svneol=native#text/plain
components/lazreport/samples/nogui_cgi/README.txt svneol=native#text/plain
components/lazreport/samples/nogui_cgi/conapp.pas svneol=native#text/pascal
components/lazreport/samples/nogui_cgi/data/SalesCustomer.dbf -text
components/lazreport/samples/nogui_cgi/data/disco.dbf -text
components/lazreport/samples/nogui_cgi/data/disco.mdx -text
components/lazreport/samples/nogui_cgi/demo_cross.lrf svneol=native#text/xml
components/lazreport/samples/nogui_cgi/disks.lrf svneol=native#text/xml
components/lazreport/samples/nogui_cgi/favicon.ico -text
components/lazreport/samples/nogui_cgi/frroundrecttester.lrf svneol=native#text/xml
components/lazreport/samples/nogui_cgi/images.lrf svneol=native#text/xml
components/lazreport/samples/nogui_cgi/images/splash_logo.png -text
components/lazreport/samples/nogui_cgi/index.html svneol=native#text/plain
components/lazreport/samples/nogui_cgi/reporter.lpi svneol=native#text/plain
components/lazreport/samples/nogui_cgi/reporter.lpr svneol=native#text/pascal
components/lazreport/samples/nogui_cgi/reporter.res -text
components/lazreport/samples/nogui_cgi/runtest.sh svneol=native#text/plain
components/lazreport/samples/nogui_cgi/unitreporter.pas svneol=native#text/pascal
components/lazreport/samples/nogui_cgi/unitweb.lfm svneol=native#text/plain
components/lazreport/samples/nogui_cgi/unitweb.pas svneol=native#text/pascal
components/lazreport/samples/report_url/report_url.lpi svneol=native#text/plain
components/lazreport/samples/report_url/report_url.lpr svneol=native#text/pascal
components/lazreport/samples/report_url/unit1.lfm svneol=native#text/plain
......@@ -3261,6 +3280,7 @@ components/lazreport/source/lr_insp.pas svneol=native#text/pascal
components/lazreport/source/lr_intrp.pas svneol=native#text/pascal
components/lazreport/source/lr_newrp.lfm svneol=native#text/plain
components/lazreport/source/lr_newrp.pas svneol=native#text/pascal
components/lazreport/source/lr_ngcanvas.pas svneol=native#text/pascal
components/lazreport/source/lr_pars.pas svneol=native#text/pascal
components/lazreport/source/lr_pgopt.lfm svneol=native#text/plain
components/lazreport/source/lr_pgopt.pas svneol=native#text/pascal
......
I. INTRODUCTION.
This project test the lazreport support for cgi, console and http server
applications. This support is implemented by using the LCL NoGui Widgetset,
and does not require any external DLL library like freetype, it require
though the used font files for text measuring or rendering purposes.
All tests are implemented in the same program by using different
build modes which are described below. Some tests use data from
a database and in this case, simple DBase files are used in order to
minimize target system configuration, it is understood though that
any relational database available can be used instead.
Check the Project->Options->Additions and overrides dialog to see
how LCLWidgetset is assigned by build mode.
NOTE. This program was developed under Windows, the instructions for
compiling, deployment and test may be different in other operating
systems, the code however should be platform and OS independent.
II. DESCRIPTION OF THE BUILD MODES.
Build Mode: CGI Debug Local
This build mode creates cgi application for testing the cgi operation
under Windows. It will create a reporter.cgi program which have to be
run under some http server, like apache, which in this case in done
through xampp. The build mode set up a compiler define CGI which in turn
creates an application of type TCGIApplication.
In order to test this application the needed files have to be deployed
to the local server in some way, and apache needs to be configured to run
cgi scripts from the respective cgi-bin directory, this is explained
somewhere else. Here some deployment suggestions:
METHOD 1: Symbolic link everything to the cgi-bin directory
Assuming that xampp is installed in drectory XAMPP and this program is in
the REPORTER directory, a link to reporter.cgi can be created in the right
folder using:
0) Make sure apache is configure to use symbolic links in windows.
In File XAMPP\apache\conf\httpd.conf, in <Directory "XAMPP/cgi-bin">
definition add flag FollowSymlinks to the "Option" value, restart apache.
1) Open a cmd window with administrator privileges
2) mklink XAMPP\cgi-bin\reporter.cgi REPORTER\reporter.cgi
mklink XAMPP\cgi-bin\images.lrf REPORTER\images.lrf
mklink XAMPP\cgi-bin\demo_cross.lrf REPORTER\demo_cross.lrf
mklink XAMPP\cgi-bin\disks.lrf REPORTER\disks.lrf
mklink XAMPP\cgi-bin\index.html REPORTER\index.html
mklink /D XAMPP\cgi-bin\data REPORTER\data
3) start XAMPP and run apache
4) point Navigator to http://localhost/cgi-bin/reporter.cgi
METHOD 2: Deploy everything to the www server directory
0) Copy index.html to XAMPP\cgi-bin\ directory
1) Copy reporter.cgi to the XAMPP\cgi-bin\ directory
2) Copy *.lrf to the XAMPP\cgi-bin\ directory
2) Copy data directory to the XAMPP\cgi-bin\ directory
METHOD 3: Configure apache for serving cgi scripts directly for program directoy
basically would be a guide for configuring apache and not this app.
Once the deployment has been done and apache is configured, test the cgi application
in the local server by opening a browser window and go to http://localhost/cgi-bin/reporter.cgi
or the server application at http://localhost:8080/
Build Mode: CGI Cross WinToLinux
Like the CGI Debug Local mode, this build mode set up a CGI define which
creates a TCGIApplication, the difference though is that it will build a
reporter_linux.cgi linux binary by doing cross compiling to linux which
need to be deployed to the target linux server. In these days crosscompiling
set up of the compiler has been dramatically reduced in complexity by using
the fpcupdeluxe program which is probably explained somewhere else.
Here deployment is done with the help of the deploy.bat script, see that file
for some indications, but basically it does the METHOD 2 described above.
Build Mode: Console App WinToLinux.
The same as CGI Cross WinToLinux but it creates a normal app.
Build Mode: Http Server.
This build mode creates a http stand alone server, on compiling it will produce
a reporter_server[.exe] file that could be run directly from the build directory
you should see the same page than in the cgi modes. It creates a THTTPApplication
through the HTTP_SERVER define declared in the build mode.
Build Mode: Console App.
This build mode creates a console application whose purpose is debugging
(debugging live cgi programs could be tricky). Included is a bash script
(runtest.sh) that tries all different lazreport export backends with all
included reports.
III. DESCRIPTION OF THE REPORTS
Todo. [This is (or will be) done in the index.html page]
IV. DESCRIPTION OF THE PROGRAM
Todo.
unit conApp;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, CustApp, UnitReporter;
type
{ TReporterApp }
TReporterApp = class(TCustomApplication)
private
fExportBackend: TExportBackend;
function GetReporter: TReporter;
procedure RunReport(reportName:string; reportFile:string='');
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure WriteHelp; virtual;
end;
var
Application: TReporterApp;
implementation
{ TReporterApp }
function TReporterApp.GetReporter: TReporter;
begin
result := TReporter.create;
result.ExportBackend := fExportBackend;
end;
procedure TReporterApp.RunReport(reportName: string; reportFile: string);
var
fReporter: TReporter;
begin
if reportFile='' then
reportFile := reportName + '.lrf';
fReporter := GetReporter;
fReporter.ExportBackend := fExportBackend;
try
case reportName of
'disks':
fReporter.PrepareDisksReport;
'cross':
fReporter.PrepareCrossTabReport;
'lrcode':
if not fReporter.PrepareLRCodeReport then begin
WriteLn('Error while producing the LRCodeReport');
exit;
end;
else
fReporter.LoadReport(reportFile);
end;
if fReporter.ProcessExportReport(reportName) then
WriteLn(reportName, ' report successfully exported')
else
WriteLn(reportName, ' report failed');
finally
fReporter.Free;
end;
end;
procedure TReporterApp.DoRun;
var
ErrorMsg: String;
begin
fExportBackend := ebPowerPDF;
// quick check parameters
ErrorMsg := CheckOptions('idcrxh', ['help','images','disks','code','cross','back:']);
if ErrorMsg <> '' then begin
ShowException(Exception.Create(ErrorMsg));
Terminate;
Exit;
end;
// parse parameters
if HasOption('h', 'help') then begin
WriteHelp;
Terminate;
Exit;
end;
if HasOption('back') then begin
ErrorMsg := GetOptionValue('back');
case lowercase(ErrorMsg) of
'powerpdf': fExportBackend := ebPowerPDF;
'fclpdf': fExportBackend := ebFCLPDF;
'txt': fExportBackend := ebTxt;
'csv': fExportBackend := ebCSV;
'html': fExportBackend := ebHtml;
'htmldiv': fExportBackend := ebHtmlDiv;
'bmp': fExportBackend := ebBmp;
'jpg': fExportBackend := ebJpg;
'png': fExportBackend := ebPng;
'ods': fExportBackend := ebOpenDoc;
'xls': fExportBackend := ebXLS;
'xlsx': fExportBackend := ebOOXML;
else begin
Writeln('Invalid export backend: ',ErrorMsg);
WriteHelp;
Terminate;
exit;
end;
end;
end;
if HasOption('i', 'images') then begin
RunReport('images');
Terminate;
exit;
end;
if HasOption('d', 'disks') then begin
RunReport('disks');
Terminate;
exit;
end;
if HasOption('c', 'code') then begin
RunReport('lrcode');
Terminate;
exit;
end;
if HasOption('r', 'rrect') then begin
RunReport('roundrect', 'frroundrecttester.lrf');
Terminate;
exit;
end;
if HasOption('x', 'cross') then begin
RunReport('cross', 'demo_cross.lrf');
Terminate;
exit;
end;
// stop program loop
Terminate;
end;
constructor TReporterApp.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException := True;
end;
destructor TReporterApp.Destroy;
begin
inherited Destroy;
end;
procedure TReporterApp.WriteHelp;
begin
{ add your help code here }
writeln('Usage: ', ExtractFileName(ExeName), ' -h');
WriteLn;
WriteLn(' --back=[powerpdf*|fclpdf|txt|csv|html|htmldiv|xls|xlsx|odf|bmp|jpg|png]');
WriteLn('-x,--cross CrossTab Report');
WriteLn('-d,--disks Disk records inventory report (60+ pages)');
WriteLn('-i,--images=[mono|all*] Bitmap monochrome or all formats Report');
WriteLn('-c,--code LRCodeReport Report');
WriteLn('-r,--rrect RoundRect Report');
WriteLn;
WriteLn('* = default');
end;
procedure InitApp;
begin
Application := TReporterApp.Create(nil);
end;
procedure DoneApp;
begin
Application.Free;
end;
initialization
InitApp;
finalization
DoneApp;
end.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<!DOCTYPE html>
<!--
This html file is not supposed to be used as the start page in a http server
like apache, instead it is used by the cgi or http application as the main
page sent to the browser by the application. So it should be treated as input
data for either application.
In order to be used as a normal, start web page, ajax should be used for
querying the cgi or http server application, or other strategies on form
actions should be implemented, but this is not yet done at this time.
-->
<html>
<head>
<meta charset="utf-8">
<title>LazReport web tester</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
fieldset {
margin: 0;
float: left;
width: 50%;
display: inline-block;
box-sizing: border-box;
}
.tbmargin {
margin-top:10px;
margin-bottom:10px
}
.centered {
text-align:center;
}
</style>
<script>
function log(msg) {
let logdiv = document.getElementById("log");
logdiv.innerHTML = msg + "<br><br>";
}
function isHttpServer() {
let index = window.location.href.indexOf(".cgi");
return (index<0);
}
function changeVisible(id, show, blockOrInline="inline") {
x = document.getElementById(id);
if (x) {
if (show)
x.style.display = blockOrInline;
else
x.style.display = "none";
}
}
function checkOptions() {
let backend = document.forms[0]["backend"].value;
let report = document.forms[0]["report"].value;
let imgfs = document.getElementById("fsimg");
let sheetfs = document.getElementById("fssheet");
//log("report: "+ report + ", backend: "+backend);
switch (backend) {
case "img":
imgfs.disabled = false;
sheetfs.disabled = true;
break;
case "sheet":
imgfs.disabled = true;
sheetfs.disabled = false;
break;
default:
imgfs.disabled = true;
sheetfs.disabled = true;
break;
}
changeVisible("btnTerminate", isHttpServer());
}
function rewriteFormAction(form) {
let backend = form["backend"].value;
let report = form["report"].value;
let lraction = form.getAttribute("lraction");
let act = lraction + report;
//log("action before: " + form.action + "<br>action after: " + act);
form.action = act;
}
</script>
</head>
<body style="margin:0; padding:0;">
<div id="header" class="centered">
<h1>Welcome to the LazReport NO-GUI Tester</h1>
<div id="log">
</div>
</div>
<div id="form" style="width:80%; margin: 0px auto;">
<form onsubmit="rewriteFormAction(this);" method="GET" target="docview" lraction="%uri%/web/">
<fieldset id="fsreport" class="tbmargin">
<legend>Select a report</legend>
<input type="radio" id="reporteimg" name="report" value="reporteimg">
<label for="reporteimg">Images Report</label><br>
<input type="radio" id="reportedisks" name="report" value="reportedisks">
<label for="reportedisks">Disks Inventory Report</label><br>
<input type="radio" id="lrcodereport" name="report" value="lrcodereport">
<label for="lrcodereport">LRCodeReport</label><br>
<input type="radio" id="crosstab" name="report" value="crosstab" checked>
<label for="crosstab">CrossTab Report</label><br>
<input type="radio" id="roundrect" name="report" value="roundrect">
<label for="roundrect">RoundRects</label><br>
</fieldset>
<fieldset id="fsbackend" class="tbmargin">
<legend>Select a backend</legend>
<input type="radio" id="powerpdf" name="backend" value="powerpdf" onchange="checkOptions()" checked>
<label for="powerpdf">PDF using PowerPDF</label><br>
<input type="radio" id="fclpdf" name="backend" value="fclpdf" onchange="checkOptions()">
<label for="fclpdf">PDF using the FCL's PDF support</label><br>
<input type="radio" id="htmldiv" name="backend" value="htmldiv" onchange="checkOptions()">
<label for="htmldiv">HTML using div</label><br>
<input type="radio" id="images" name="backend" value="img" onchange="checkOptions()">
<label for="images">Report to an image</label><br>
<input type="radio" id="spreadsheet" name="backend" value="sheet" onchange="checkOptions()">
<label for="spreadsheet">Spreadsheet</label><br>
<input type="radio" id="text" name="backend" value="text" onchange="checkOptions()">
<label for="text">Plain Text (txt)</label><br>
<input type="radio" id="csv" name="backend" value="csv" onchange="checkOptions()">
<label for="csv">Comma Separated Values (csv)</label><br>
</fieldset>
<fieldset id="fsimg">
<legend>Format for 'Report to images'</legend>
<input type="radio" id="imgbmp" name="imgext" value="bmp">
<label for="imgbmp">.BMP</label><br>
<input type="radio" id="imgpng" name="imgext" value="png" checked>
<label for="imgpng">.PNG</label><br>
<input type="radio" id="imgjpg" name="imgext" value="jpg">
<label for="imgjpg">.JPG</label><br>
</fieldset>
<fieldset id="fssheet">
<legend>Format for 'Spreadsheet'</legend>
<input type="radio" id="xls" name="shext" value="xls">
<label for="xls">Excel .xls format</label><br>
<input type="radio" id="xlsx" name="shext" value="xlsx" checked>
<label for="xlsx">Excel .xlsx format</label><br>
<input type="radio" id="odf" name="shext" value="odf">
<label for="odf">Open/Libre Office .odf</label><br>
</fieldset>
<div>&nbsp;</div>
<div class="tbmargin centered">
<input id="btnSubmit" type="submit" value="Run Report">
<input id="btnTerminate" type="submit" value="Terminate HTTP server" formaction="/Terminate">
</div>
</form>
</div>
<div class="tbmargin centered">
<iframe id="iframe" name="docview" title="Report Viewer" height="550px" width="80%"></iframe>
</div>
<script>
checkOptions();
</script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="reporter"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
<Resources Count="1">
<Resource_0 FileName="images\splash_logo.png" Type="RCDATA" ResourceName="LOGO1"/>
</Resources>
</General>
<BuildModes>
<Item Name="Default" Default="True"/>
<Item Name="CGI Debug Local">
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="nogui"/>
</MacroValues>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="reporter.cgi" ApplyConventions="False"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf2"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-dCGI"/>
</Other>
</CompilerOptions>
</Item>
<Item Name="HTTP Server">
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="nogui"/>
</MacroValues>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="reporter"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf2"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-dHTTP_SERVER"/>
</Other>
</CompilerOptions>
</Item>
<Item Name="CGI Cross WinToLinux">
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="nogui"/>
</MacroValues>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="reporter_linux.cgi" ApplyConventions="False"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="x86_64"/>
<TargetOS Value="linux"/>
</CodeGeneration>