Styles, slots and the cascade
Named styles and slots
Section titled “Named styles and slots”The look of a table is described with two concepts.
A named style is a set of formatting attributes, declared once with @ExcelStyle and identified by a name. A named style does nothing on its own.
A slot is a place where a named style is applied, by name. The slots are:
| Slot | Declared in | Applies to |
|---|---|---|
titleStyle |
@ExcelSheet |
the title row |
header.base |
@ExcelSheet(header = @HeaderStyles(...)) |
every header cell |
header.firstColumn, header.lastColumn |
@HeaderStyles |
the header cell of the first or last column |
headerStyle |
@ExcelColumn |
the header cell of one column |
body.base |
@ExcelSheet(body = @BodyStyles(...)) |
every data cell |
body.odd, body.even |
@BodyStyles |
the data cells of odd or even rows |
body.firstRow, body.lastRow |
@BodyStyles |
the data cells of the first or last data row |
body.firstColumn, body.lastColumn |
@BodyStyles |
the data cells of the first or last column |
styles.base, styles.odd, styles.even, styles.firstRow, styles.lastRow |
@ExcelColumn(styles = @ColumnStyles(...)) |
the data cells of one column, optionally restricted to odd, even, first or last rows |
One named style can be referenced by any number of slots.
@ExcelSheet( header = @HeaderStyles(base = "header"), body = @BodyStyles(odd = "zebra", lastRow = "total"))@ExcelStyle(name = "header", bold = Toggle.TRUE, fillColor = "#1F4E79", fontColor = "#FFFFFF")@ExcelStyle(name = "zebra", fillColor = "#EEF3F8")@ExcelStyle(name = "total", bold = Toggle.TRUE, borderTop = Border.DOUBLE)public record InvoiceLine( @ExcelColumn(header = "Description", order = 10) String description, @ExcelColumn(header = "Amount", order = 20, format = "#,##0.00") BigDecimal amount) {}Unset attributes
Section titled “Unset attributes”Every attribute of a named style, apart from its name, has a default that means unset. An unset attribute overrides nothing: it leaves the value decided by the levels below. Because annotation attributes cannot be null, “unset” is represented as follows:
| Kind of attribute | Unset value |
|---|---|
Enum attributes (align, border, fillPattern, underline, …) |
the constant INHERIT of the enum |
Yes or no attributes (bold, wrapText, locked, …) |
Toggle.INHERIT (the three states are INHERIT, TRUE, FALSE) |
Numeric attributes (rotation, indent, fontSize, and @ExcelColumn.width) |
ExcelStyle.UNSET, equal to Integer.MIN_VALUE |
| Text attributes (colours, font name, data format) | the empty string |
Integer.MIN_VALUE is used instead of -1 because -1 is a valid rotation. A plain boolean is not used for yes or no attributes because it cannot express “unset”: Toggle.FALSE explicitly switches an attribute off, while Toggle.INHERIT leaves it to lower levels.
The role of a data cell is its position in the table, and decides which slots apply to it:
- odd or even row. Data rows are numbered from 1, in list order, so the first data row is odd.
- first row and last row. The first and the last element of the data list.
- first column and last column. By position after sorting by
order.
Roles are independent of each other. With one data row, that row is both first and last. With one column, it is both first and last. A header cell has only the first and last column roles. The title has no role.
The cascade
Section titled “The cascade”The effective style of a cell is obtained by laying the applicable styles on top of each other, from the least to the most specific, attribute by attribute. Each level overrides only the attributes it sets and keeps the others. Attributes that no level sets keep the Excel defaults (Calibri 11, no fill, no border, general alignment, General format).
Data cells, from the least to the most specific level:
| Level | Source |
|---|---|
| 1 | the preset body layers, if a preset applies: preset base, then preset odd or even |
| 2 | body.base |
| 3 | body.odd or body.even |
| 4 | the edges of the outer frame (outerBorder) |
| 5 | body.lastColumn, then body.firstColumn |
| 6 | body.lastRow, then body.firstRow |
| 7 | column styles.base |
| 8 | column styles.odd or styles.even |
| 9 | column styles.lastRow, then styles.firstRow |
| 10 | the column format, as data format |
| (final) | the application default format for the kind of value, only when no level set a format |
Header cells, from the least to the most specific level:
| Level | Source |
|---|---|
| 1 | the preset header layer, if a preset applies |
| 2 | header.base |
| 3 | the edges of the outer frame |
| 4 | header.lastColumn, then header.firstColumn |
| 5 | the headerStyle of the column |
Title: the preset title layer, if a preset applies, then titleStyle.
Precedence rules that follow from the cascade
Section titled “Precedence rules that follow from the cascade”The order of the cascade produces a small number of rules worth remembering:
- The row wins over the column. When a body row slot (
firstRow,lastRow) and a body column slot (firstColumn,lastColumn) set the same attribute on the same cell, the row slot wins, because it is applied later. - The first wins over the last. With one data row,
lastRowis applied beforefirstRow, sofirstRowwins. With one column,firstColumnwins overlastColumn. The same holds for the header column slots and for the column row slots. - The column is the most specific level. Column slots come after every table level, so a column can always override the table. Only the column
formatcomes after them. - Header and data are separate. Header slots and column header styles never apply to data cells. Body and column slots never apply to header cells. None of them applies to the title. The header does not inherit anything from the body.
- The frame yields to role slots. The outer frame sits above the base and odd or even levels and below the role slots: a first or last row or column slot, a column slot or a column header style that sets a border side overrides the frame on that side.
- The column format is final.
@ExcelColumn.formatwins over thedataFormatof every style applied to the cell and over the application default formats. - Local wins over shared. A named style declared on the sheet class replaces a style with the same name coming from a style sheet, entirely: the two are not merged.
- Any declared style wins over the preset. The preset is the lowest level of every cascade.
Presets
Section titled “Presets”A preset is a ready-made table style generated by the library from one accent colour. It produces a title layer, a header layer and body layers (base, odd, even), applied below every declared style. A preset is chosen per sheet class (@ExcelSheet.preset) or for the whole application (application defaults), and can be adjusted with ordinary named styles. Presets are described in section 7.