1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
A discussion of the style code, version 0.3
by Jody Goldberg <jody@gnome.org>
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 (style, "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, style);
1.1.2 Getting a style
GnmStyle const *style = sheet_style_get (sheet, col, row);
or
GnmStyle const *style = cell_get_style (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 const *style = cell_get_style (cell);
gnm_style_set_font_size (style, 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 *style = gnm_style_new ();
gnm_style_set_font_name (style, "dingbats");
cell_set_style (cell, style);
style = gnm_style_new ();
gnm_style_set_font_bold (style, TRUE);
cell_set_style (cell, style);
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 *style = gnm_style_new ();
Creating an style in this way hands you a single reference.
sheet_style_set_pos (sheet, col, row, style)
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 (style, 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.
|