Until know, we have filled ODS cells with dynamic content from Python expressions, producing strings, integers, floats or dates. Cells formatting was applied by simply using LibreOffice Calc the standard way, like for any non-POD ODS file. Indeed, this is the main and recommended way to design ODT and ODS templates: use LibreOffice standard options as much as possible, while trying to minimise the injection of Python code. That being said, some situations require to apply styles dynamically. This is where the cell function comes into play.
We will start from the example from the last section, that consisted in producing an ODS file whose rows contained contracts-related data for every employee of some company, during a given month. The result attained so far was the following.
Now, for every cell representing a day, we want:
- to display char "X" if, at this day, we are outside the period defined by the contract. In the example, the month is November 2020. If, according to Mr X's contract, he must start to work for the Appy company at November, the 5th, we expect that a X char will be drawn in the 4 first cells, for days 1 to 4;
- we want every cell corresponding to a Saturday and Sunday to get a grey background.
With what we have learned so far, it is possible to implement item #1 but not item #2.
Achieving item #2 can be done by using a from clause using the cell function and by defining a couple of styles within the ODS document.
Let's start with the from clause. The following screenshot is an excerpt from the initial ODS template example, whose main parts have been removed to highlight the unique cell we want to style.
Column D will be repeated as many times as there are days in variable grid. Moreover, every repeated cell will be filled via the from clause.
The cell function takes 2 args:
- the content of the cell (as a string),
- the name of the style to apply to the cell content.
When using the cell function, any "handmade" cell formatting will be removed. So, if you want to have full control over the appearance of every cell generated from D1, be it a weekday or a weekend day, let's create 2 styles.
In LibreOffice, in the right panel, display the currently applied styles in your ODS document:
Right-click on style Default and create a new style named Weekday having these characteristics.
Taking care of margins and borders is important if you want to produce nicely rendered cells. Once you're done with this style, create yet another one, based on Weekday (right-click on its name) and named WeekEnd:
This one will be exaclty the same than Weekday, excepted that its background color will be grey. Choosing the background color is done via tab "Background" in the popup for style properties.
We are almost done. The from clause, in the ewample, calls the cell function with these args:
do cell for day in grid
from cell(self.getDayChar(_ctx_), style=self.getDayStyle(_ctx_))
We will not dig into implementation of methods getDayChar and getDayStyle, but assume that:
- getDayChar returns the empty string if the current day is within the contract or char X else;
- getDayStyle returns, as a string, the name of the style to use: "WeekEnd" if it is a weekend day and "Weekday" if it is a weekday.
Based on these assumptions, the result would look like this (excerpt).
The _ctx_ context variable
One last remark concerns variable _ctx_ passed as unique arg for the hereabove-mentioned methods. This is a powerful POD functionality: the whole current POD context is itself present in the context (so, in itself!), as variable _ctx_. Incredible, huh? But true. Functions like getDayChar of getDayStyle may require several variables from the context. While you could pass them all as explicit args, while improving your template, you may notice that an additional arg is required; the number of args may start to be long and it augments the complexity of your ODS (or ODT) template. Passing, as a general convention, the context as unique arg for any method or function called within a POD template may be a good idea because it simplifies the whole thing. The context is always a Python dict (even if you pass another type of object to Renderer attribute context).
def getDayChar(self, ctx):
# Accessing context variable "day"
day = ctx['day']
The cell function, as available in the default POD context, corresponds to method importCell defined on class Renderer. You will find hereafter the complete function signature, with a detailed explanation of every parameter.
def importCell(self, content, style='Default'):
'''Creates a chunk of ODF code ready to be dumped as a table cell
containing this content and styled with this style.'''
This is not for ODT
The cell function only works in ODT templates. There is an alternate way to style cells in ODT templates.