This method is used by both the XHTML and XSL-FO output sides to build the physical rows of the final table so as to use no more than a given number of detail columns. In the XHTML rendering this reduces or eliminates horizontal scrolling; in the PDF it is necessary to fit on the physical paper.
The actual number of table columns is one greater than the number of detail columns, but the row label column is not involved in the computation of the physical column count. Note that the phrase “detail columns” always refers to one less than the actual table column count.
The general procedure here is:
create a list of empty PhysRow instances,
each with no row label, and all detail cells set to empty
(SpacerCell);
copy the logical row label into the row label of the
first PhysRow and mark it as spanning
all of the physical rows;
distribute the logical detail cells into the physical rows from left to right and top to bottom; and finally
distribute the suffix cells into the end of the last physical row, from right to left.
# - - - R o w . f o l d
def fold(self, maxPhysCols):
'''Convert one logical row to one or more physical rows.
[ maxPhysCols > 0 ->
return a list of PhysRow instances representing self
folded into one or more physical rows each with no
more than (maxPhysCols) detail columns ]
'''
First calculate the number of physical rows required; see
Section 29.2, “Row.nPhysRows(): How many physical rows
will this logical row occupy?” and Section 29.3, “Row.nPhysCols(): How many physical
columns?”. Create rowList,
containing empty PhysRow instances.
#-- 1
# [ nPhysRows := number of physical rows required to hold
# this logical row
# nPhysCols := number of physical columns required to
# hold this logical row ]
nPhysRows = self.nPhysRows(maxPhysCols)
nPhysCols = self.nPhysCols(maxPhysCols)
#-- 2
# [ rowList := a list of (nPhysRows) PhysRow instances with
# (nPhysCols) columns each, no row label, and all
# cells set to SpacerCell instances ]
rowList = [ PhysRow(nPhysCols)
for k in range(nPhysRows) ]
Next, we copy the logical row's label to the first physical
row. When rendered, the label cell will span all the
following physical rows. The remaining physical rows, if any,
will have None as their row label, which tells
the output generation logic that the first cell of those rows
has been spanned from a previous row; in that case it will
generate no corresponding output cell. See Section 45.2, “PhysRow.setLabel()”.
#-- 3
rowList[0].setLabel(self._rowLabel, nPhysRows)
Copying logical detail cells into physical detail cells is
straightforward. Index logx steps through the
logical cells. For a given cell, its physical location is in
row (logx/nPhysCols) and physical column (logx % nPhysCols).
#-- 4
# [ rowList := rowList with the detail cells of self copied
# from left to right, then top to bottom ]
for logx in range(self.cbcHist.nCols):
rowx, colx = divmod(logx, nPhysCols)
rowList[rowx].setCell(colx, self._cellList[logx])
The suffix cells are also copied into the physical rows, but
they occupy the last positions. See Section 29.5, “Row._setSuffixCells(): Copy the suffix
cells to physical rows”.
#-- 5
# [ rowList := rowList with the last Row.N_SUFFIX_COLS
# cells set to the concrete class's suffix
# cells ]
self._setSuffixCells(nPhysRows, nPhysCols, rowList)
#-- 6
return rowList