# Report Writer

Generating a Report |

The reports created by the Report Designer can be generated in several ways.

- Generated from the Report Designer itself
- Generated programmatically using pvxreport object methods
- By a special PxPlus program that can be called from an application or used as a lead program to generate a report

Each approach requires that the input files needed to generate the reports are accessible during the PxPlus session.

## Report Designer Interface

The Report Designer can generate reports directly. Select a tool bar icon to generate output to the PxPlus Viewer (Print Preview) or a tool bar drop button to select from multiple destinations (printer, PDF file, Windows Clipboard, HTML file, tab-delimited file or custom output destination).

Alternately, you can send the report to the designated output destination by selecting File > Generate Report from the Report Designer menu bar.

To automatically display HTML and PDF reports using the default browser and PDF reader after they have been generated, set the Auto Display options for HTML and PDF files in Designer Options.

## Program CALL

A report can be generated by calling the *rpt/runreport program using the Run_Call entry point.

The first argument in the CALL statement must be the path to the report definition file.

A second optional argument can be used to specify a file path or a channel number to print to. A file path or channel number is not needed to output to the Clipboard or printer or if a Destination Path Expression has been specified for a report requiring an output file such as HTML, PDF or tab-delimited output. If a file path or channel number is specified, the Destination Path Expression will be ignored, and report definitions generating multiple reports will be written together in a single physical file.

(The Destination Path Expression option was added in PxPlus 2022.)

If no channel number is indicated for printer output, the default printer will be invoked as is. A channel number must be passed as a string.

Example:

> call "*rpt/runreport;Run_Call","c:\rptdef\cust.pvr"
> call "*rpt/runreport;Run_Call","c:\rptdef\cust.pvr",channel$
> call "*rpt/runreport;Run_Call","c:\rptdef\cust.pvr","myrpt.pdf"

## Lead Program

When launching PxPlus, the *rpt/runreport program can be run as a lead program to generate a report. The Command line requires the path to the report definition file as an argument:

> c:\pxplus\pxplus.exe *rpt/runreport -xt=1 -mn -arg c:\rpt\cust.pvr

A file path may be specified as a second argument to generate output files corresponding to the specified output definition for the report (.prn or .pdf file for printer reports, .htm for HTML output):

> c:\pxplus\pxplus.exe *rpt/runreport -arg \rpt\cust.pvr \myrpt.pdf

The second file path argument is optional if a Destination Path Expression has been specified for a report requiring an output file such as HTML, PDF or tab-delimited output. If a file path is specified, it will override the Destination Path Expression, and report definitions generating multiple reports will be written together in a single physical file.

(The Destination Path Expression option was added in PxPlus 2022.)

## Objects - RunReport( ) Method

Report generation can also be invoked by accessing objects that define the underlying components of the Report Writer. From PxPlus, pvxreport is the primary object used to generate a report.

First, create the object:

> rpt=new("*rpt/pvxreport")

Once instantiated, the pvxreport object interface provides several methods for generating reports. This includes the RunReport( ) method, which provides three formats for direct control over report generation. However, ultimate program control can be gained using a number of different methods that break the report generation sequence down to individual parts.

RunReport(RptDefFile$)

This format of the RunReport( ) method creates the report exactly as defined in the report definition file, which is passed as the only argument. If the printer is the defined output destination, the default printer will be used. See RunReport(RptDefFile$) method.

This format can also be used to generate PDF, HTML and tab-delimited files if a Destination Path Expression has been specified for the report. It can also be used to generate output files using custom output object interfaces and specifying the output file in the output object's 'DestinationFile$ property.

(The Destination Path Expression option was added in PxPlus 2022.)

Example:

> ! Use output destination designated in definition
> !
> rpt=new("*rpt/pvxreport");
> if rpt=0 \
> then end
> rpt'RunReport("MyRptDef.pvr")
> WrapUp: \
> drop object rpt
> end

RunReport(RptDefFile$,Chan)

This format gives the application developer control over the output channel. The application program must open the output channel (which must be compatible with the defined output destination), which is passed to the RunReport( ) method as the second argument. The program must then close the channel after the report is generated. See RunReport(RptDefFile$,Chan) method.

This format cannot be used to generate output to the Clipboard.

When an output channel is supplied, the Destination Path Expression specified for an output file will be ignored, and report definitions generating multiple reports will instead be written together in a single physical file.

(The Destination Path Expression option was added in PxPlus 2022.)

Example:

> ! Output to pdf file (Defined output destination is 'printer')
> !
> rpt=new("*rpt/pvxreport");
> if rpt=0 \
> then end
> !
> Options$="Overwrite;File=MyRpt.pdf;"+rpt'GetPageSetup$("MyRptDef.pvr")
> open (hfn,opt=Options$,err=WrapUp)"*pdf*";
> prt=lfo
> rpt'RunReport("MyRptDef.pvr",prt)
> close (prt)
> !
> system_help "myrpt.pdf"
> !
> WrapUp: \
> drop object rpt
> end

RunReport( )

This format gives the application program control over the report definition and output channel. The program must do all the initial set up: open the output channel, open the report definition, set the output channel, make changes as required (i.e. change input source or output destination), add more filters, and get user parameters, if necessary. After the report is generated, the program must close the report and the output channel. See RunReport( ) method.

Example:

> ! Change the output destination to HTML file
> !
> rpt=new("*rpt/pvxreport");
> if rpt=0 \
> then end
> !
> serial "myrpt.htm ",err=*next
> open purge (hfn,err=WrapUp)"myrpt.htm";
> prt=lfo
> !
> if rpt'open("MyRptDef.pvr")=0 \
> then goto WrapUp ! open and init the report definition
> rpt'OutputHTML(prt) ! set the output channel
> if rpt'ParamCount()>0 \
> then rpt'AcceptParameters() ! get parameter values from user
> rpt'RunReport() ! generate the report
> rpt'close() ! close the report object
> close (prt)
> !
> system_help "myrpt.htm"
> !
> WrapUp: \
> drop object rpt
> end

An alternate way to change the output destination is to use the ReportDestinationPath$ property:

> ! Change the output destination to HTML file using ReportDestinationPath$
> !
> rpt=new("*rpt/pvxreport");
> if rpt=0 \
> then end
> %ext$="htm" ! Set the extension for the type of report
> !
> if rpt'open("custinfo.pvr")=0 \
> then goto WrapUp ! open and init the report definition
> ! Evaluate ReportDestinationPath$ that is set to "custinfo."+%ext$ in the report definition
> ! The EvaluateReportDestinationPath$(pathExpr,"R") method evaluates the path and resets output type
> reportFile$=rpt'EvaluateReportDestinationPath$(rpt'ReportDestinationPath$,"R")
> serial reportFile$,err=*next
> open purge (hfn,err=WrapUp)reportFile$;
> prt=lfo
> rpt'setOutputChannel(prt)
> !
> if rpt'ParamCount()>0 \
> then rpt'AcceptParameters() ! get parameter values from user
> rpt'RunReport() ! generate the report
> rpt'close() ! close the report object
> close (prt)
> !
> system_help reportFile$
> !
> WrapUp: \
> drop object rpt
> end

See pvxreport Methods for information on the other methods used in this example.

(Support for Destination Path Expressions was added in PxPlus 2022.)

## Other Methods

Ultimate program control over report generation may be derived via the methods that conduct each of the steps in the report process:

Open(RptDefFile$) | Opens and initializes the report definition.
OutputPrint(Chan) OutputClipboard( ) OutputHTML(Chan) | Sets the appropriate output destination and channel.
StartReport( ) | Initializes workspace and objects required by report engine.
ReadData$( ) | Retrieves a data record from the input source.
ProcessData( ) | Processes the data and outputs it to the report.
FinishReport( ) | Processes summary lines and wraps up report.
Close( ) | Resets workspace and releases objects required by the report engine.

Besides the required methods, there are many methods and properties that allow an application to alter the report definition; i.e. ScaleToFit, SetDataSource( ), SetColumnWidth( ), SetFont( ), SetParameter( ), etc. These must logically be placed after an Open( ) and before a StartReport( ).

Any methods dealing with printer properties must be set, then followed by a SetPrinterProperties( ) method; e.g. SetMargins( ), SetLeftMargin( ), SetRightMargin( ), SetTopMargin( ), SetBottomMargin( ), SetPageOrientation( ). To take effect, these methods must precede the OPEN command used to open the output channel. GetPageSetup$( ) can be used to retrieve the page setup for a report.

Example:

> ! sortreport - Sort simple reports
> !
> ! This program processes simple reports that have no data groupings,
> ! and whose column headings are on line three of the page header.
> !
> ! This is a called program that accepts a report definition file
> ! name as an argument.
> !
> ! After loading the report, the program sets up three parameters
> ! (SortColumn, StartValue & EndValue) and retrieves these values
> ! from a user parameter panel interface.
> ! It then sets up a custom sort based on SortColumn and
> ! sets the background colour of that column to green
> ! Next it adds filters to process the StartValue and EndValue range
> ! Lastly, it sets the scale-to-fit option and generates the report
> ! to the Viewer.
> !
> enter ReportName$,err=*end
> !
> Rpt=new("*rpt/pvxreport")
> if Rpt'open(ReportName$)=0 \
> then goto WrapUp
> ! Check if report has groupings
> g=Rpt'GetGroup("H","01");
> if g \
> then exit 17
> !
> ! Add the parameters
> Rpt'ClearParams()
> p=Rpt'AddParam()
> p'Name$="SortColumn"
> p'Description$="Column to sort by"
> p'Type$="S"
> p'Length=60
> !
> p=Rpt'AddParam()
> p'Name$="StartValue"
> p'Description$="Start at"
> p'Type$="S"
> p'Length=30
> !
> p=Rpt'AddParam()
> p'Name$="EndValue"
> p'Description$="End at"
> p'Type$="S"
> p'Length=30
> !
> Rpt'SetParameterPanel("ReportParams","app.en")
> !
> ! Get the object handle for the data source
> src=Rpt'Source()
> ! Get column number to sort by and store in SortColumn parameter
> sts=Rpt'AcceptParameters();
> if sts=0 \
> then goto WrapUp
> ! Get column info from src using the "SortColumn" parameter
> SortColumn$=Rpt'GetParameter$("SortColumn")
> c=src'GetColumnInfo(SortColumn$);
> if c=0 \
> then c=Rpt'GetCalcField(SortColumn$);
> if c=0 \
> then goto WrapUp
> SortType$=c'Type$,SortVar$=SortColumn$+tbl(SortType$="S","","$")
> ! Redefine the sort
> Rpt'ClearSort() ! clear the original sort
> Rpt'SetSort(-1) ! set to custom sort
> s=Rpt'AddSortItem() ! add custom sort segment
> s'SegmentName$=c'Name$
> s'Type$=c'Type$
> s'Length=c'Length
> s'Order$="A"
> s'IgnoreCase=1
> ! Find the location of the sort column cell in the detail line
> SortColumn$=ucs(SortColumn$),Column=0
> line=Rpt'GetGroup("D","L1")'GetLine(1)
> c=line'CellCount()
> for c
> cell=line'GetCell(c)
> if ucs(stp(cell'Value$,1,"$"))=SortColumn$ \
> then SortColumn=cell'Column;
> break
> next
> ! Find the cell with the column heading and set the background colour
> line=Rpt'GetGroup("H","PG")'GetLine(3)
> c=line'CellCount()
> for c
> cell=line'GetCell(c)
> if cell'Column=SortColumn \
> then cell'BackgroundColour$="RGB:100,200,100";
> break
> next
> ! Set up the range filters
> StartAt$=Rpt'GetParameter$("StartValue")
> EndAt$=Rpt'GetParameter$("EndValue")
> if StartAt$+EndAt$<>"" \
> then Rpt'ClearFilters();
> fs=Rpt'AddFilterSet();
> quo$=tbl(SortType$="S","",quo),FF$=tbl(SortType$="S","",$FF$)
> if StartAt$<>"" \
> then fltr=fs'AddFilter();
> fltr'Variable$=SortVar$;
> fltr'ConditionCode=6;
> fltr'IsCaseSensitive=0;
> fltr'SetCompareValue(1,quo$+StartAt$+quo$)
> if EndAt$<>"" \
> then fltr=fs'AddFilter();
> fltr'Variable$=SortVar$;
> fltr'ConditionCode=5;
> fltr'IsCaseSensitive=0;
> fltr'SetCompareValue(1,quo$+EndAt$+FF$+quo$)
> !
> ! Turn on the Scale-to-fit option
> Rpt'ScaleToFit=1
> ! Now generate the report
> Generate_Report:
> open (hfn,err=WrapUp,opt="Normal;"+Rpt'GetPageSetup$())"*viewer*";
> prt=lfo
> Rpt'OutputPrint(prt)
> Rpt'RunReport()
> close (prt)
> WrapUp: \
> drop object Rpt
> end

In addition, there are methods to retrieve/change data (i.e. GetData( ) and SetData$( )) between ReadData$( ) and ProcessData( ) methods. This allows the program to alter the data before it is written.

Example:

> ! Data modification example
> !
> rpt=new("*rpt/pvxreport");
> if rpt=0 \
> then end
> if rpt'open("test.pvr")=0 \
> then goto WrapUp ! Open report definition
> !
> open (hfn,opt="Normal;File=test.prn;"+rpt'GetPageSetup$(),err=WrapUp)"*winprt*";
> prt=lfo
> rpt'OutputPrint(prt) ! Set output channel
> !
> if rpt'ParamCount()>0 \
> then rpt'AcceptParameters() ! Could also use SetParameter method
> !
> if rpt'startreport()=0 \
> then goto WrapUp ! Set up workspace
> !
> r$=rpt'ReadData$() ! Get a data record
> while r$<>""
> Balance=rpt'GetData("Balance") ! Get value of Balance
> rpt'SetData$("Balance",Balance*100) ! Modify Balance
> rpt'processdata() ! Process/output data
> r$=rpt'ReadData$() ! Get a data record
> wend
> !
> rpt'finishreport() ! Wrap up report
> rpt'close() ! Reset workspace
> WrapUp: \
> drop object rpt
> close (prt,err=*next)
> end

Another way to change data is to alter the record information returned by the ReadData$ method, then pass the altered record back to the Report Writer as an argument to the ProcessData method.

Example:

> !
> gosub Check_Access ! Sets NoAccess flag to 0/1
> !
> SourceIolist$=rpt'SourceIolist$() ! Get iolist for input source object
> !
> r$=rpt'ReadData$()
> while r$<>""
> ! if the user is not to have access to restricted data
> ! ! Load the record into the record fields
> ! ! Set restricted fields to 0
> ! ! Reload the record
> if NoAccess \
> then read data from r$ to iol=SourceIolist$;
> CreditRating=0,Balance=0;
> r$=rec(SourceIolist$)
> rpt'ProcessData(r$) ! Pass the altered record back for processing
> r$=rpt'ReadData$()
> wend
> !

## See Also

pvxreport Methods
Object-Oriented Interface