Revision as of 22:50, 16 April 2012
Styles in ODF
Styles is a complex subject in ODF but the basic ideas are simple.
A 'style' is a collection of properties, each of them with a name and a value. They are collected into property sets that apply to specific types of data. For example, a style that applies to text in general have text-properties only. A style that applies to paragraphs has both text-properties and paragraph-properties. Other types of styles have other property sets depending on which type of data they apply to.
The two main files in an ODF zip store are called content.xml and styles.xml. The file styles.xml contains so called named styles, i.e. those that the user can choose between in a typical user interface. Paragraph styles like "Default", "Heading 1", etc. is the typical example, but also other types of styles can be named: Character styles, graphic styles, table styles, cell styles (spreadsheets), chart styles and so on.
Now, suppose the user makes a formatting change that does not involve applying a named style or changing a named style, such as setting some characters to bold. In this case a new style without a name is created to hold the difference between the properties of the named style that apply to the text in question and the actual format. In our example the only property that it will hold is the bold property.
Such a an unnamed style is called automatic style because they are created automatically when formatting is changed. These automatic styles are stored in the same file as the data they refer to which means content.xml with a few exceptions. The exception is when the actual contents are stored in styles.xml like page headers and footers in text documents (headers/footers are part of the page style).
Named style can have a parent style, which means that when a property is not defined in the style it is also looked up in the parent style. If it is not found there then the parent's parent is searched and so on. All automatic styles have a parent style, which is a named style. An automatic style can never have another automatic style as parent.
A document can also define so called default style which are used when a property is not found anywhere along the chain of parent styles. If a property isn't found even there its value is undefined and it is up to each application to define the default values.
Styles in Calligra
Style handling in Calligra is not perfect at this time (version 2.4). In general, the idea is that when an ODF file is loaded the first thing that should happen is that all the styles are loaded into a style manager. Then the contents of the document is loaded and the appropriate styling is applied to it depending on the styles in the style manager.
That is what is happening in some parts of Calligra, specifically Calligra Words and the styles that have to do with text: text, paragraph, table, table-row, table-column, and table-cell properties. In other applications and other types of styles this is not so well organized. In particular graphic styles are never loaded in this way, which is a problem.
If you want to know more details of how styles work inside Calligra, see Internals of Styles in Calligra. But you should probably read and understand this overview first.
Styles and loading
Despite the missing loading and storing of named styles things work reasonably well, at least when it comes to the visual appearance.
The central class when loading the contents is the KoStyleStack. When loading an object, there can be several styles that are valid for this object. For example a textobject on a page has styles 'pr3' and 'P7' and a paragraph in that textobject has styles 'P1' and 'T3'. And all of these styles may have parent styles. If you want to know if there is, for example, the attribute 'fo:font-family' for this paragraph, you have to look into style 'T3', 'P1', 'P7' and 'pr3' in that order. When you find this attribute in one style you have to stop processing the list and take the found attribute for this object.
This is what KoStyleStack does. When the contents is traversed some styles come into scope and some go out of scope. When a new object with a new style comes into scope the style is pushed on the style stack together with its parent tree and when the value of a property is needed the style stack is probed rather than the individual style. This means that the individual properties will be correct for each object even if the named styles are not handled correctly. The KoStyleStack is only used during the loading process. When the loading is done the style stack is discarded.
Styles during editing
During the editing of the document it is up to each data object to keep track of all formatting properties that are relevant to it. For the text styles, the KoStyleManager in libs/kotext/ keeps track of the named styles that have to do with text but for graphic and other types of styles there is no such equivalent. However, all the individual properties for each object, down to a text fragment or a simple graphic shape, are stored inside these objects.
There is a visual style manager that allows the user to add new styles or edit or delete the already existing ones. When a style is changed, the changes are applied to the text elements that have those styles. Parts of this style manager are disabled for Calligra 2.4, though.
This system should be extended to the types of styles that are not yet handled by the KoStyleManager.
Styles and Saving
When saving the central classes are KoGenStyles and KoGenStyle. These are used when creating the automatic styles in styles.xml and content.xml.
KoGenStyles collects a set of KoGenStyle items. When the saving starts, it is first loaded with the set of named styles if that set is retained.
An object that wants to save its formatting properties creates a new KoGenStyle and puts all its formatting properties into it. It also sets the parent style. Then it adds the KoGenŚtyle to KoGenStyles which examines the KoGenStyle and removes all the properties that are also part of the parent styles or the parent's parent and so on.
The remaining set of properties is compared to the automatic styles already in the set. If there is an exact equivalent the name of that style is returned. Otherwise the new KoGenStyle is added to the set and a new name is generated and returned. The returned name is then used as the style name for the object in question and saved in the XML attributes for that object.
When all the contents of the document is saved and all the styles are generated, the KoGenStyles object contains the minimal set of automatic styles for that document. This set is then saved to content.xml and styles.xml depending on where each automatic styles is supposed to end up.