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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
<!DOCTYPE book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
]>
<book id="gnumeric-design">
<bookinfo>
<title>The Gnumeric Spreadsheet Internal Design</title>
<releaseinfo>July 2, 1998</releaseinfo>
<author>
<firstname>Miguel</firstname>
<surname>de Icaza</surname>
<affiliation>
<shortaffil>Instituto de Ciencias Nucleares, Universidad
Nacional Autnoma de Mxico
</shortaffil>
</affiliation>
</author>
<address><email>miguel@gnu.org</email></address>
<date>September 2, 1998; July 2, 1999.</date>
</bookinfo>
<chapter>
<title>Gnumeric Internal Design</title>
<sect1>
<title>Design Goals</title>
<para>
The Gnumeric Spreadsheet is a spreadsheet that is intended to
grow in the future to provide all of the features available in
commercial-grade spreadsheets.
</para>
<para>
I am not only intending to provide Gnumeric with a very good
computation engine, but I am also interested in making the GUI
experience for the user as pleasant as possible, and that
includes taking a lot of ideas from existing spreadsheets.
</para>
</sect1>
<sect1>
<title>Target</title>
<para>
Gnumeric should be compatible as much as possible with
Microsoft Excel in terms of the user. This means formulae and
expressions should be compatible unless we find a serious
design problem in Excel.
</para>
<para>
An example of a design problem in Excel is the fact that
various internal functions have limits on the number of
arguments they can take: this is just bad coding and this sort
of limitation is unacceptable in Gnumeric. When writing code
for Gnumeric, no hard coded limits should be set (currently
Gnumeric breaks this rule by having hardcoded, in a few places,
the maximum number of columns to be 256).
</para>
<sect1>
<title>Basic organization</title>
<para>
The Gnumeric spreadsheet is basically organized as Workbooks
(see src/sheet.h for the definition of the workbook object).
There might be various workbooks loaded at the same time.
Every one of these workbooks might have a variable number of
Sheets (see src/sheet.h for the definition of the Sheet
object), and finally each sheet contains cells (The definition
of a Gnumeric Cell is in src/cell.h).
</para>
<itemizedlist>
<listitem>
<para>
Workbooks only take care of keeping various sheets
together and giving a name to them.
</para>
</listitem>
<listitem>
<para>
Item Sheets are the repository of information: cells are
kept here, information on the columns and rows is kept
here, and the styles attached to the regions are also
kept here.
</para>
<para>
Sheets might have multiple views, this is required to
support split views and in the future to support the
GNOME document model. The actual front-end to the Sheet
object is the SheetView object: SheetView object each
one has a number of components:
</para>
<itemizedlist>
<listitem><para>
Their scrollbars.</para>
<listitem><para> Their cell display engine (more in a
second).</para>
<listitem><para> Their bar display (column and row
display).</para>
</itemizedlist>
<para>The cell display engine is basically a modified
GnomeCanvas that can deal with keystrokes and can do some
extra spreadsheet oriented tasks. This cell display
engine is of type GnumericSheet.</para>
<para>GnumericSheet objects usually contain a number of
Gnome Canvas items specially designed to be used for a
spreadsheet: the Grid Item and the Cursor Item:</para>
<itemizedlist>
<listitem><para> The Grid item takes care of rendering the
actual contents of the Sheet object and displaying the
Cells in the way the user requested, this is the
actual "core" display engine.</para>
<listitem><para> The Cursor item is the item that actually
draws the spreadsheet cursor. This item, as every
other Gnome Canvas item can take events and this one
is specially interesting, as it provides the basic
facilities for dragging a region of cells. </para>
</itemizedlist>
<para>
During the course of a user session, Gnumeric will
create Items of type Editor, a special item designed to
display the contents of a cell as it is being typed and
it is syncronized with a GtkEntry (to provide an
Excel-like way of typing text into the cells).
</para>
</itemizedlist>
<para>
Sheets contain information for columns and rows in doubly
linked lists to facilitate their traversal (in the future,
when bottlenecks are identified, we will provide an
alternate quick access method based on hash tables, but the
information will still be linked forward and
backwards).
</para>
<para>
The column and row information is stored in GList's that
contain ColRowInfo structures. These structures include a
number of interesting bits:
</para>
<itemizedlist>
<listitem>
<para>
Their assigned position (or -1 if they are the "default"
style), field name "pos".
</para>
<listitem>
<para>
The actual width used in pixels (for the current
magnification setting) as well as their logical size,
plus the margins required in pixels for displaying
various cell adornements.
</para>
</listitem>
</itemizedlist>
<para>
When a cell is allocated, both ColRowInfos (for column and
row) are allocated and properly linked, the cell is made to
point to these new structures.
</para>
<para>
The column ColRowInfos have a field called "data", this is a
linked list of Cells for every row where a cell
exists.
</para>
<para>
Cells are stored in a hash table inside the Sheet data
structure for quick retrieval and they are also linked
properly in their respective columns.
</para>
<para>
A cell might display information in more than one column, so
Gnumeric needs to keep track of which cells (column, row
pairs) are being managed by which cell. This information is
kept in a per-row fashion in the data pointer in the
ColRowInfo structure for the rows. The registration and
unregistration of the view areas code is on the cellspan.c
file.</para>
</sect1>
<sect1>
<title>Formula storage</title>
<para>
When a formula is encountered, Gnumeric parses the formula
into a tree structure. The tree structure is later used to
evaluate the expression at a given location (each cordinate
in a cell references is stored as either an absolute
reference or a relative reference to the cell position). To
read about the actual implementation of this, look in the
files <filename>gnumeric/src/expr.h</filename>,
<filename>gnumeric/src/expr.c</filename>.
</para>
<para>
To speed up formula duplication, Gnumeric reference counts
the parsed expression, this allow for quick duplication of p
expressions. It should be noted that some file formats (the
Excel file format) uses formula references, which can
preserve the memory saving features of reference counting.
</para>
<para>
Currently Gnumeric does not provide any way to keep these
references, a possible scheme for saving these cells correctly
would be to keep in a special list any formula being
saved that has a reference count bigger than one and keep
track of these duplicates and generate formula references in
the output file rather than outputing the actual formula.
</para>
</sect1>
<sect1>
<title>Resource management</title>
<para>
Data structures in Gnumeric are lightweight, they are
designed to consume little memory by reusing as much
information as possible. This is achieved by making common
information be hashed and reference-counted. This is done
with strings, parser/interprester symbols and styles.
</para>
<para>
To learn more about this, read:
<itemizedlist>
<listitem>
<para>for strings:
<filename>gnumeric/src/str.c</filename> and
<filename>gnumeric/src/str.h</filename>
</para>
</listitem>
<listitem>
<para>for styles:
<filename>gnumeric/src/style.c</filename> and
<filename>gnumeric/src/style.h</filename>.
</para>
</listitem>
<listitem>
<para>
for symbols:
<filename>gnumeric/src/symbol.c</filename> and
<filename>gnumeric/src/symbol.h</filename>
</para>
</listitem>
</para>
</sect1>
<sect1>
<title>Plugins</title>
<para>
Gnumeric's plugin API is very simple. Every plugin must have
one function: init_plugin see
<filename>gnumeric/src/gnm-plugin.h</filename> for the full details.
</para>
</sect1>
</chapter>
</book>
|