A discussion of the style code, version 0.3 by Jody Goldberg In order to solve several of the problems associated with blank cells and to simplify the way styles are handled a new approach to styles was developed by Michael Meeks. This solved all of the problems it set out to address, but became bogged down in performance issues as attempts were made to use it in conjunction with large sheets. Another approach was then developed to build upon the experience of and pitfalls of the Michael's work. 1 Programmers guide 1.1 The raw mechanics. 1.1.1 Applying a style to a region Simply apply the following steps a) Create the style: GnmStyle *empty = gnm_style_new (); GnmStyle *full_of_default_settings = gnm_style_new_default (). b) Set elements: gnm_style_set_font_name (mstyle, "Dingbats"); The passed const font name in this case is hashed and ref-counted internally for efficiency. The only case in which it is necessary to do manual ref-counting is if you wish to apply the same StyleColor pointer to several mstyles but this is unusual. c) Specify the range: GnmRange range range.start.col = 0; range.start.row = 0; range.end.col = 5; range.end.row = 5; This specifies A1:F6. d) Attach it to the sheet: /* Overlay a partially specified style onto the current style */ sheet_style_apply_range (sheet, range, style); /* Use the fully specified style in place of the current style sheet_style_set_range (sheet, range, style); sheet_style_set_pos (sheet, col, row, mstyle); 1.1.2 Getting a style GnmStyle *mstyle = sheet_style_get (sheet, col, row); or GnmStyle *mstyle = cell_get_mstyle (cell); Neither of these adds a reference to the style. If you intend to store the style for later use you will need to ref/unref it. NB. it is important not to try and set elements on a style you have obtained in this way. The way to attach elements is via sheet_style_attach ie. BAD BAD BAD GnmStyle *mstyle = cell_get_mstyle (cell); gnm_style_set_font_size (mstyle, 12.0); BAD BAD BAD Do _not_ even think of doing the above, it will produce wacky results; The next phase of style work will make these things constant. 1.2 Simple points to bear in mind If you do the following: GnmStyle *mstyle = gnm_style_new (); gnm_style_set_font_name (mstyle, "dingbats"); cell_set_style (cell, mstyle); mstyle = gnm_style_new (); gnm_style_set_font_bold (mstyle, TRUE); cell_set_style (cell, mstyle); Then you needlessly create two style regions ( for the same cell ) where one would have sufficed. This is a degenerate case clearly, but happens in real code ( often when subroutines are used ). If you need to build up a style for a range pass an GnmStyle * around and build it up before applying it once. 1.3 Ref counting for dummies. Since the only efficient way to keep copies of styles around is to reference count them the followings ( standard ) conventions are used namely: GnmStyle *mstyle = gnm_style_new (); Creating an mstyle in this way hands you a single reference. sheet_style_set_pos (sheet, col, row, mstyle) Attaching a style passes that reference on to the style code. The way to ascertain whether a style reference has been handed on is to examine the prototype for the function. Should the GnmStyle * parameter be 'const' the reference is _not_ passed, otherwise in general it is ( don't get hung up on that rule ). Of course non const parameters are needed for eg. gnm_style_set_font_name, but these have no conceivable reason to fiddle with the ref-count so they don't. The real gotchas happen when you decide to add a cache to your code to speed up style allocation. In general this is what you want where 'cache' denotes an GnmStyle * cache item. GnmStyle *cache = cache_lookup_fn (gnm_style_cache); if (!cache) { /* We must create the style */ cache = gnm_style_new (); gnm_style_set_font_bold (cache, bold); cache_insert_fn (gnm_style_cache, cache); } gnm_style_ref (cache); /* NB. */ return cache; NB. we 'leave' a reference in the cache. This then must be removed when we flush the cache with a simple gnm_style_unref. 2 Implementation details 2.1 How styles are stored 2.2 How styles are searched 2.3 How 'unique' styles are generated Unique styles are needed for user feedback. This is only used in the cell format dialog, since the toolbar used the settings of the 'terminal' ( first selected ) cell in a selection. The process of generating unique styles is is effectively a merging of all styles with the target regions. Conflicts are marked in the final GnmStyle result and can be tested for using: gnm_style_element_is_conflict (mstyle, GnmStyleElement); 2.3.1 Unique borders Border support is a HUGE pain. The current code uses the get_row facilities for styles and does some simplistic homogeneity tests. The result is correct but can be slow when applied to an entire sheet. We could easily speed it up by providing a specialized accessor (get_uniform_col) that could take advantage of the homogeneity with a tile. 2.4 Further work This document needs some explanation of how elements are stored indexed by type internally. More work could be done to decrease style fragmentation.