Pagination
Automatic pagination is one of the primary features of any document generation system. Well, "automatic" but with control! Conceptually, pagination is dead simple: when you run out of paper, start a new sheet. When you want control over that process it becomes substantially more difficult than that. But that's the developer moaning. It has to be easy for the user.
Let's back up for a second. What happened just before pagination? Data merge happened. That means that there is now a big DOM full of instantiated panes. Typically poor old "page 1" has a container that is bursting with panes – way more than its container can possibly hold. Data merging doesn't care about that. To it, pages/containers are of infinite capacity. Then along comes pagination to face the real world with its physical limits.
If no control were offered, pagination would/could just see if a pane fits in the container, and if it does, great, get the next pane, but if it doesn't, well start a new page and put the overflowing pane there. Simple. ... but it's not.
What do you mean pane? Sure there are some simple form designs where there is simply one "leaf node" pane after another, but mostly one has a hierarchy of panes where one pane encloses several other panes, etc. Now, what does it mean when we think "if the pane doesn't fit"? Which pane? The outer pane, some inner pane... what?
Besides, even in the simple case of a sweet string of leaf node panes, you won't be happy if pagination does a new page between any old pair of panes. You have to be kind to "widows and orphans". It's a life rule.
For example, it's unlikely that you want a column header pane to be the last pane on a page – widowed there. It's equally unlikely that you want a totals pane, signature block, or even first of a set of detail lines to be the first thing on a page -orphaned there. In real applications, panes like context.
You need control
Corollary – you need to conscientiously apply that control or face the penalties for inattentiveness.
That control is provided to you via the usual modal and modeless property dialogs for pane objects.
Modeless Pane Properties | Modal Pane Properties |
---|---|
The modal properties are shown because they have a bit more text so as to explain what the checkboxes mean. One important piece of text is missing though. The context of these checkboxes is within this pane's immediate parent. It is not a 'within the entire document' context.
For example, consider the "Allow Multiple" checkbox. Sure, a pane can occur lots of times within a whole document, but what matters is whether it is able to occur multiple times within the pane's immediate parent. Always keep that implicit context in mind.
Pagination Checkboxes
The checkboxes are damnably simple. So simple that one tends to gloss over them, not giving them the attention they deserve. Beware of deadly results. Pay attention to the checkboxes for each and every pane; the high-level ones and the itsy-bitsy bottom-level leaf node ones.
Mandatory
Does this pane have to come out even if there is no data for any of the fields in the pane (or the pane has no fields)?
Careful though, a footer pane may seem mandatory in that you really do want it to come out, but it is forced out by means of an Overflow Footer specification. Think about it. Do you want the pane to come out where it sits in the form design, no matter what?
In the case of a detail type usage pane, must it come out, or are there perfectly valid situations where there might be no detail lines?
Allow Multiple
The only trick here is to realize that the question is being asked in the context of the pane's immediate parent. In that context, is it allowed to come out more than once? Does the tag name for this pane occur multiple times in the XML file – within the context of its parent?
Too often we see an enclosing pane marked as allow multiple and its sole or at least primary child pane also marked as allow multiple. That might be right but please do look at it and decide if perhaps one of them should not be marked as allow multiple.
Allow Split
Containers will fill up with 'too many panes'. Something has to be done. When a pane, first at the outermost level of the panes in the hierarchy, overflows its container you want to control whether to push the whole pane over to a new page or to allow the pane to be split leaving as much as can fit on the current page stay on the current page, and only the rest move to the new page.
Panes that enclose other panes are more likely to need the "Allow Split" setting turned on. Not always, as sometimes there is a tightly knit group of panes that are meant to stay together. Look carefully.
Where will it split the pane? You are in control of that using these same checkboxes throughout the child panes of the overflowing pane. First of all, if the pane that overflows the container is a leaf node pane (has no child panes) but is marked as allow split, then it will be split at the lowest possible place where there is a gap in the extents of the objects in that pane. E.g.
between a row of fields. By 'lowest' we mean a split point that keeps as much as possible on the current page; that makes maximum use of the paper stock.
How much room is there? Nothing is easy for the code. Enjoy the fact that you need to only click a few boxes. How much room is available is determined not only by the container size but also by the size of the overflow footers that apply to the pane being split. The footers for pane A are not necessarily the same as the footers for Pane B. So the available room varies.
But of course, the pane that overflows is likely going to be an enclosing pane, a pane with child panes. At that point the pagination code will recurse down a level looking for a good spot to split between the child panes or possibly within a leaf node child pane. The applicable footers may change.
Finding that split point is controlled by your settings of "Allow Split", "Break Before" and "Break After".
Allow Break Before
That is "Allow break before". This is not forcing the pagination code to break before this pane is used but merely allowing this pane to become the first pane on a new page.
I like to personify the pane this way. If I check Allow Break then I am saying I am so strong that I can leave the nest, start out on a new page all by myself. I don't need any elder sibling or mama. I'm good to go. Conversely, if I don't check Allow Break, it is saying that I am too weak to stand on my own. I need an elder sibling or my mama. Don't orphan me. I need my context.
As it happens, leave Allow Break Before off almost all the time. You do not want a break before headings. You don't want a break before the first in a series of detail lines – you want to cuddle up under the detail line headings. You probably don't want a break before a totals type usage pane. It would just be odd to have a total with no context as to what it is totalling, so usually you want to drag along the last detail line. "Usually", you can choose to put Break Before on if you want. Similarly, a signature type usage pane probably wants some context dragged on its page.
But there are times when a document contains, oh, sections. These sections are strong. They can start out on their own. You could easily want to mark the first pane of a section as "Allow Break Before".
Allow Break After
That is "Allow break after", not force break after. This is the protective mama end of the spectrum. Leaving this off says that you don't want your kids, well, your younger siblings, to be sent off in the world on their own. You want to wrap them to your bosom by keeping them on the same page where you can "look after them" by providing your context. Or like saying "Don't abandon me, or leave me a widow". Conversely, checking Break After means that you have faith in your younger siblings, faith that they can stand on their own.
Less personified, the example is of the details header pane that says "don't break after me", my, at least eldest detail line has to be on my page – or move me too.
Like Allow Break Before, you pretty much always have Allow Break After unchecked. Think about it. Where would you really want to say it's ok to break after this pane? Certainly not immediately after a header pane – it's a header for something that wants that header context. Continue thinking like that as you imagine the various pane usage types and you'll see that allowing break after is a rarity.
Allow Break Between
What? There is no "Allow Break Between" checkbox. Correct. Merge pagination always believes that it can break between two successive instances of the same pane. That's automatically always true.
It is this implicit Allow Break Between setting that takes all the steam out of Allow Break Before and Allow Break After. Allow
Break Before really means "Allow Break Before the first occurrence of this pane" (in its parent's context), and Allow Break After really means "Allow Break After the last occurrence of this pane" (in its parent's context). Both of those cases are generally false, but break between – well, that's a winner. There's context on both pages so breaking feels great.
Force Page
This is the pagination code's friend. No hassle, no thought, do as commanded. If it encounters a pane with this checked, it will immediately start a new page. One exception is if the current page's container has nothing in it, then Force Page will do nothing.
You almost never set Force Page. Let pagination do its thing.
Layout in multiple columns
If pane has "Layout in multiple columns" checked then Pagination Algorithm tries to arrange the pane's children panes in multiple columns interpreting this pane as a kind of a "container".
Footers/Headers defined for the "Layout in multiple columns" pane (or its parents) are applied when the pane itself is being split between pages. If you want footers/headers for the columns then you should define footers/headers for the children panes keeping in mind that in this case "OnSplit" occurs when the pane is being split between columns.
Column balancing
By default children, panes are evenly balanced between the columns. As of version 3.2.001.09, it's possible to disable balancing with a tag "BalancedColumns No" set for the "Layout in multiple columns" pane. It can also be set globally when used as a Merge command line option.
Minimum Height
What is this about anyway? Well, when drawing out a pane on the Design canvas it can be convenient to leave space at the bottom of the pane, just to have room to mouse around in. You more clearly see the objects in the pane without confusing them with the bottom edge of the pane. Whitespace is your design-time friend.
But do you want that whitespace to show up in the rendered documents? Probably not. So by setting Minimum Height to something really small you are allowing Merge to throw away all the whitespace below the lowest object in the pane. That is generally what you want to do.
But what if you do want whitespace at the bottom of your pane? Merge will always respect your bottom margin specification. So specify all the whitespace you want via the bottom margin setting. Alternatively, you can draw out your pane to the exact height you want it to be, including whitespace at the bottom. Then you can select the "(full height)" setting for the Minimum Height setting. You don't need to set a bottom margin in that case.
Min Height of Panes that wrap other panes
The setting "(full height)" means the full height as seen at Design time, i.e. the height that you drew the pane(s) out at. An enclosing pane may include all sorts of optional panes. It makes no sense to set the Minimum Height of an enclosing pane to "(full height)". They should always have a very small minimum height and let them be as tall as they need to be. Use a bottom margin as applicable.
A small number? Zero is small isn't it? Yes, it is, but zero is actually the encoding for "(full height)", so don't use zero, use a small number.
Pagination Generalities
But don't even dream about not paying attention every time.
Setting | Value |
---|---|
Mandatory | On a lot of the time |
Allow Multiple | Mostly off, unless it's a repeating detail type pane |
Allow Split | On a lot, especially for enclosing panes, and panes over 1 "row" high |
Force Page | Almost never on |
Allow Break Before | Rarely on, but sometimes |
Allow Break After | Rarely on, but sometimes |
Allow Break Between | Automatically on all the time |
Minimum Height | Mostly a very small size (.001) |
Footers/Headers
Note that besides OnSplit Footers/Headers for a pane, it's also possible to define Overflow Footers/Headers for a container. Though only the closest ones to the split point are applied, i.e. footers/headers are not accumulated going up the objects hierarchy from the split point.
Modeless Container Properties | Modal Container Properties |
---|---|
Pagination Algorithm
As of 3.1.002.06 version of "Pagination Algorithm" is the property of the form. The difference between different pagination versions is how footer/headers are applied in the split point.
Version | Description |
---|---|
Version 1 (relaxed) | Pagination Algorithm looks for the footers/headers defined for the pane being moved to the next page (first one in the set of moved panes). |
Version 2 (strict) | Pagination Algorithm looks for the footers/headers defined for the pane being split. |
Pagination Algorithm gets complex really fast but some high-level insight might help.
- Determine the container height
- Walk down the list of panes until one causes overflow (consider footers)
- Walk back up the list of panes looking for...
- A pane that is splittable
- Or a pane that is marked as Allow Break Before and has an elder sibling that is marked as Allow Break After.
- If no split point is found...
- Walk back up the list of panes looking for...
- A pane that is marked Allow Break Before and simply has an elder sibling, regardless of its Break After setting.
- Walk back up the list of panes looking for...
- If no split point is found yet...
- Walk back up the list of panes looking for...
- A pane whose elder sibling has Allow Break After set.
- Walk back up the list of panes looking for...
- If still no split point is found...
- Split before the pane that overflowed regardless, as long as it is not the only pane in the container. Else log a message.
When dealing with a pane that is marked as "Allow Split", then the algorithm for finding the split point in it is much the same as that for a container. In extremis, it may have to split a leaf node pane somewhere between its objects.
Splitting a leaf node pane between its objects has its own set of difficulties when one considers long vertical lines, tables, borders and the like.