Sw4   >   Reports   >   Reports (All Contents)
Reports tends to be the last thing we complete in our applications, yet it is often the output that users and their managers are looking for from the application.
Writing and modifying reports tends to be a tedious low level job, not one of my favorite jobs, but one that has to be done.
The oReports object in the StudioWorks framework attempts to simplify report writing by auto-generating reports based on the meta-data of the SQL list of records being passed to the object.
For very simple reports, the auto-generated report does the trick. If you need a more complex report (e.g. calculated fields, subtotals, multiple lines per record, ...) you can let StudioWorks auto-generate a report for you and then modify the report class which was created by StudioWorks.
This section explains how to setup up and modify reports in the StudioWorks framework.
The following diagram gives you an overview of the classes and sequence of messages for printing a report.
Although it may seem complex, the class structure actually reduces the amount of code you need to write, and makes it possible to reuse code for a web application.The
menu can be made to appear in any window instance toolbar. The menu lists the reports which are available to the user from a particular window instance.Each report that you create needs to be assigned a unique report instance ID. The string table translation of the ReportInstID is used for the report menu line text and the report title.
To add a report to a window instance's
menu:The oReportsMenuObserver object is classified as a visual object. It is responsible for prompting the user for any input values or choices that are needed prior to running the report. (Date from, Date to, select from a list of records, etc.)
Once the object has the necessary user input criteria it sends a message with the necessary parameters to the non-visual oPrintReport object in the same library. The oPrintReport object fetches the records, and all going well sends a $printReport message to oReports.
The oReportsMenuObserver object is also responsible for notifying the user if an error is returned by oPrintReport.
The reason for splitting the visual and non-visual code between oReportsMenuObserver and oPrintReport is so that the oPrintReport code can be reused by a web app if you decide to add web app functionality to your application.
If there are no user prompts required when running a particular report, you can simply redirect the message to oPrintReport as shown in the following code snip.
; No prompts required. Redirect the message to oPrintReport.
Do $cinst.$redirectToPrintReportObj($cmethod) Returns FlagOK
Quit method FlagOK
The oModelessPrompts object, instantiated by the task variable modelessprmpt is a helpful friend any time you need to prompt the user for input. Use oModelessPrompts rather than Prompt for input.
The oPrintReport object is a non-visual object responsible for gathering the list of records to be printed on the report and then sending a message to the oReports object which handles the actual printing of the report.
The method gets a SQL defined list, prepares a WHERE statement, and asks the table class to get the records. Once it has the records it passes the list of records along with other parameters to the oReports object.
How you accomplish fetching the records is up to your own creativity. The following is a snip of some code which used in an oPrintReport object method:
; Print a list of all the active books in the library sorted by Type/Series/Title.
; Get a defined list based on a query class used for books reports.
Do lsts.$retDefinedList('qBooksReport') Returns ReportList
; Prepare the SQL text WHERE clause.
Calculate SQLText as con("WHERE TypeGroupName = 'Books' AND Book.Active = 1")
; Call the custom $getWhere tBase table class method.
Do ReportList.$getWhere(SQLText) Returns FlagOK
If FlagOK
If ReportList.$linecount
; Self call $_printReport which calls oReports. We could call oReports direct.
Calculate ReportInstID as 'BooksReportSortByTypeSeriesTitle'
Do $cinst.$_printReport(ReportList,ReportInstID) Returns FlagOK
Else
; This isn't really an 'error', but the error handler is a convenient way to communicate this to the user.
Calculate Mssg as "No records found matching the query."
Calculate Dtls as SQLText
Do errhndlr.$logMinorError($cmethod,Mssg,Dtls)
Calculate FlagOK as kFalse
End If
End If
Quit method FlagOK
The oReports object is the central dispatcher for printing reports. You aren't required to use this object for printing reports, however, you should try to use it because the object has some helpful techniques for printing reports and automatically adding report and page headers which can then be set by user defined report preferences.
The oReports object, of the swReports4 library is instantiated using the startup task variable rprts.
The oReports object has public methods which you can use to print reports. The code inside oReports can get quite complicated to follow, so for now we'll stick to the basics.
The simplest method is $printDefaultReport. You can pass in a SQL defined list of records and this method will generate a report which prints the includeinlist columns of the SQL defined list.
Do rprts.$printDefaultReport(pReportsList,pReportTitle_opt,pReportInstID_opt) returns FlagOK
If you don't pass in a ReportInstID, the method calculates the ReportInstID as the base table of the ReportList plus the suffix List. e.g. BookList.
If you don't pass in a report title, the method calculates the ReportTitle as the Tblplural string table translation of the report list's base table.
The oReports object looks for a report class which matches the name of the ReportInstID prefixed with the letter r. eg. rBookList. If found it prints the report using the report class. If not found, the oReports object creates a temporary report class with the prefix X_, indicating that it is a temporary class. e.g. X_rBookList. The temporary report class is created in the same library as the SQL class of the ReportList.
After a temporary report has been printed, you can manually remove the X_ prefix from the report class name and then customize the report adjusting fields, adding subtotal sections, adding sorting, etc. The next time you print the same report, the oReports object will find your customized report and use it rather than generating its own report.The rReport_abstract report class, located in the swReports4 library is the superclass used by the StudioWorks framework for report classes. It is recommended that you subclass your report class from rReport_abstract. Auto-generated reports are automatically subclassed from rReport_abstract.
The main feature of rReport_abstract is that is creates a standard report page header on-the-fly. The header can include: date and time printed, user who printed the report, page number of, company logo, company name, company contact info, page header notes. A multitude of property methods control displaying or hiding the various header objects, and whether or not they print on the first page only. You can review the public methods using the on the rReport_abstract class.
If you study the $construct method you will see that it receives the following parameters: pfList, pExtraParamsRow, prCallBackInst, pCallBackMethod.
This gives you two ways to control the report which is being printed:
Users often want some level of control over how the report prints out. As developers we like to give users this control so they don't need to ask us for minor changes to reports.
The rReport_abstract and are declared in the oReports object.
menu includes a menu line which lets the user control the report page header objects of reports which are subclassed fromAfter you create a custom report and it shows up in the
menu you can select the menu item. This opens a window where the user can modify the report page header and some of report presentation properties.If the report instance doesn't show up in the window check to make sure it has been added to the oReportsList object in the module.
Report suffixes can be useful if you have several slighty different versions of the same basic report. The following example describes a situation where we could use report suffixes.
We have a Books report that is sorted by Title/Author or by Author/Title. Even though both versions of the report has the same information, using the same report class would be difficult because we want the Title in column one for the Title/Author sort, and the Author in column one for the Author/Title sort.
To use report suffixes we would do the following:
When the user selects $BooksReport message will be sent to the oReportsMenuObserver object. In that method you could prompt the user for which books they want to include in the report and whether they want the report sorted by Title/Author or Author/Title. You then pass this information to the $BooksReport method of the non-visual oPrintReport object. The oPrintReport method then fetches the records and sends a $printReport message to oReports with the necessary parameters.
, aReport suffixes are optional. Using them can reduce the amount of code you write for slightly different versions of the same report. The oPrintReport protected methods $_getReportRecordsAndPrintReport and $_printReport and the oReports method $printReport support report suffixes in their parameters.
There are actually 2 types of report suffixes:
The StudioWorks framework makes it easy for you to print the same report class as a summary report or a detailed report.
Typically you need this when management wants a report with just the summary information, but staff needs the same report with both the summary and detailed information.
To accomplish this in StudioWorks:
The $_processExtraParamsRow method of the report class sets the ivar iPrintDetailed in the report class to the value you pass via the pExtraParamsRow_opt parameter. If no value is passed StudioWorks defaults to false.
You can extend this technique to other sections of your report by using the iPrintDetailed in the $printif property of the section.
The following is a snip of code which prompts the user with a radio button input and then puts the selected value into an extra parameters row variable.
; Prompt the user to indicate what records they want to select for the report.
Calculate PromptTitle as 'Report Type'
Calculate Mssg as "Select the type of report you wish to run."
; RadioGroupLabel_kRadio_Radio1Label_Radio2Label_
Calculate DetailsRadioGroupLabel as 'Report Type_kRadio_Summary_Detailed'
Calculate PromptButtons as 'Cancel,Continue'
; prmpts.$promptInputVars(pMessage,pTitleStbNameID_opt,pIconName_opt,pInfoMessage_opt,pCSVButtonStbIDsLeftToRight_opt,pCSVButtonModesLeftToRight_opt,pInputLabel1,pfInputVar1,...)
Do $ctask.prmpts.$promptInputVars(Mssg,PromptTitle,cPromptIcon,,PromptButtons,,,DetailsRadioGroupLabel,cPick_Summary_Detailed) Returns ButtonPressed
If low(ButtonPressed)<>'continue'
Quit method kTrue
End If
; Pack the 'PrintDetailed' variable into an extra parameter row which gets passed to the report.
Do ExtraParamsRow.$cols.$add('printdetailed',kBoolean) Returns ColRef
Calculate ExtraParamsRow.[ColRef().$name] as cPick_Summary_Detailed