GnuCash  5.6-150-g038405b370+
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 
43 typedef 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 
58 TableLayout *
60 {
61  TableLayout *layout;
62 
63  layout = g_new0 (TableLayout, 1);
64 
65  return layout;
66 }
67 
68 void
69 gnc_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 
97 void
98 gnc_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 
126 BasicCell *
127 gnc_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 
144 const char *
145 gnc_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 
157 gboolean
158 gnc_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 
176 GList *
177 gnc_table_layout_get_cells (TableLayout *layout)
178 {
179  if (!layout)
180  return NULL;
181 
182  return layout->cells;
183 }
184 
185 void
186 gnc_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 
212 CellBlock *
213 gnc_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 
234 GList *
235 gnc_table_layout_get_cursors (TableLayout *layout)
236 {
237  g_return_val_if_fail (layout != NULL, NULL);
238  return layout->cursors;
239 }
240 
241 void
242 gnc_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 
249 void
250 gnc_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 
285 CursorBuffer *
286 gnc_cursor_buffer_new (void)
287 {
288  CursorBuffer *buffer;
289 
290  buffer = g_new0 (CursorBuffer, 1);
291 
292  return buffer;
293 }
294 
295 static void
296 destroy_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 
310 static void
311 gnc_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 
328 void
329 gnc_cursor_buffer_destroy (CursorBuffer *buffer)
330 {
331  if (!buffer) return;
332 
333  gnc_cursor_buffer_clear (buffer);
334 
335  g_free (buffer);
336 }
337 
338 static CellBuffer *
339 save_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 
356 void
357 gnc_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 
383 static void
384 restore_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 
414 void
415 gnc_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 }
Type definitions.
Definition: table-layout.c:35
TableLayout * gnc_table_layout_new(void)
API Declarations.
Definition: table-layout.c:59
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
void gnc_cellblock_destroy(CellBlock *cellblock)
Delete a CellBlock and its Cells.
Definition: cellblock.c:78
Declarations for the CellBlock object.
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
BasicCell * gnc_cellblock_get_cell(CellBlock *cellblock, int row, int col)
Retrieve the Cell at the specified coordinates.
Definition: cellblock.c:109