Report Record Highlighting - General Case

A nice ride on an airplane, uninterrupted by telephone calls or email messages (or frozen pipes!), can do wonders for one’s creativity! The solution to this problem presented itself very nicely in this relaxed environment...

The Problem

We want to use a colored rectangle as a backdrop for alternate Record sections in a report to make that report easier to read. But our report might have variable height Record sections because some field within that section may have an align property value of “kExtendingJst” that could cause an instance of the section to have a different (larger) height than is designed for it in the Class. By the same token, one or more fields may have their nolineifempty property set to “kTrue”, which can cause a section instance to be shorter than its design height in the Class. Also, the report may contain more than just a Record section, so setting the $top position of our backdrop rectangles becomes more complicated. These possibilities are not accounted for in the technique we developed for the fixed section height case.

In developing the “fixed height” version of this technique, we discovered that the sequence of events in an Omnis Studio report works against our building a precise solution for this problem. The section doesn’t know its true height until it is placed on the Virtual Page. An extending object within the section doesn’t even know its true height until after it has been placed in the Virtual Section. And even if it did, background objects are placed in the Virtual Section before foreground objects, so it’s too late to modify our backdrop rectangle (a background object) by the time the $print method for any extending field (most likely a foreground object) is executed. Even if the extending object is a background object, the rectangle must be placed in the Virtual Section first or it will cover up the extending object (which isn’t an issue with an extending foreground object).

So we just can’t create a colored backdrop that is set to precisely the height of the section for the variable section height least, not if we play by the rules...

The Dodge

The problem mainly results from our changing the visibility of the backdrop rather than just changing its color. (Remember the “alternating colors” variation of the “fixed section height” technique.) What if we decided that the “invisible” color for the report is kWhite”? The automatic background color for a report printed to the screen destination is white, so why not? (And how many times do we print our reports on other colors of paper?)

And if we do this, why not make the backdrop for each Record section arbitrarily large — like the height of the current page? (This decision can vary depending on the expectations of a specific report and will be dictated by the largest possible extended section — but should be at least the page height so the last record backdrop simply fills the rest of the last page.) The backdrop rectangle of each new section will be placed over the previous one and only extending foreground objects cause new pages to be created. So this sounds like a plan!

All we have to do is figure out what the page height is and how to properly position the $top coordinate of the backdrop rectangle within each section...

The General Solution

First we need to determine how to achieve alternating colors in our sections. We will alternate between “white” and my favorite “light aqua” color in this example. In the $print method of the rectangle object, we will place the following command lines:

Calculate $cfield.$backcolor as pick(mod($cinst.$reccount,2),kWhite,rgb(204,255,255))
Do default

Using this algorithm, even numbered records will have a white background and odd numbered records (beginning with number one) will have an aqua background.

The only other thing we need to work out is the height we want to apply to our record backdrop object. We could just choose some arbitrarily large number, but it might be instructive for other purposes to determine the actual height of the “local” area on the page (the area between the page header and page footer and between the left and right margins). The technique we use for getting this information has many other uses in Omnis Studio report work.

Page Height Determination

We can derive information about the local area on the current page by performing a couple of “transforms” on the Position Vector for the section. We can perform these same transforms on the Position Vector for a foreground or background object, but that transform will not yield the information we need from within the first section to be printed and so our backdrop for the first record will not take on the proper size. It appears that the first page is not initialized until the “Do default” point of the sections $print method is actualized and the section is placed on the page. (This is just a guess since I didn’t write Omnis Studio and can only observe it from the “outside”. The cause for the effect I observe may be different. It may well be that performing these transforms from a different starting point — the object in “Section” space instead of the section in “Global” space — yields a different result.) But since we modified the height property of the rectangle from within the sections $print method in the “fixed section height” technique, there is no reason we shouldn’t do the same here.

To determine the height of the local area onto which our Virtual Section is about to be placed while preserving the original values of the sections Position Vector, we need a “scratchpad” variable to emulate that Position Vector. Since we know the Position Vector is a row variable, we need a local variable of that data type to act as a clone of the original on which we can perform our transform operations. We will name this variable “boundaryVector” as it is the page boundaries we eventually want to capture with it.

Here is the code we must put into the $print method of the Record section to expand the height of the backdrop rectangle to the height of the current local area:

Calculate boundaryVector as pPosition
Calculate boundaryVector.$posmode as kPosLocal
Calculate boundaryVector.$posmode as kBndsGlobal
Calculate rectRef.$height as boundaryVector.$height
Calculate rectRef.$width as pPosition.$width

Here is what this code means: The first line performs the “cloning” procedure, making an exact copy of pPosition in boundaryVector. The boundaryVector variable inherits all the attributes of pPosition during this move, including the fact that the contents of the row belong to a specific report coordinate system. We can “transform” this information to different report coordinate systems by modifying the value of the $posmode property of the row variable. (For more on report coordinate systems, take my “Omnis Studio Reporting Techniques” course or hang in there for the book...)

The Position Vector for the Record section begins its life in “Global” report space. It contains the size and position that the section intends to take in absolute coordinates. To transform this into information about the size of the “Local” area of the current page requires two moves. First, we must transform the vector to the “Local” coordinate space, which associates it with a specific horizontal and vertical page number coordinate as well as setting the effective origin of the coordinate space to the upper left corner of the current page (excluding headers, footers and margins). We do this by setting the $posmode property to “kPosLocal”.

The next thing we must do is to transform this vector such that it represents the implied container (the Local area) instead of the original object. We do this by transforming to the “Global Boundaries” coordinate system (boundaries of the current container in Global space) — that is, we change the $posmode property from “kPosLocal” to “kBndsGlobal”. After making this change, the $height, $width, $top and $left properties of the boundaryVector variable now represent these properties of the Local area in Global space — just what we need!

We can then set the $height property of our backdrop rectangle to the height of the “page”, which should be sufficient to deal with the length of the extended object in my example library and to extend to the bottom of the last page should only one record appear there.

And remember: The next backdrop rectangle in the alternate color will print over the current one at the beginning of the next record. The “height” of each record (i.e., where the next Record section begins) is dictated by its foreground objects.

Other Considerations

I have noticed that the Wrapping List and Data Grid components for a report do not respond to the nolineifempty property. If the associated list variable has no lines, these components appear to generate an empty report line even if they are the only object on that line and the nolineifempty property is set to a value of “kTrue”. This line could, under the right circumstances, spill over onto a subsequent page, causing a bar of the “wrong” color to appear at the top of that page with no content in it.

To achieve the proper effect when using these components (i.e., empty lists not requiring any space, we need to use an additional field on that line. This field must be invisible and represent the entire contents of the first line of the list variable associated with the “problem” component. If the list only contains one column, then we can assign the following value to the dataname property of our “shadow” field:


If the list contains more than one column, we can leave the dataname property empty, but must make this a “calculated” field with a text property value that contains an expression that concatenates all the columns of the first list line (using the same notation given above). In either event, the nolineifempty property will be properly treated by this field.

The Finished Product

This solution works equally well for the “fixed section height” case, so I recommend it over the technique that modifies the visibility of the backdrop rectangle — hence the title “General Case”. You should be pleased with the results!