1 /********************************************************************\
2 * This program is free software; you can redistribute it and/or *
3 * modify it under the terms of the GNU General Public License as *
4 * published by the Free Software Foundation; either version 2 of *
5 * the License, or (at your option) any later version. *
6 * *
7 * This program is distributed in the hope that it will be useful, *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10 * GNU General Public License for more details. *
11 * *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact: *
14 * *
15 * Free Software Foundation Voice: +1-617-542-5942 *
16 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17 * Boston, MA 02110-1301, USA gnu@gnu.org *
18 * *
19 \********************************************************************/
20
21 /*
22 * configure the cursor styles
23 */
24
25 #include <config.h>
26 #include "gnucash-color.h"
27 #include "gnucash-item-edit.h"
28 #include "gnucash-sheet.h"
29 #include "gnucash-sheetP.h"
30 #include "gnucash-style.h"
31 #include "gnc-engine.h" // For debugging, e.g. ENTER(), LEAVE()
32
33 /** GLOBALS *********************************************************/
34 /* This static indicates the debugging module that this .o belongs to. */
35 #define DEFAULT_STYLE_WIDTH 680
36
37
38 /** Static Globals *****************************************************/
39
40 /* This static indicates the debugging module that this .o belongs to. */
41 static QofLogModule log_module = GNC_MOD_REGISTER;
42
43
44 /** Implementation *****************************************************/
45
46 static gpointer
style_get_key(SheetBlockStyle * style)47 style_get_key (SheetBlockStyle *style)
48 {
49 static gint key;
50
51 key = style->cursor->num_rows;
52
53 return &key;
54 }
55
56 static gpointer
style_create_key(SheetBlockStyle * style)57 style_create_key (SheetBlockStyle *style)
58 {
59 static gint key;
60 gpointer new_key;
61
62 key = style->cursor->num_rows;
63 new_key = g_malloc(sizeof(key));
64 new_key = memcpy(new_key, &key, sizeof(key));
65
66 return new_key;
67 }
68
69 static void
cell_dimensions_construct(gpointer _cd,gpointer user_data)70 cell_dimensions_construct (gpointer _cd, gpointer user_data)
71 {
72 CellDimensions *cd = _cd;
73
74 cd->pixel_width = -1;
75 cd->can_span_over = TRUE;
76 }
77
78
79 static BlockDimensions *
style_dimensions_new(SheetBlockStyle * style)80 style_dimensions_new (SheetBlockStyle *style)
81 {
82 BlockDimensions *dimensions;
83
84 dimensions = g_new0 (BlockDimensions, 1);
85
86 dimensions->nrows = style->nrows;
87 dimensions->ncols = style->ncols;
88
89 dimensions->cell_dimensions = g_table_new (sizeof (CellDimensions),
90 cell_dimensions_construct,
91 NULL, NULL);
92
93 g_table_resize (dimensions->cell_dimensions,
94 style->nrows, style->ncols);
95
96 return dimensions;
97 }
98
99 static void
style_dimensions_destroy(BlockDimensions * dimensions)100 style_dimensions_destroy (BlockDimensions *dimensions)
101 {
102 if (dimensions == NULL)
103 return;
104
105 dimensions->refcount--;
106
107 if (dimensions->refcount == 0)
108 {
109 g_table_destroy (dimensions->cell_dimensions);
110 dimensions->cell_dimensions = NULL;
111
112 g_free(dimensions);
113 }
114 }
115
116
117 static void
gnucash_style_dimensions_init(GnucashSheet * sheet,SheetBlockStyle * style)118 gnucash_style_dimensions_init (GnucashSheet *sheet, SheetBlockStyle *style)
119 {
120 BlockDimensions *dimensions;
121
122 dimensions = g_hash_table_lookup (sheet->dimensions_hash_table,
123 style_get_key (style));
124
125 if (!dimensions)
126 {
127 dimensions = style_dimensions_new (style);
128 g_hash_table_insert (sheet->dimensions_hash_table,
129 style_create_key (style), dimensions);
130 }
131
132 dimensions->refcount++;
133
134 style->dimensions = dimensions;
135 }
136
137
138 CellDimensions *
gnucash_style_get_cell_dimensions(SheetBlockStyle * style,int row,int col)139 gnucash_style_get_cell_dimensions (SheetBlockStyle *style, int row, int col)
140 {
141 if (style == NULL)
142 return NULL;
143 if (style->dimensions == NULL)
144 return NULL;
145 if (style->dimensions->cell_dimensions == NULL)
146 return NULL;
147
148 return g_table_index (style->dimensions->cell_dimensions, row, col);
149 }
150
151 static int
compute_row_width(BlockDimensions * dimensions,int row,int col1,int col2)152 compute_row_width (BlockDimensions *dimensions, int row, int col1, int col2)
153 {
154 int j;
155 int width = 0;
156
157 col1 = MAX(0, col1);
158 col2 = MIN(col2, dimensions->ncols - 1);
159
160 for (j = col1; j <= col2; j++)
161 {
162 CellDimensions *cd;
163 cd = g_table_index (dimensions->cell_dimensions, row, j);
164
165 if (!cd)
166 continue;
167
168 width += cd->pixel_width;
169 }
170
171 return width;
172 }
173
174
175 /* This sets the initial sizes of the cells, based on the sample_text */
176 static void
set_dimensions_pass_one(GnucashSheet * sheet,CellBlock * cursor,BlockDimensions * dimensions)177 set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
178 BlockDimensions *dimensions)
179 {
180 CellDimensions *cd;
181 int row, col;
182 gint max_height = -1;
183 PangoLayout *layout;
184 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
185
186 /* g_return_if_fail (font != NULL); */
187
188 for (row = 0; row < cursor->num_rows; row++)
189 {
190 for (col = 0; col < cursor->num_cols; col++)
191 {
192 int width;
193 char *text;
194 BasicCell *cell;
195
196 cd = g_table_index (dimensions->cell_dimensions,
197 row, col);
198
199 cell = gnc_cellblock_get_cell (cursor, row, col);
200 if (!cell || !cd)
201 continue;
202
203 text = cell->sample_text;
204 if (text)
205 cd->can_span_over = FALSE;
206
207 if (text)
208 {
209 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
210 pango_layout_get_pixel_size (layout, &width, &cd->pixel_height);
211 g_object_unref (layout);
212 width += gnc_item_edit_get_margin (item_edit, left_right) +
213 gnc_item_edit_get_padding_border (item_edit, left_right);
214
215 // This is used on new popup cells to get the default
216 // width of text plus toggle button.
217 if (cell && cell->is_popup)
218 width += gnc_item_edit_get_button_width (item_edit) + 2; // + 2 for the button margin
219
220 cd->pixel_height += gnc_item_edit_get_margin (item_edit, top_bottom) +
221 gnc_item_edit_get_padding_border (item_edit, top_bottom);
222 }
223 else
224 {
225 width = 0;
226 cd->pixel_height = gnc_item_edit_get_margin (item_edit, top_bottom) +
227 gnc_item_edit_get_padding_border (item_edit, top_bottom);
228 }
229 // add 1 to cd->pixel_height to allow for a cell border
230 max_height = MAX(max_height, cd->pixel_height + 1);
231
232 if (cd->pixel_width > 0)
233 continue;
234
235 cd->pixel_width = MAX (cd->pixel_width, width);
236 }
237
238 dimensions->height += max_height;
239 }
240
241 for (row = 0; row < cursor->num_rows; row++)
242 {
243 for (col = 0; col < cursor->num_cols; col++)
244 {
245 cd = g_table_index (dimensions->cell_dimensions,
246 row, col);
247 if (!cd)
248 continue;
249
250 cd->pixel_height = max_height;
251 }
252 }
253 }
254
255
256 /* Now adjust things to make everything even. This code assumes that
257 * all cursors have the same number of columns!!! */
258 static void
set_dimensions_pass_two(GnucashSheet * sheet,int default_width)259 set_dimensions_pass_two (GnucashSheet *sheet, int default_width)
260 {
261 SheetBlockStyle *style;
262 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
263 BlockDimensions *dimensions;
264 CellDimensions *cd;
265 GTable *cd_table;
266 CellBlock *cursor;
267 GList *cursors;
268 GList *node;
269
270 int num_cols;
271 int *widths;
272 int width;
273 int row, col;
274
275 style = gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
276 dimensions = style->dimensions;
277 cd_table = dimensions->cell_dimensions;
278 cursor = style->cursor;
279
280 width = 0;
281 num_cols = cursor->num_cols;
282 widths = g_new (int, num_cols);
283
284 /* find header widths */
285 for (col = 0; col < num_cols; col++)
286 {
287 cd = g_table_index (cd_table, 0, col);
288
289 if (!cd)
290 continue;
291
292 widths[col] = cd->pixel_width;
293 width += cd->pixel_width;
294 }
295
296 if (width < default_width)
297 for (col = 0; col < num_cols; col++)
298 {
299 BasicCell *cell;
300
301 cell = gnc_cellblock_get_cell (cursor, 0, col);
302
303 if (!cell || !cell->expandable)
304 continue;
305
306 cd = g_table_index (cd_table, 0, col);
307
308 if (!cd)
309 continue;
310
311 cd->pixel_width += (default_width - width);
312 widths[col] = cd->pixel_width;
313
314 break;
315 }
316 else if (width > default_width && width == sheet->window_width)
317 {
318 for (col = 0; col < num_cols; col++)
319 {
320 BasicCell *cell;
321 const char *text;
322 int sample_width;
323 int old_width;
324 PangoLayout *layout;
325
326 cell = gnc_cellblock_get_cell (cursor, 0, col);
327
328 if (!cell || !cell->expandable)
329 continue;
330
331 cd = g_table_index (cd_table, 0, col);
332
333 if (!cd)
334 continue;
335
336 cd->pixel_width += (default_width - width);
337
338 text = cell->sample_text;
339 if (text)
340 {
341 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
342 pango_layout_get_pixel_size (layout, &sample_width, NULL);
343 g_object_unref (layout);
344 /*sample_width = gdk_string_width (font, text);*/
345 sample_width += gnc_item_edit_get_margin (item_edit, left_right) +
346 gnc_item_edit_get_padding_border (item_edit, left_right);
347 }
348 else
349 sample_width = 0;
350
351 cd->pixel_width = MAX (cd->pixel_width, sample_width);
352
353 widths[col] = cd->pixel_width;
354
355 break;
356 }
357 }
358
359 cursors = gnc_table_layout_get_cursors (sheet->table->layout);
360
361 /* adjust widths to be consistent */
362 for (node = cursors; node; node = node->next)
363 {
364 cursor = node->data;
365 style = gnucash_sheet_get_style_from_cursor
366 (sheet, cursor->cursor_name);
367 dimensions = style->dimensions;
368 cd_table = dimensions->cell_dimensions;
369
370 for (row = 0; row < cursor->num_rows; row++)
371 for (col = 0; col < num_cols; col++)
372 {
373 cd = g_table_index (cd_table, row, col);
374
375 if (!cd)
376 continue;
377
378 cd->pixel_width = widths[col];
379 }
380 }
381
382 /* now expand spanning cells */
383 for (node = cursors; node; node = node->next)
384 {
385 CellDimensions *cd_span;
386
387 cursor = node->data;
388 style = gnucash_sheet_get_style_from_cursor
389 (sheet, cursor->cursor_name);
390 dimensions = style->dimensions;
391 cd_table = dimensions->cell_dimensions;
392
393 for (row = 0; row < cursor->num_rows; row++)
394 {
395 cd_span = NULL;
396
397 for (col = 0; col < num_cols; col++)
398 {
399 BasicCell *cell;
400
401 cell = gnc_cellblock_get_cell (cursor,
402 row, col);
403 if (!cell)
404 continue;
405
406 cd = g_table_index (cd_table, row, col);
407
408 if (cell->span)
409 {
410 cd_span = cd;
411 continue;
412 }
413
414 if (!cd || !cd->can_span_over)
415 continue;
416
417 if (cd_span == NULL)
418 continue;
419
420 if (cell->sample_text != NULL)
421 {
422 cd_span = NULL;
423 continue;
424 }
425
426 if (cd->pixel_width <= 0)
427 continue;
428
429 cd_span->pixel_width += cd->pixel_width;
430 cd->pixel_width = 0;
431 }
432 }
433 }
434
435 g_free (widths);
436 }
437
438 gint
gnucash_style_row_width(SheetBlockStyle * style,int row)439 gnucash_style_row_width(SheetBlockStyle *style, int row)
440 {
441 BlockDimensions *dimensions;
442
443 dimensions = style->dimensions;
444
445 return compute_row_width(dimensions, row, 0, dimensions->ncols - 1);
446 }
447
448 static void
compute_cell_origins_x(BlockDimensions * dimensions)449 compute_cell_origins_x (BlockDimensions *dimensions)
450 {
451 int x;
452 int i, j;
453
454 for (i = 0; i < dimensions->nrows; i++)
455 {
456 x = 0;
457
458 for (j = 0; j < dimensions->ncols; j++)
459 {
460 CellDimensions *cd;
461
462 cd = g_table_index (dimensions->cell_dimensions, i, j);
463
464 if (!cd)
465 continue;
466
467 cd->origin_x = x;
468 x += cd->pixel_width;
469 }
470 }
471 }
472
473 static void
compute_cell_origins_y(BlockDimensions * dimensions)474 compute_cell_origins_y (BlockDimensions *dimensions)
475 {
476 CellDimensions *cd;
477 int y = 0;
478 int i, j;
479
480 for (i = 0; i < dimensions->nrows; i++)
481 {
482 for (j = 0; j < dimensions->ncols; j++)
483 {
484 cd = g_table_index (dimensions->cell_dimensions, i, j);
485
486 if (!cd)
487 continue;
488
489 cd->origin_y = y;
490 }
491 cd = g_table_index (dimensions->cell_dimensions, i, 0);
492
493 if (!cd)
494 continue;
495
496 y += cd->pixel_height;
497 }
498 }
499
500 /* Calculate the widths and offsets */
501 static void
set_dimensions_pass_three(GnucashSheet * sheet)502 set_dimensions_pass_three (GnucashSheet *sheet)
503 {
504 GList *cursors;
505 GList *node;
506
507 cursors = gnc_table_layout_get_cursors (sheet->table->layout);
508
509 for (node = cursors; node; node = node->next)
510 {
511 CellBlock *cursor = node->data;
512
513 SheetBlockStyle *style;
514 BlockDimensions *dimensions;
515
516 style = gnucash_sheet_get_style_from_cursor
517 (sheet, cursor->cursor_name);
518 dimensions = style->dimensions;
519
520 dimensions->width = compute_row_width (dimensions, 0, 0,
521 dimensions->ncols - 1);
522
523 compute_cell_origins_x (dimensions);
524 compute_cell_origins_y (dimensions);
525 }
526 }
527
528 static void
styles_recompute_layout_dimensions(GnucashSheet * sheet,int default_width)529 styles_recompute_layout_dimensions (GnucashSheet *sheet, int default_width)
530 {
531 CellBlock *cursor;
532 SheetBlockStyle *style;
533 BlockDimensions *dimensions;
534 GList *cursors;
535 GList *node;
536
537 cursors = gnc_table_layout_get_cursors (sheet->table->layout);
538
539 for (node = cursors; node; node = node->next)
540 {
541 cursor = node->data;
542
543 style = gnucash_sheet_get_style_from_cursor
544 (sheet, cursor->cursor_name);
545
546 dimensions = style->dimensions;
547
548 dimensions->height = 0;
549 dimensions->width = default_width;
550
551 set_dimensions_pass_one (sheet, cursor, dimensions);
552 }
553
554 set_dimensions_pass_two (sheet, default_width);
555 set_dimensions_pass_three (sheet);
556 }
557
558 void
gnucash_sheet_styles_set_dimensions(GnucashSheet * sheet,int default_width)559 gnucash_sheet_styles_set_dimensions (GnucashSheet *sheet, int default_width)
560 {
561 g_return_if_fail (sheet != NULL);
562 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
563
564 styles_recompute_layout_dimensions (sheet, default_width);
565 }
566
567 gint
gnucash_style_col_is_resizable(SheetBlockStyle * style,int col)568 gnucash_style_col_is_resizable (SheetBlockStyle *style, int col)
569 {
570 if (col < 0 || col >= style->ncols)
571 return FALSE;
572
573 return TRUE;
574 }
575
576 void
gnucash_sheet_set_col_width(GnucashSheet * sheet,int col,int width)577 gnucash_sheet_set_col_width (GnucashSheet *sheet, int col, int width)
578 {
579 CellDimensions *cd;
580 SheetBlockStyle *style;
581 int total;
582 int diff;
583
584 g_return_if_fail (sheet != NULL);
585 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
586 g_return_if_fail (col >= 0);
587
588 if (width < 0)
589 return;
590
591 style = gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
592
593 g_return_if_fail (col < style->ncols);
594
595 cd = gnucash_style_get_cell_dimensions (style, 0, col);
596 if (!cd) return;
597
598 /* adjust the overall width of this style */
599 diff = cd->pixel_width - width;
600 cd->pixel_width = width;
601
602 total = MAX (sheet->window_width, sheet->width - diff);
603
604 set_dimensions_pass_two (sheet, total);
605 set_dimensions_pass_three (sheet);
606 }
607
608
609 void
gnucash_sheet_styles_recompile(GnucashSheet * sheet)610 gnucash_sheet_styles_recompile(GnucashSheet *sheet)
611 {
612 }
613
614
615 void
gnucash_sheet_get_borders(GnucashSheet * sheet,VirtualLocation virt_loc,PhysicalCellBorders * borders)616 gnucash_sheet_get_borders (GnucashSheet *sheet, VirtualLocation virt_loc,
617 PhysicalCellBorders *borders)
618 {
619 SheetBlockStyle *style;
620 PhysicalCellBorderLineStyle line_style;
621
622 g_return_if_fail (sheet != NULL);
623 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
624
625 line_style = sheet->use_horizontal_lines ?
626 CELL_BORDER_LINE_NORMAL : CELL_BORDER_LINE_NONE;
627
628 borders->top = line_style;
629 borders->bottom = line_style;
630
631 line_style = sheet->use_vertical_lines ?
632 CELL_BORDER_LINE_NORMAL : CELL_BORDER_LINE_NONE;
633
634 borders->left = line_style;
635 borders->right = line_style;
636
637 style = gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
638 if (style)
639 if (virt_loc.phys_col_offset == (style->ncols - 1))
640 borders->right = CELL_BORDER_LINE_NORMAL;
641
642 if (virt_cell_loc_equal (virt_loc.vcell_loc,
643 sheet->table->current_cursor_loc.vcell_loc))
644 {
645 borders->top = CELL_BORDER_LINE_NORMAL;
646 borders->bottom = CELL_BORDER_LINE_NORMAL;
647 }
648
649 gnc_table_get_borders (sheet->table, virt_loc, borders);
650 }
651
652
653 static SheetBlockStyle *
gnucash_sheet_style_new(GnucashSheet * sheet,CellBlock * cursor)654 gnucash_sheet_style_new (GnucashSheet *sheet, CellBlock *cursor)
655 {
656 SheetBlockStyle *style;
657
658 g_return_val_if_fail (sheet != NULL, NULL);
659 g_return_val_if_fail (GNUCASH_IS_SHEET (sheet), NULL);
660 g_return_val_if_fail (cursor != NULL, NULL);
661
662 style = g_new0 (SheetBlockStyle, 1);
663
664 style->cursor = cursor;
665
666 style->nrows = cursor->num_rows;
667 style->ncols = cursor->num_cols;
668
669 gnucash_style_dimensions_init (sheet, style);
670
671 return style;
672 }
673
674 static void
destroy_style_helper(gpointer key,gpointer value,gpointer user_data)675 destroy_style_helper (gpointer key, gpointer value, gpointer user_data)
676 {
677 char *cursor_name = key;
678 SheetBlockStyle *style = value;
679 GnucashSheet *sheet = user_data;
680
681 gnucash_sheet_style_unref (sheet, style);
682 g_free (cursor_name);
683 }
684
685 void
gnucash_sheet_clear_styles(GnucashSheet * sheet)686 gnucash_sheet_clear_styles (GnucashSheet *sheet)
687 {
688 g_return_if_fail (sheet != NULL);
689 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
690
691 g_hash_table_foreach (sheet->cursor_styles,
692 destroy_style_helper, sheet);
693 }
694
695 void
gnucash_sheet_create_styles(GnucashSheet * sheet)696 gnucash_sheet_create_styles (GnucashSheet *sheet)
697 {
698 GList *cursors;
699 GList *node;
700
701 g_return_if_fail (sheet != NULL);
702 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
703
704 gnucash_sheet_clear_styles (sheet);
705
706 cursors = gnc_table_layout_get_cursors (sheet->table->layout);
707
708 for (node = cursors; node; node = node->next)
709 {
710 CellBlock *cursor = node->data;
711 SheetBlockStyle *style = gnucash_sheet_style_new (sheet, cursor);
712
713 gnucash_sheet_style_ref (sheet, style);
714 g_hash_table_insert (sheet->cursor_styles,
715 g_strdup (cursor->cursor_name),
716 style);
717 }
718 }
719
720 void
gnucash_sheet_compile_styles(GnucashSheet * sheet)721 gnucash_sheet_compile_styles (GnucashSheet *sheet)
722 {
723 g_return_if_fail (sheet != NULL);
724 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
725
726 ENTER("sheet=%p", sheet);
727
728 gnucash_sheet_styles_set_dimensions (sheet, DEFAULT_STYLE_WIDTH);
729
730 LEAVE(" ");
731 }
732
733 void
gnucash_sheet_style_destroy(GnucashSheet * sheet,SheetBlockStyle * style)734 gnucash_sheet_style_destroy (GnucashSheet *sheet, SheetBlockStyle *style)
735 {
736 if (sheet == NULL)
737 return;
738 if (style == NULL)
739 return;
740
741 style->dimensions->refcount--;
742
743 if (style->dimensions->refcount == 0)
744 {
745 style_dimensions_destroy (style->dimensions);
746 g_hash_table_remove (sheet->dimensions_hash_table,
747 style_get_key (style));
748 }
749
750 g_free (style);
751 }
752
753
754 void
gnucash_sheet_style_get_cell_pixel_rel_coords(SheetBlockStyle * style,gint cell_row,gint cell_col,gint * x,gint * y,gint * w,gint * h)755 gnucash_sheet_style_get_cell_pixel_rel_coords (SheetBlockStyle *style,
756 gint cell_row, gint cell_col,
757 gint *x, gint *y,
758 gint *w, gint *h)
759 {
760 CellDimensions *cd;
761
762 g_return_if_fail (style != NULL);
763 g_return_if_fail (cell_row >= 0 && cell_row <= style->nrows);
764 g_return_if_fail (cell_col >= 0 && cell_col <= style->ncols);
765
766 cd = gnucash_style_get_cell_dimensions (style, cell_row, cell_col);
767 if (!cd) return;
768
769 *x = cd->origin_x;
770 *y = cd->origin_y;
771 *h = cd->pixel_height;
772 *w = cd->pixel_width;
773 }
774
775
776 SheetBlockStyle *
gnucash_sheet_get_style(GnucashSheet * sheet,VirtualCellLocation vcell_loc)777 gnucash_sheet_get_style (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
778 {
779 SheetBlock *block;
780
781 g_return_val_if_fail (sheet != NULL, NULL);
782 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
783
784 block = gnucash_sheet_get_block (sheet, vcell_loc);
785
786 if (block)
787 return block->style;
788 else
789 return NULL;
790 }
791
792
793 SheetBlockStyle *
gnucash_sheet_get_style_from_table(GnucashSheet * sheet,VirtualCellLocation vcell_loc)794 gnucash_sheet_get_style_from_table (GnucashSheet *sheet,
795 VirtualCellLocation vcell_loc)
796 {
797 Table *table;
798 VirtualCell *vcell;
799 CellBlock *cursor;
800 SheetBlockStyle *style;
801
802 g_return_val_if_fail (sheet != NULL, NULL);
803 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
804
805 table = sheet->table;
806
807 vcell = gnc_table_get_virtual_cell (table, vcell_loc);
808
809 if (!vcell)
810 return NULL;
811
812 cursor = vcell->cellblock;
813
814 style = gnucash_sheet_get_style_from_cursor (sheet,
815 cursor->cursor_name);
816 if (style)
817 return style;
818
819 return gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
820 }
821
822 SheetBlockStyle *
gnucash_sheet_get_style_from_cursor(GnucashSheet * sheet,const char * cursor_name)823 gnucash_sheet_get_style_from_cursor (GnucashSheet *sheet,
824 const char *cursor_name)
825 {
826 g_return_val_if_fail (sheet != NULL, NULL);
827 g_return_val_if_fail (GNUCASH_IS_SHEET (sheet), NULL);
828
829 if (!cursor_name)
830 return NULL;
831
832 return g_hash_table_lookup (sheet->cursor_styles, cursor_name);
833 }
834
835 /*
836 * For now, refcounting doesn't do much, but later we may want to
837 * destroy styles
838 */
839
840 void
gnucash_sheet_style_ref(GnucashSheet * sheet,SheetBlockStyle * style)841 gnucash_sheet_style_ref (GnucashSheet *sheet, SheetBlockStyle *style)
842 {
843 g_return_if_fail (style != NULL);
844
845 style->refcount++;
846 }
847
848
849 void
gnucash_sheet_style_unref(GnucashSheet * sheet,SheetBlockStyle * style)850 gnucash_sheet_style_unref (GnucashSheet *sheet, SheetBlockStyle *style)
851 {
852 g_return_if_fail (style != NULL);
853
854 style->refcount--;
855
856 if (style->refcount == 0)
857 gnucash_sheet_style_destroy (sheet, style);
858 }
859
860 typedef struct
861 {
862 char *cell_name;
863 int width;
864 } WidthNode;
865
866 GNCHeaderWidths
gnc_header_widths_new(void)867 gnc_header_widths_new (void)
868 {
869 return g_hash_table_new (g_str_hash, g_str_equal);
870 }
871
872 static void
header_width_destroy_helper(gpointer key,gpointer value,gpointer user_data)873 header_width_destroy_helper (gpointer key, gpointer value, gpointer user_data)
874 {
875 WidthNode *wn = value;
876
877 g_free (wn->cell_name);
878 wn->cell_name = NULL;
879
880 g_free (wn);
881 }
882
883 void
gnc_header_widths_destroy(GNCHeaderWidths widths)884 gnc_header_widths_destroy (GNCHeaderWidths widths)
885 {
886 if (!widths) return;
887 g_hash_table_foreach (widths, header_width_destroy_helper, NULL);
888 g_hash_table_destroy (widths);
889 }
890
891 void
gnc_header_widths_set_width(GNCHeaderWidths widths,const char * cell_name,int width)892 gnc_header_widths_set_width (GNCHeaderWidths widths,
893 const char *cell_name,
894 int width)
895 {
896 WidthNode *wn;
897
898 g_return_if_fail (widths != NULL);
899 g_return_if_fail (cell_name != NULL);
900
901 wn = g_hash_table_lookup (widths, cell_name);
902 if (!wn)
903 {
904 wn = g_new0 (WidthNode, 1);
905
906 wn->cell_name = g_strdup (cell_name);
907
908 g_hash_table_insert (widths, wn->cell_name, wn);
909 }
910
911 wn->width = width;
912 }
913
914 int
gnc_header_widths_get_width(GNCHeaderWidths widths,const char * cell_name)915 gnc_header_widths_get_width (GNCHeaderWidths widths,
916 const char *cell_name)
917 {
918 WidthNode *wn;
919
920 g_return_val_if_fail (widths != NULL, 0);
921
922 wn = g_hash_table_lookup (widths, cell_name);
923 if (!wn)
924 return 0;
925
926 return wn->width;
927 }
928
929 void
gnucash_sheet_get_header_widths(GnucashSheet * sheet,GNCHeaderWidths widths)930 gnucash_sheet_get_header_widths (GnucashSheet *sheet,
931 GNCHeaderWidths widths)
932 {
933 SheetBlockStyle *style;
934 CellBlock *header;
935 int row, col;
936
937 g_return_if_fail (sheet != NULL);
938 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
939
940 style = gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
941 g_return_if_fail (style != NULL);
942
943 header = style->cursor;
944 g_return_if_fail (header != NULL);
945
946 for (row = 0; row < style->nrows; row++)
947 for (col = 0; col < style->ncols; col++)
948 {
949 CellDimensions *cd;
950 BasicCell *cell;
951
952 cd = gnucash_style_get_cell_dimensions (style,
953 row, col);
954 if (cd == NULL)
955 continue;
956
957 cell = gnc_cellblock_get_cell (header, row, col);
958 if (!cell || !cell->cell_name)
959 continue;
960
961 gnc_header_widths_set_width (widths,
962 cell->cell_name,
963 cd->pixel_width);
964 }
965 }
966
967 void
gnucash_sheet_set_header_widths(GnucashSheet * sheet,GNCHeaderWidths widths)968 gnucash_sheet_set_header_widths (GnucashSheet *sheet,
969 GNCHeaderWidths widths)
970 {
971 SheetBlockStyle *style;
972 CellBlock *header;
973 int row, col;
974
975 g_return_if_fail (sheet != NULL);
976 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
977
978 style = gnucash_sheet_get_style_from_cursor (sheet, CURSOR_HEADER);
979 g_return_if_fail (style != NULL);
980
981 header = style->cursor;
982 g_return_if_fail (header != NULL);
983
984 for (row = 0; row < style->nrows; row++)
985 for (col = 0; col < style->ncols; col++)
986 {
987 CellDimensions *cd;
988 BasicCell *cell;
989
990 cd = gnucash_style_get_cell_dimensions (style,
991 row, col);
992
993 cell = gnc_cellblock_get_cell (header, row, col);
994 if (!cell || !cell->cell_name || !cd)
995 continue;
996
997 cd->pixel_width = gnc_header_widths_get_width
998 (widths, cell->cell_name);
999 }
1000 }
1001
1002 gboolean
gnucash_style_init(void)1003 gnucash_style_init (void)
1004 {
1005 return TRUE;
1006 }
1007
1008
1009