Flexlines Volume IX Number 5 (a Data Access publication)
Building A Better REPORT.PKG
by Michael Steffano
With the advent of DataFlex 3.0's object orientation comes a much brighter possibility for the writing of
truly sophisticated and classy programs. Class inheritance is one of the keys to developing powerful tools
that are easy to incorporate into everyone's programming arsenal.
As one of my first projects in object oriented development I was approached by a business client and
fellow developer to create a powerful reporting package. Having read many articles in FlexLines
concerning this very topic, I thought this would be an easy task. It turned out to be interesting and
challenging, but not easy.
My first breakthrough came with obtaining 2E Software's 3.0 REPORT.PKG written by John Tuohy. This
excellent package contained within it many of the necessary building blocks I required. And, since part of
the package was written as a class, I could easily add its functionality to the new package (which I'll refer
to as NEW_RPT.PKG) through class inheritance. In fact, Tuohy had already written several examples
that used class inheritance. Here is an example of class inheritance:
Class Report is an Edit (from REPORT.PKG using a 3.0 class)
Class New_Report is a Report (from NEW_RPT.PKG)
Some of the elements of what I considered necessary for a world-class report package were:
* a consistent visual appearance easily manipulated by the programmer
* totally hidden inner mechanics
* easy rewrite incorporation for existing programs
* simultaneous multiple channel output (screen, file, printer)
* report interruption and subsequent viewing of the partial report
A tall order but I felt 3.0 was up to the task. The key to the project was the starting point. As mentioned
above, Tuohy's REPORT.PKG allowed me to jumpstart the project; in one fell swoop giving
NEW_RPT.PKG a consistent powerful reporting mechanism by which an application programmer could
immediately become productive. This is the promise held out to us by object-oriented programming:
using powerful tools to develop complex programs and even more powerful tools. As one of the
converted, believe me IT WORKS!
By using Tuohy's REPORT.PKG I was able to concentrate on the user interface, output device selection,
management of the user interface during report processing, and simultaneous multiple channel output.
Still a challenge!
I saw no reason to limit the application programmer to my idea of a report input screen. For this reason,
the programmer was left responsible for creating his or her parameter selection screen. These
parameters are then used when creating the actual program logic for report selection. This level of
program design takes place within the functionality of Tuohy's REPORT class, so I had little to do here
(thankfully). However, once parameters were selected it became time for output device selection and
direction. Now NEW_RPT.PKG's functionality came into play. One quick word on packages and
classes. A package can hold more than just a class (and typically does). NEW_RPT.PKG has within it
multiple classes, objects, global variables, and of course, documentation.
OUTPUT DEVICE SELECTION & DIRECTION
By designing a sub-class from Tuohy's REPORT class I was able to augment or override any of his
internal methods (procedures and functions). This ability makes it easy for me to intercept his
RUN_REPORT message (which is sent by the application programmer's logic as the last step in report
initiation). At this point an object responsible for obtaining output device selection and direction
information is invoked. Since this is all contained within NEW_RPT.PKG, the programmer does not need
to know anything about it's function or how it is invoked (unless he or she wants to). All the programmer
has to do is include the USE NEW_RPT.PKG command. There is the possibility that the screen
appearance of the Output Device Selection object may not harmonize with the program's screen
appearance. This is easily remedied by editing NEW_RPT.PKG and changing the appearance of the
object's screen. This object (which is actually a client) contains within it a check box, entry form, and
buttons. The check box is used to toggle select the printer and file output devices built into
NEW_RPT.PKG. As part of the package's operation, output is always directed to the screen, thus giving
the user a consistent visual interface (and obviating the programmer's need to display some type of
customised "busywork" screen). As a device is selected the default device name is displayed in the entry
form object. The programmer has the ability to default choices here (such as report file name, printer
device) from within the application program through the use of class properties. The button object
contains confirmation and cancel buttons from which program control may be passed on to the heart of
the new report class.
REPORT PROCESSING (or Let's Write A Virtualized Edit Object)
This is the real heart of the package. The user not only gets an ongoing visual display of the report as it
is processing, but also has the ability to interrupt the report at any point and VIEW the entire completed
portion of the report. Upon first approach, I thought this would be easy. I felt the VConsole and Edit
classes had all the functionality necessary. The virtual console would be used to give the user a dynamic
display of the report as it processed. This worked great until wide (greater than 80 column) reports were
tried. You guessed it: screen wrap! The goal of creating a world-class package made this a real thorn in
my side. As there currently is no property SCREEN_WRAP_MODE for the VConsole class (hint, hint
DAC) I ended up being saved through a trick: if you Activate, then DeActivate, and finally Activate again
the same VConsole object the text will no longer wrap. Frankly I don't know why this is, but it works great
on 132 column virtual consoles (I have not tried on it on smaller ones).
Object VC is a Vconsole
set Size to 24 132 // use full screen
Set Location to 0 0
Send Activate to (VC(Current_Object)) // sets it up
// This command sends all screen IO to the virtual console.
Send virtual_console to (VC(Current_Object))
// These next two lines take care of the word wrap problem
Send DeActivate to (VC(Current_Object)) //
Send Activate to (VC(Current_Object)) // sets it up
Another requirement was allowing the user to be able to view the report during any point in the
processing by entering into an EDIT object. The Edit class would give the user full cursoring and
scrolling/paging functions. One of the basic design premises had report output always directed to a file.
This allows the package to close the reporting file and reopen it as an input stream to the Edit object (the
Edit class supports this option). This was great except one large problem surfaced: the Edit object is
RAM-bound. That is, there is a limitation of how many lines of text it can hold (32767 or less). For small
reports this isn't much of a problem, but in larger ones the user would not be able to view all of the
completed report (which was one of the package's requirements). It was decision time: live with the
limitation or modify the Edit object's behavior (and incur a large amount of programming overhead)?
That's another nice thing about 3.0- you almost always have choices. I decided to create a virtualized
edit class, that is, one which would work on any size file. Since NEW_RPT.PKG was now in control of
the edit object's window into the report file, its MAX_LINES property was decreased from 32767 to only
24, thus conserving precious conventional memory. However, now all the functions taken for granted
when using the Edit class: top of file, bottom of file, page up, page down, scroll up, scroll down, scroll left,
scroll right, etc. had to be programmed. This was probably the hardest part of the project and was
accomplished with a fair degree of effort.
SIMULTANEOUS MULTIPLE CHANNEL OUTPUT
3.0 brings with it powerful new I/O capabilities through the CHANNEL command. Rather than rehash
them here, suffice to say multiple I/O channels can be easily managed in 3.0. As part of the package
design, I wanted the user to be able to direct output to the printer, screen, and file at the same time if
desired, rather than having to rerun the report multiple times for each output device. The screen always
gets output to as part of the user visuals, while as mentioned above, the class makes use of a report file
to allow report reviewing. The report file is not retained unless explicitly requested by the user during
output device selection. This leaves only the printer device. One of the many design choices
encountered was whether to output the same data to all three output devices. Should a report file or
screen display contain formfeed characters, page number headings, multiple footers, etc.? The decision
was reached that only the printer should contain these which made for more programming work. The
class had to be able to know which output devices were active and decide what to print (or not print) to
each of them. The hardest part of this task was managing the line counts and augmenting or overriding
internal methods in Tuohy's REPORT.PKG. Fortunately, the CHANNEL command is smart enough to
maintain a separate LineCount variable for each channel opened, thus when you change channels
DataFlex will automatically reset LineCount to that channel.
// Direct output to the named file
direct_output channel FILE_CHANNEL (File_Name(EC(Current_Object)))
// Direct output to the console
direct_output channel CONSOLE_CHANNEL 'CON:'
// If printer is selected direct output to it also
If (To_Printer_State(Current_Object)) begin
direct_output channel PRINTER_CHANNEL 'LST:'
send Initialize_Printer // designed for override
direct_output channel FILE_CHANNEL // this is the primary channel
So there you have it: one world-class report package riding "piggyback" on top of another world-class
report package, adding functionality and versatility all via the use of the USE command.
A special thanks goes to David King of King Business Systems for his technical review, programming
advice, and monetary support during this development process. Also, thanks to John Tuohy for his
REPORT.PKG and technical advice.
Michael D. Steffano is a long-time DataFlex developer, and creator of ExReport.pkg.