GnuCash c935c2f+
Loading...
Searching...
No Matches
table-layout.c
1/********************************************************************\
2 * table-layout.c -- 2D table layout *
3 * Copyright (c) 2001 Free Software Foundation *
4 * Author: Dave Peticolas <dave@krondo.com> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23\********************************************************************/
24
25#include <config.h>
26
27#include <glib.h>
28#include <string.h>
29
30#include "basiccell.h"
31#include "cellblock.h"
32#include "table-layout.h"
33
34
36{
37 GList *cells; /* The cells in the table */
38 GList *cursors; /* The cursors in the table */
39
40 CellBlock *primary_cursor;
41};
42
43typedef struct _CellBuffer CellBuffer;
45{
46 char * cell_name;
47 char * value;
48 guint32 changed;
49 guint32 conditionally_changed;
50};
51
53{
54 GList *cell_buffers;
55};
56
57
58TableLayout *
60{
61 TableLayout *layout;
62
63 layout = g_new0 (TableLayout, 1);
64
65 return layout;
66}
67
68void
69gnc_table_layout_destroy (TableLayout *layout)
70{
71 GList *node;
72
73 if (!layout)
74 return;
75
76 for (node = layout->cells; node; node = node->next)
77 {
78 BasicCell *cell = node->data;
79
80 gnc_basic_cell_destroy (cell);
81 }
82 g_list_free (layout->cells);
83 layout->cells = NULL;
84
85 for (node = layout->cursors; node; node = node->next)
86 {
87 CellBlock *cursor = node->data;
88
89 gnc_cellblock_destroy (cursor);
90 }
91 g_list_free (layout->cursors);
92 layout->cursors = NULL;
93
94 g_free (layout);
95}
96
97void
98gnc_table_layout_add_cell (TableLayout *layout,
99 BasicCell *cell)
100{
101 GList *node;
102
103 g_return_if_fail (layout != NULL);
104 g_return_if_fail (cell != NULL);
105
106 for (node = layout->cells; node; node = node->next)
107 {
108 BasicCell *list_cell = node->data;
109
110 if (gnc_basic_cell_has_name (list_cell, cell->cell_name))
111 {
112 if (list_cell == cell)
113 return;
114
115 gnc_basic_cell_destroy (list_cell);
116 break;
117 }
118 }
119
120 if (!node)
121 layout->cells = g_list_append (layout->cells, cell);
122 else
123 node->data = cell;
124}
125
126BasicCell *
127gnc_table_layout_get_cell (TableLayout *layout, const char *cell_name)
128{
129 GList *node;
130
131 g_return_val_if_fail (layout != NULL, NULL);
132
133 for (node = layout->cells; node; node = node->next)
134 {
135 BasicCell *list_cell = node->data;
136
137 if (gnc_basic_cell_has_name (list_cell, cell_name))
138 return list_cell;
139 }
140
141 return NULL;
142}
143
144const char *
145gnc_table_layout_get_cell_value (TableLayout *layout, const char * cell_name)
146{
147 BasicCell *cell;
148
149 g_return_val_if_fail (layout != NULL, NULL);
150
151 cell = gnc_table_layout_get_cell (layout, cell_name);
152 if (!cell) return NULL;
153
154 return gnc_basic_cell_get_value (cell);
155}
156
157gboolean
158gnc_table_layout_get_cell_changed (TableLayout *layout,
159 const char *cell_name,
160 gboolean include_conditional)
161{
162 BasicCell *cell;
163
164 g_return_val_if_fail (layout != NULL, FALSE);
165
166 cell = gnc_table_layout_get_cell (layout, cell_name);
167 if (!cell) return FALSE;
168
169 if (!include_conditional)
170 return gnc_basic_cell_get_changed (cell);
171 else
172 return (gnc_basic_cell_get_changed (cell) ||
173 gnc_basic_cell_get_conditionally_changed (cell));
174}
175
176GList *
177gnc_table_layout_get_cells (TableLayout *layout)
178{
179 if (!layout)
180 return NULL;
181
182 return layout->cells;
183}
184
185void
186gnc_table_layout_add_cursor (TableLayout *layout,
187 CellBlock *cursor)
188{
189 GList *node;
190
191 g_return_if_fail (layout != NULL);
192 g_return_if_fail (cursor != NULL);
193
194 if (g_list_find (layout->cursors, cursor))
195 return;
196
197 for (node = layout->cursors; node; node = node->next)
198 {
199 CellBlock *list_cursor = node->data;
200
201 if (strcmp (list_cursor->cursor_name, cursor->cursor_name) == 0)
202 {
203 layout->cursors = g_list_remove (layout->cursors, list_cursor);
204 gnc_cellblock_destroy (list_cursor);
205 break;
206 }
207 }
208
209 layout->cursors = g_list_append (layout->cursors, cursor);
210}
211
212CellBlock *
213gnc_table_layout_get_cursor (TableLayout *layout,
214 const char *cursor_name)
215{
216 GList *node;
217
218 g_return_val_if_fail (layout != NULL, NULL);
219
220 if (!cursor_name)
221 return NULL;
222
223 for (node = layout->cursors; node; node = node->next)
224 {
225 CellBlock *cursor = node->data;
226
227 if (strcmp (cursor_name, cursor->cursor_name) == 0)
228 return cursor;
229 }
230
231 return NULL;
232}
233
234GList *
235gnc_table_layout_get_cursors (TableLayout *layout)
236{
237 g_return_val_if_fail (layout != NULL, NULL);
238 return layout->cursors;
239}
240
241void
242gnc_table_layout_set_primary_cursor (TableLayout *layout,
243 CellBlock *cursor)
244{
245 g_return_if_fail (layout != NULL);
246 layout->primary_cursor = cursor;
247}
248
249void
250gnc_table_layout_set_cell (TableLayout *layout,
251 CellBlock *cursor,
252 const char *cell_name,
253 int row, int col)
254{
255 CellBlock *header;
256 BasicCell *cell;
257
258 g_return_if_fail (layout != NULL);
259 g_return_if_fail (layout->primary_cursor != NULL);
260 g_return_if_fail (cursor != NULL);
261 g_return_if_fail (cell_name != NULL);
262 g_return_if_fail (row >= 0);
263 g_return_if_fail (col >= 0);
264 g_return_if_fail (row < cursor->num_rows);
265 g_return_if_fail (col < cursor->num_cols);
266
267 header = gnc_table_layout_get_cursor (layout, CURSOR_HEADER);
268 cell = gnc_table_layout_get_cell (layout, cell_name);
269
270 g_return_if_fail (header != NULL);
271 g_return_if_fail (cell != NULL);
272
273 cursor->start_col = MIN (cursor->start_col, col);
274 cursor->stop_col = MAX (cursor->stop_col, col);
275
276 header->start_col = MIN (header->start_col, col);
277 header->stop_col = MAX (header->stop_col, col);
278
279 gnc_cellblock_set_cell (cursor, row, col, cell);
280
281 if (cursor == layout->primary_cursor)
282 gnc_cellblock_set_cell (header, row, col, cell);
283}
284
285CursorBuffer *
286gnc_cursor_buffer_new (void)
287{
288 CursorBuffer *buffer;
289
290 buffer = g_new0 (CursorBuffer, 1);
291
292 return buffer;
293}
294
295static void
296destroy_cell_buffer (CellBuffer *cb)
297{
298 if (cb == NULL)
299 return;
300
301 g_free (cb->cell_name);
302 cb->cell_name = NULL;
303
304 g_free (cb->value);
305 cb->value = NULL;
306
307 g_free (cb);
308}
309
310static void
311gnc_cursor_buffer_clear (CursorBuffer *buffer)
312{
313 GList *node;
314
315 if (!buffer) return;
316
317 for (node = buffer->cell_buffers; node; node = node->next)
318 {
319 CellBuffer *cb = node->data;
320
321 destroy_cell_buffer (cb);
322 }
323
324 g_list_free (buffer->cell_buffers);
325 buffer->cell_buffers = NULL;
326}
327
328void
329gnc_cursor_buffer_destroy (CursorBuffer *buffer)
330{
331 if (!buffer) return;
332
333 gnc_cursor_buffer_clear (buffer);
334
335 g_free (buffer);
336}
337
338static CellBuffer *
339save_cell (BasicCell *bcell)
340{
341 CellBuffer *cb;
342
343 if (!bcell)
344 return NULL;
345
346 cb = g_new0 (CellBuffer, 1);
347
348 cb->cell_name = g_strdup (bcell->cell_name);
349 cb->value = g_strdup (bcell->value);
350 cb->changed = bcell->changed;
351 cb->conditionally_changed = bcell->conditionally_changed;
352
353 return cb;
354}
355
356void
357gnc_table_layout_save_cursor (TableLayout *layout,
358 CellBlock *cursor,
359 CursorBuffer *buffer)
360{
361 GList *node;
362
363 if (!layout || !cursor || !buffer)
364 return;
365
366 gnc_cursor_buffer_clear (buffer);
367
368 for (node = layout->cells; node; node = node->next)
369 {
370 BasicCell *list_cell = node->data;
371 CellBuffer *cb;
372
373 if (!gnc_basic_cell_get_changed (list_cell) &&
374 !gnc_basic_cell_get_conditionally_changed (list_cell))
375 continue;
376
377 cb = save_cell (list_cell);
378
379 buffer->cell_buffers = g_list_prepend (buffer->cell_buffers, cb);
380 }
381}
382
383static void
384restore_cell (BasicCell *bcell, CellBuffer *cb, CellBlock *cursor)
385{
386 int r, c;
387
388 if (!bcell || !cb || !cursor)
389 return;
390
391 if (!cb->changed && !cb->conditionally_changed)
392 return;
393
394 /* only restore if it's in the current cursor */
395 for (r = 0; r < cursor->num_rows; r++)
396 for (c = 0; c < cursor->num_cols; c++)
397 {
398 BasicCell *cell;
399
400 cell = gnc_cellblock_get_cell (cursor, r, c);
401 if (!cell)
402 continue;
403
404 if (cell == bcell)
405 {
406 gnc_basic_cell_set_value (bcell, cb->value);
407 bcell->changed = cb->changed;
408 bcell->conditionally_changed = cb->conditionally_changed;
409 return;
410 }
411 }
412}
413
414void
415gnc_table_layout_restore_cursor (TableLayout *layout,
416 CellBlock *cursor,
417 CursorBuffer *buffer)
418{
419 GList *node;
420
421 if (!layout || !cursor || !buffer)
422 return;
423
424 for (node = buffer->cell_buffers; node; node = node->next)
425 {
426 CellBuffer *cb = node->data;
427 BasicCell *cell;
428
429 cell = gnc_table_layout_get_cell (layout, cb->cell_name);
430
431 restore_cell (cell, cb, cursor);
432 }
433}
Declarations for the CellBlock object.
BasicCell * gnc_cellblock_get_cell(CellBlock *cellblock, int row, int col)
Retrieve the Cell at the specified coordinates.
Definition cellblock.c:109
void gnc_cellblock_set_cell(CellBlock *cellblock, int row, int col, BasicCell *cell)
Add a cell to the CellBlock at the specified coordinates.
Definition cellblock.c:92
void gnc_cellblock_destroy(CellBlock *cellblock)
Delete a CellBlock and its Cells.
Definition cellblock.c:78
TableLayout * gnc_table_layout_new(void)
API Declarations.
#define CURSOR_HEADER
Standard Cursor Names.
Type definitions.