33#include <gdk/gdkkeysyms.h>
38#include "dialog-utils.h"
50# include <gdk/gdkwin32.h>
53#define DEFAULT_SHEET_HEIGHT 400
54#define DEFAULT_SHEET_WIDTH 400
56#define DEFAULT_SHEET_INITIAL_ROWS 10
72static QofLogModule log_module = G_LOG_DOMAIN;
76static void gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet);
78static gboolean gnucash_sheet_cursor_move (GnucashSheet *sheet,
79 VirtualLocation virt_loc);
81static void gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet);
82static void gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
83 gboolean changed_cells);
84static void gnucash_sheet_stop_editing (GnucashSheet *sheet);
85gboolean gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr,
86 G_GNUC_UNUSED gpointer data);
90G_DEFINE_TYPE (GnucashSheet, gnucash_sheet, GTK_TYPE_LAYOUT);
101gnucash_sheet_set_entry_selection (GnucashSheet *sheet)
103 DEBUG(
"Set entry selection to sheet: %d:%d", sheet->bound, sheet->pos);
104 gtk_editable_select_region (GTK_EDITABLE(sheet->entry),
105 sheet->bound, sheet->pos);
109gnucash_sheet_set_selection_from_entry (GnucashSheet *sheet)
111 gtk_editable_get_selection_bounds (GTK_EDITABLE(sheet->entry),
112 &sheet->bound, &sheet->pos);
116gnucash_sheet_set_selection (GnucashSheet *sheet,
int pos,
int bound)
118 DEBUG(
"Set sheet selection %d:%d", bound, pos);
120 sheet->bound = bound;
121 gnucash_sheet_set_entry_selection (sheet);
126gnucash_sheet_set_position_and_selection (GnucashSheet* sheet,
int pos,
129 if (pos == end || start == -1)
130 gnucash_sheet_set_selection (sheet, pos, start);
131 else if (pos == start || end == -1)
132 gnucash_sheet_set_selection (sheet, start, end);
133 else if (start == end)
134 gnucash_sheet_set_selection (sheet, pos, pos);
136 gnucash_sheet_set_selection (sheet, pos, end);
140gnucash_sheet_set_position (GnucashSheet* sheet,
int pos)
142 gnucash_sheet_set_position_and_selection (sheet, pos, pos, pos);
146gnucash_sheet_set_entry_value (GnucashSheet *sheet,
const char* value)
148 g_signal_handler_block (G_OBJECT(sheet->entry),
149 sheet->insert_signal);
150 g_signal_handler_block (G_OBJECT(sheet->entry),
151 sheet->delete_signal);
153 gtk_entry_set_text (GTK_ENTRY(sheet->entry), value);
155 g_signal_handler_unblock (G_OBJECT(sheet->entry),
156 sheet->delete_signal);
157 g_signal_handler_unblock (G_OBJECT(sheet->entry),
158 sheet->insert_signal);
162static inline gboolean
163gnucash_sheet_virt_cell_out_of_bounds (GnucashSheet *sheet,
164 VirtualCellLocation vcell_loc)
166 return (vcell_loc.virt_row < 1 ||
167 vcell_loc.virt_row >= sheet->num_virt_rows ||
168 vcell_loc.virt_col < 0 ||
169 vcell_loc.virt_col >= sheet->num_virt_cols);
173gnucash_sheet_cell_valid (GnucashSheet *sheet, VirtualLocation virt_loc)
176 SheetBlockStyle *style;
178 valid = !gnucash_sheet_virt_cell_out_of_bounds (sheet,
183 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
185 valid = (virt_loc.phys_row_offset >= 0 &&
186 virt_loc.phys_row_offset < style->nrows &&
187 virt_loc.phys_col_offset >= 0 &&
188 virt_loc.phys_col_offset < style->ncols);
196gnucash_sheet_cursor_set (GnucashSheet *sheet, VirtualLocation virt_loc)
198 g_return_if_fail (sheet != NULL);
199 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
201 g_return_if_fail (virt_loc.vcell_loc.virt_row >= 0 ||
202 virt_loc.vcell_loc.virt_row <= sheet->num_virt_rows);
203 g_return_if_fail (virt_loc.vcell_loc.virt_col >= 0 ||
204 virt_loc.vcell_loc.virt_col <= sheet->num_virt_cols);
206 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
207 sheet->cursor->x, sheet->cursor->y,
208 sheet->cursor->w, sheet->cursor->h);
210 gnucash_cursor_set (GNUCASH_CURSOR(sheet->cursor), virt_loc);
212 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
213 sheet->cursor->x, sheet->cursor->y,
214 sheet->cursor->w, sheet->cursor->h);
218gnucash_sheet_cursor_set_from_table (GnucashSheet *sheet, gboolean do_scroll)
221 VirtualLocation v_loc;
223 g_return_if_fail (sheet != NULL);
224 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
226 table = sheet->table;
227 v_loc =
table->current_cursor_loc;
229 g_return_if_fail (gnucash_sheet_cell_valid (sheet, v_loc));
231 gnucash_sheet_cursor_set (sheet, v_loc);
234 gnucash_sheet_make_cell_visible (sheet, v_loc);
239gnucash_sheet_set_popup (GnucashSheet *sheet, GtkWidget *popup, gpointer data)
242 g_object_ref (popup);
245 g_object_unref (sheet->popup);
247 sheet->popup = popup;
248 sheet->popup_data = data;
253gnucash_sheet_hide_editing_cursor (GnucashSheet *sheet)
255 if (sheet->item_editor == NULL)
258 gtk_widget_hide (sheet->item_editor);
259 gnc_item_edit_hide_popup (GNC_ITEM_EDIT(sheet->item_editor));
263gnucash_sheet_stop_editing (GnucashSheet *sheet)
268 if (sheet->insert_signal != 0)
269 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
270 sheet->insert_signal);
271 if (sheet->delete_signal != 0)
272 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
273 sheet->delete_signal);
274 sheet->insert_signal = 0;
275 sheet->delete_signal = 0;
277 gnucash_sheet_hide_editing_cursor (sheet);
279 sheet->editing = FALSE;
280 sheet->input_cancelled = FALSE;
285gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet)
287 VirtualLocation virt_loc;
289 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
291 gnucash_sheet_stop_editing (sheet);
293 if (!gnc_table_model_read_only (sheet->table->model))
294 gnc_table_leave_update (sheet->table, virt_loc);
296 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
300gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
301 gint x, gint y, gint width, gint height)
303 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
305 rect->x = x + gnc_item_edit_get_margin (item_edit, left);
306 rect->y = y + gnc_item_edit_get_margin (item_edit, top);
307 rect->width = MAX (0, width - gnc_item_edit_get_margin (item_edit, left_right));
308 rect->height = height - gnc_item_edit_get_margin (item_edit, top_bottom);
312gnucash_sheet_get_text_offset (GnucashSheet *sheet,
const VirtualLocation virt_loc,
313 gint rect_width, gint logical_width)
315 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
316 Table *
table = sheet->table;
320 switch (gnc_table_get_align (
table, virt_loc))
323 case CELL_ALIGN_LEFT:
324 x_offset = gnc_item_edit_get_padding_border (item_edit, left);
327 case CELL_ALIGN_RIGHT:
328 x_offset = rect_width - gnc_item_edit_get_padding_border (item_edit, right) - logical_width - 1;
331 case CELL_ALIGN_CENTER:
332 if (logical_width > rect_width)
335 x_offset = (rect_width - logical_width) / 2;
342gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
343 gboolean changed_cells)
345 Table *
table = sheet->table;
346 VirtualLocation virt_loc;
347 SheetBlockStyle *style;
348 int cursor_pos, start_sel, end_sel;
349 gboolean allow_edits;
353 gnucash_sheet_deactivate_cursor_cell (sheet);
355 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
358 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
360 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
362 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
365 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
373 if (gnc_table_model_read_only (
table->model))
376 allow_edits = gnc_table_enter_update (
table, virt_loc,
378 &start_sel, &end_sel);
381 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
384 gtk_entry_reset_im_context (GTK_ENTRY (sheet->entry));
385 gnucash_sheet_start_editing_at_cursor (sheet);
389 if (sheet->button != 1)
391 gnucash_sheet_set_position_and_selection (sheet, cursor_pos,
396 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
397 Table *
table = sheet->table;
398 const char *text = gnc_table_get_entry (
table, virt_loc);
400 PangoRectangle logical_rect;
402 gint x, y, width, height;
403 gint index = 0, trailing = 0;
409 gnc_item_edit_get_pixel_coords (item_edit, &x, &y,
411 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
414 pango_layout_set_width (layout, -1);
415 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
416 gnucash_sheet_set_text_bounds (sheet, &rect, x, y,
418 x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
421 pango_layout_xy_to_index (layout,
422 PANGO_SCALE * (sheet->button_x - rect.x - x_offset),
423 PANGO_SCALE * (height/2), &index, &trailing);
424 g_object_unref (layout);
426 gnucash_sheet_set_position (sheet, index + trailing);
431 if (sheet->sheet_has_focus)
432 gtk_widget_grab_focus (GTK_WIDGET(sheet));
437gnucash_sheet_cursor_move (GnucashSheet *sheet, VirtualLocation virt_loc)
439 VirtualLocation old_virt_loc;
440 gboolean changed_cells;
443 table = sheet->table;
446 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &old_virt_loc);
449 gnucash_sheet_deactivate_cursor_cell (sheet);
453 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
457 gnucash_sheet_deactivate_cursor_cell (sheet);
462 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
464 gnucash_sheet_cursor_set (sheet, virt_loc);
468 gnucash_sheet_make_cell_visible (sheet, virt_loc);
470 changed_cells = !virt_loc_equal (virt_loc, old_virt_loc);
475 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
476 gtk_widget_queue_draw (GTK_WIDGET(sheet));
480 gnucash_sheet_activate_cursor_cell (sheet, changed_cells);
483 (sheet->moved_cb)(sheet, sheet->moved_cb_data);
484 return changed_cells;
489gnucash_sheet_y_pixel_to_block (GnucashSheet *sheet,
int y)
491 VirtualCellLocation vcell_loc = { 1, 0 };
494 vcell_loc.virt_row < sheet->num_virt_rows;
495 vcell_loc.virt_row++)
499 block = gnucash_sheet_get_block (sheet, vcell_loc);
506 return vcell_loc.virt_row;
511gnucash_sheet_compute_visible_range (GnucashSheet *sheet)
513 VirtualCellLocation vcell_loc;
520 g_return_if_fail (sheet != NULL);
521 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
523 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
524 height = alloc.height;
526 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
527 cy = gtk_adjustment_get_value (adj);
529 top_block = gnucash_sheet_y_pixel_to_block (sheet, cy);
531 sheet->num_visible_blocks = 0;
532 sheet->num_visible_phys_rows = 0;
534 for (vcell_loc.virt_row = top_block, vcell_loc.virt_col = 0;
535 vcell_loc.virt_row < sheet->num_virt_rows;
536 vcell_loc.virt_row++)
540 block = gnucash_sheet_get_block (sheet, vcell_loc);
544 sheet->num_visible_blocks++;
545 sheet->num_visible_phys_rows += block->
style->nrows;
555gnucash_sheet_show_row (GnucashSheet *sheet, gint virt_row)
557 VirtualCellLocation vcell_loc = { virt_row, 0 };
566 g_return_if_fail (virt_row >= 0);
567 g_return_if_fail (sheet != NULL);
568 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
570 vcell_loc.virt_row = MAX (vcell_loc.virt_row, 1);
571 vcell_loc.virt_row = MIN (vcell_loc.virt_row,
572 sheet->num_virt_rows - 1);
574 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
575 cx = gtk_adjustment_get_value (adj);
576 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
577 cy = gtk_adjustment_get_value (adj);
580 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
581 height = alloc.height;
583 block = gnucash_sheet_get_block (sheet, vcell_loc);
587 block_height = block->
style->dimensions->height;
589 if ((cy <= y) && (cy + height >= y + block_height))
591 gnucash_sheet_compute_visible_range (sheet);
596 y -= height - MIN (block_height, height);
598 if ((sheet->height - y) < height)
599 y = sheet->height - height;
605 gtk_adjustment_set_value (sheet->vadj, y);
607 gtk_adjustment_set_value (sheet->hadj, x);
609 gnucash_sheet_compute_visible_range (sheet);
610 gnucash_sheet_update_adjustments (sheet);
615gnucash_sheet_make_cell_visible (GnucashSheet *sheet, VirtualLocation virt_loc)
617 g_return_if_fail (sheet != NULL);
618 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
620 if (!gnucash_sheet_cell_valid (sheet, virt_loc))
623 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
625 gnucash_sheet_update_adjustments (sheet);
630gnucash_sheet_show_range (GnucashSheet *sheet,
631 VirtualCellLocation start_loc,
632 VirtualCellLocation end_loc)
643 g_return_if_fail (sheet != NULL);
644 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
646 start_loc.virt_row = MAX(start_loc.virt_row, 1);
647 start_loc.virt_row = MIN(start_loc.virt_row,
648 sheet->num_virt_rows - 1);
650 end_loc.virt_row = MAX(end_loc.virt_row, 1);
651 end_loc.virt_row = MIN(end_loc.virt_row,
652 sheet->num_virt_rows - 1);
654 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
655 cx = gtk_adjustment_get_value (adj);
656 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
657 cy = gtk_adjustment_get_value (adj);
660 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
661 height = alloc.height;
663 start_block = gnucash_sheet_get_block (sheet, start_loc);
664 end_block = gnucash_sheet_get_block (sheet, end_loc);
665 if (!(start_block && end_block))
669 block_height = (end_block->
origin_y +
670 end_block->
style->dimensions->height) - y;
672 if ((cy <= y) && (cy + height >= y + block_height))
674 gnucash_sheet_compute_visible_range (sheet);
679 y -= height - MIN(block_height, height);
681 if ((sheet->height - y) < height)
682 y = sheet->height - height;
688 gtk_adjustment_set_value (sheet->vadj, y);
690 gtk_adjustment_set_value (sheet->hadj, x);
692 gnucash_sheet_compute_visible_range (sheet);
693 gnucash_sheet_update_adjustments (sheet);
698gnucash_sheet_update_adjustments (GnucashSheet *sheet)
702 g_return_if_fail (sheet != NULL);
703 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
704 g_return_if_fail (sheet->vadj != NULL);
708 if (sheet->num_visible_blocks > 0)
709 gtk_adjustment_set_step_increment (vadj,
710 gtk_adjustment_get_page_size (vadj) / sheet->num_visible_blocks);
712 gtk_adjustment_set_step_increment (vadj, 0);
717gnucash_sheet_vadjustment_value_changed (GtkAdjustment *adj,
720 gnucash_sheet_compute_visible_range (sheet);
725gnucash_sheet_redraw_all (GnucashSheet *sheet)
727 g_return_if_fail (sheet != NULL);
728 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
730 gtk_widget_queue_draw (GTK_WIDGET(sheet));
732 g_signal_emit_by_name (sheet->reg,
"redraw_all");
736gnucash_sheet_redraw_help (GnucashSheet *sheet)
738 g_return_if_fail (sheet != NULL);
739 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
741 g_signal_emit_by_name (sheet->reg,
"redraw_help");
745gnucash_sheet_redraw_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
751 g_return_if_fail (sheet != NULL);
752 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
754 block = gnucash_sheet_get_block (sheet, vcell_loc);
755 if (!block || !block->
style)
761 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
762 h = block->
style->dimensions->height;
763 w = MIN(block->
style->dimensions->width, alloc.width);
765 gtk_widget_queue_draw_area (GTK_WIDGET(sheet), x, y, w + 1, h + 1);
769gnucash_sheet_is_read_only (GnucashSheet *sheet)
771 g_return_val_if_fail (sheet != NULL, TRUE);
772 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), TRUE);
773 return gnc_table_model_read_only (sheet->table->model);
777gnucash_sheet_set_has_focus (GnucashSheet *sheet, gboolean has_focus)
779 sheet->sheet_has_focus = has_focus;
783gnucash_sheet_finalize (GObject *
object)
787 sheet = GNUCASH_SHEET(
object);
791 sheet->blocks = NULL;
793 gnucash_sheet_clear_styles (sheet);
795 g_hash_table_destroy (sheet->cursor_styles);
796 g_hash_table_destroy (sheet->dimensions_hash_table);
798 g_object_unref (sheet->cursor);
800 (*G_OBJECT_CLASS(gnucash_sheet_parent_class)->finalize)(
object);
805gnucash_sheet_create (Table *
table)
811 sheet = g_object_new (GNUCASH_TYPE_SHEET, NULL);
812 sheet->table =
table;
814 sheet->vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
815 sheet->hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
817 g_signal_connect (G_OBJECT(sheet->vadj),
"value_changed",
818 G_CALLBACK(gnucash_sheet_vadjustment_value_changed), sheet);
819 g_signal_connect (G_OBJECT(sheet),
"draw",
820 G_CALLBACK(gnucash_sheet_draw_cb), sheet);
827gnucash_sheet_get_preferred_width (G_GNUC_UNUSED GtkWidget *widget,
831 *minimal_width = *natural_width = DEFAULT_SHEET_WIDTH;
837gnucash_sheet_get_preferred_height (G_GNUC_UNUSED GtkWidget *widget,
841 GnucashSheet *sheet = GNUCASH_SHEET(widget);
842 SheetBlockStyle *style;
846 *minimal_width = *natural_width = DEFAULT_SHEET_HEIGHT;
851 style = gnucash_sheet_get_style_from_cursor (sheet,
CURSOR_HEADER);
855 cd = gnucash_style_get_cell_dimensions (style, 0, 0);
859 row_height = cd->pixel_height;
861 *minimal_width = *natural_width = row_height * DEFAULT_SHEET_INITIAL_ROWS;
865gnucash_sheet_modify_current_cell (GnucashSheet *sheet,
const gchar *new_text)
867 GtkEditable *editable;
868 Table *
table = sheet->table;
869 VirtualLocation virt_loc;
870 int new_text_len = 0;
872 int cursor_position, start_sel, end_sel;
874 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
876 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
879 if (gnc_table_model_read_only (
table->model))
882 editable = GTK_EDITABLE(sheet->entry);
884 cursor_position = gtk_editable_get_position (editable);
885 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
888 new_text_len = strlen (new_text);
890 retval = gnc_table_modify_update (
table, virt_loc,
891 new_text, new_text_len,
892 new_text, new_text_len,
894 &start_sel, &end_sel,
900 DEBUG(
"%s", retval ? retval :
"nothing");
901 gnucash_sheet_set_entry_value (sheet, retval);
902 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
910 GtkEditable *editable;
917gnucash_sheet_direct_event (GnucashSheet *sheet, GdkEvent *event)
919 GtkEditable *editable;
920 Table *
table = sheet->table;
921 VirtualLocation virt_loc;
923 char *new_text = NULL;
924 int cursor_position, start_sel, end_sel;
925 int new_position, new_start, new_end;
927 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
929 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
932 if (gnc_table_model_read_only (
table->model))
935 editable = GTK_EDITABLE(sheet->entry);
937 cursor_position = gtk_editable_get_position (editable);
938 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
940 new_position = cursor_position;
941 new_start = start_sel;
943 result = gnc_table_direct_update (
table, virt_loc,
946 &new_start, &new_end,
950 DEBUG(
"%s", new_text ? new_text :
"nothing");
951 if (new_text != NULL)
952 gnucash_sheet_set_entry_value (sheet, new_text);
953 gnucash_sheet_set_position_and_selection (sheet, new_position,
960normalize_selection_bounds (
int *pos,
int *bound,
int length)
962 *bound = *bound < 0 ? length : *bound;
963 *pos = *pos < 0 ? length : *pos;
974insert_text (
const char* old_text,
const char* new_text,
int pos,
int bound)
976 int old_len = g_utf8_strlen (old_text, -1);
977 char* begin = g_utf8_substring (old_text, 0, pos);
978 char* end = g_utf8_substring (old_text, bound, old_len);
979 char *retval = g_strdup_printf (
"%s%s%s", begin, new_text, end);
986make_new_text (GnucashSheet *sheet,
const char* new_text,
int *position)
988 GtkEditable* editable = (GTK_EDITABLE(sheet->entry));
990 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
991 int old_length = g_utf8_strlen (old_text, -1);
992 int insert_length = g_utf8_strlen (new_text, -1);
994 if (!old_text || old_length == 0)
996 *position = insert_length;
997 return g_strdup (new_text);
1000 gtk_editable_get_selection_bounds (editable, &bound, &pos);
1001 normalize_selection_bounds (&pos, &bound, old_length);
1003 if (*position != pos)
1004 bound = pos = *position;
1006 if (pos == 0 && bound == old_length)
1008 *position = insert_length;
1009 return g_strdup (new_text);
1016 *position = insert_length;
1017 return g_strdup_printf (
"%s%s", new_text, old_text);
1019 else if (pos == old_length)
1021 *position = old_length + insert_length;
1022 return g_strdup_printf (
"%s%s", old_text, new_text);
1026 *position = pos + insert_length;
1027 return insert_text (old_text, new_text, pos, bound);
1031gnucash_sheet_insert_cb (GtkEditable *editable,
1032 const gchar *insert_text,
1033 const gint insert_text_len,
1035 GnucashSheet *sheet)
1038 Table *
table = sheet->table;
1039 VirtualLocation virt_loc;
1040 char *new_text = NULL;
1041 glong new_text_len = 0;
1043 int start_sel = 0, end_sel = 0;
1044 int old_position = *position;
1045 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1047 g_assert (GTK_WIDGET(editable) == sheet->entry);
1048 if (sheet->input_cancelled)
1050 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1055 if (insert_text_len <= 0)
1058 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1060 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1063 if (gnc_table_model_read_only (
table->model))
1066 new_text = make_new_text (sheet, insert_text, position);
1067 new_text_len = strlen (new_text);
1070 retval = gnc_table_modify_update (
table, virt_loc,
1071 insert_text, insert_text_len,
1072 new_text, new_text_len,
1073 position, &start_sel, &end_sel,
1074 &sheet->input_cancelled);
1082 DEBUG(
"%s, got %s", new_text, retval);
1083 gnucash_sheet_set_position_and_selection (sheet, *position, start_sel,
1086 if ((strcmp (retval, new_text) != 0) || (*position != old_position))
1088 gnucash_sheet_set_entry_value (sheet, retval);
1089 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1093 else if (retval == NULL)
1098 gtk_entry_reset_im_context (GTK_ENTRY(sheet->entry));
1100 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1108delete_text (GnucashSheet *sheet,
int pos,
int bound)
1110 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1111 int old_length = g_utf8_strlen (old_text, -1);
1113 char *retval = NULL;
1115 normalize_selection_bounds (&pos, &bound, old_length);
1117 return g_strdup (old_text);
1119 if (pos == 0 && bound == old_length)
1120 return g_strdup (
"");
1122 if (bound == old_length)
1123 return g_utf8_substring (old_text, 0, pos);
1126 return g_utf8_substring (old_text, bound, old_length);
1128 begin = g_utf8_substring (old_text, 0, pos);
1129 end = g_utf8_substring (old_text, bound, old_length);
1130 retval = g_strdup_printf (
"%s%s", begin, end);
1137gnucash_sheet_delete_cb (GtkWidget *widget,
1138 const gint start_pos,
1140 GnucashSheet *sheet)
1142 GtkEditable *editable;
1143 Table *
table = sheet->table;
1144 VirtualLocation virt_loc;
1145 char *new_text = NULL;
1148 int cursor_position = start_pos;
1149 int start_sel, end_sel;
1151 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1153 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1156 if (gnc_table_model_read_only (
table->model))
1159 new_text = delete_text (sheet, start_pos, end_pos);
1160 new_text_len = strlen (new_text);
1161 editable = GTK_EDITABLE(sheet->entry);
1162 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
1163 retval = gnc_table_modify_update (
table, virt_loc,
1165 new_text, new_text_len,
1167 &start_sel, &end_sel,
1168 &sheet->input_cancelled);
1171 gnucash_sheet_set_entry_value (sheet, retval);
1173 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
"delete_text");
1175 DEBUG(
"%s", retval ? retval :
"nothing");
1176 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
1177 start_sel, end_sel);
1181gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer data)
1183 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1184 GtkStyleContext *context = gtk_widget_get_style_context (widget);
1185 GtkAllocation alloc;
1187 gtk_widget_get_allocation (widget, &alloc);
1189 gtk_style_context_save (context);
1190 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
1191 gtk_render_background (context, cr, 0, 0, alloc.width, alloc.height);
1192 gtk_style_context_restore (context);
1194 gnucash_sheet_draw_internal (sheet, cr, &alloc);
1195 gnucash_sheet_draw_cursor (sheet->cursor, cr);
1202gnucash_sheet_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
1204 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1206 ENTER(
"widget=%p, allocation=%p", widget, allocation);
1208 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1209 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1210 (widget, allocation);
1212 if (allocation->height == sheet->window_height &&
1213 allocation->width == sheet->window_width)
1215 LEAVE(
"size unchanged");
1219 if (allocation->width != sheet->window_width)
1221 gnucash_sheet_styles_set_dimensions (sheet, allocation->width);
1222 gnucash_sheet_recompute_block_offsets (sheet);
1225 sheet->window_height = allocation->height;
1226 sheet->window_width = allocation->width;
1228 gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
1229 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
1230 gnucash_sheet_set_scroll_region (sheet);
1232 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1233 gnucash_sheet_update_adjustments (sheet);
1237 VirtualLocation virt_loc;
1239 virt_loc = sheet->table->current_cursor_loc;
1241 if (gnucash_sheet_cell_valid (sheet, virt_loc))
1242 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
1244 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
1249gnucash_sheet_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1251 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1253 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1254 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1257 gnc_item_edit_focus_in (GNC_ITEM_EDIT(sheet->item_editor));
1263gnucash_sheet_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1265 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1267 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1268 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1271 gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
1276gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
1279 VirtualLocation virt_loc;
1281 g_return_if_fail (sheet != NULL);
1282 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1284 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1286 text = gnc_table_get_entry (sheet->table, virt_loc);
1288 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1289 gtk_widget_show (GTK_WIDGET(sheet->item_editor));
1291 gtk_entry_set_text (GTK_ENTRY(sheet->entry), text);
1293 sheet->editing = TRUE;
1296 sheet->insert_signal =
1297 g_signal_connect (G_OBJECT(sheet->entry),
"insert_text",
1298 G_CALLBACK(gnucash_sheet_insert_cb), sheet);
1299 sheet->delete_signal =
1300 g_signal_connect (G_OBJECT(sheet->entry),
"delete_text",
1301 G_CALLBACK(gnucash_sheet_delete_cb), sheet);
1305gnucash_sheet_button_release_event (GtkWidget *widget, GdkEventButton *event)
1307 GnucashSheet *sheet;
1309 g_return_val_if_fail (widget != NULL, TRUE);
1310 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1311 g_return_val_if_fail (event != NULL, TRUE);
1313 sheet = GNUCASH_SHEET(widget);
1315 if (sheet->button != event->button)
1320 if (event->button != 1)
1323 gtk_grab_remove (widget);
1324 sheet->grabbed = FALSE;
1330clamp_scrollable_value (
float value, GtkAdjustment* adj)
1332 float lower = gtk_adjustment_get_lower (adj);
1333 float upper = gtk_adjustment_get_upper (adj);
1334 float size = gtk_adjustment_get_page_size (adj);
1335 return CLAMP(value, lower, upper - size);
1339gnucash_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1341 GnucashSheet *sheet;
1342 GtkAdjustment *vadj;
1343 gfloat h_value, v_value;
1345 g_return_val_if_fail (widget != NULL, TRUE);
1346 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1347 g_return_val_if_fail (event != NULL, TRUE);
1349 sheet = GNUCASH_SHEET(widget);
1351 v_value = gtk_adjustment_get_value (vadj);
1353 switch (event->direction)
1356 v_value -= gtk_adjustment_get_step_increment (vadj);
1358 case GDK_SCROLL_DOWN:
1359 v_value += gtk_adjustment_get_step_increment (vadj);
1366 case GDK_SCROLL_SMOOTH:
1367 h_value = gtk_adjustment_get_value (sheet->hadj);
1368 h_value +=
event->delta_x;
1369 h_value = clamp_scrollable_value (h_value, sheet->hadj);
1370 gtk_adjustment_set_value (sheet->hadj, h_value);
1371#if defined MAC_INTEGRATION
1372 v_value +=
event->delta_y;
1374 int direction =
event->delta_y > 0 ? 1 :
event->delta_y < 0 ? -1 : 0;
1375 v_value += gtk_adjustment_get_step_increment (vadj) * direction;
1381 v_value = clamp_scrollable_value (v_value, vadj);
1382 gtk_adjustment_set_value (vadj, v_value);
1384 if (event->delta_y == 0)
1389 gtk_widget_hide (GTK_WIDGET(sheet->vscrollbar));
1390 gtk_widget_show (GTK_WIDGET(sheet->vscrollbar));
1396gnucash_sheet_check_grab (GnucashSheet *sheet)
1398 GdkModifierType mods;
1403 if (!sheet->grabbed)
1406 window = gtk_widget_get_window (GTK_WIDGET(sheet));
1408 seat = gdk_display_get_default_seat (gdk_window_get_display (window));
1409 device = gdk_seat_get_pointer (seat);
1411 gdk_device_get_state (device, window, 0, &mods);
1413 if (!(mods & GDK_BUTTON1_MASK))
1415 gtk_grab_remove (GTK_WIDGET(sheet));
1416 sheet->grabbed = FALSE;
1421gnucash_sheet_button_press_event (GtkWidget *widget, GdkEventButton *event)
1423 GnucashSheet *sheet;
1425 VirtualLocation cur_virt_loc;
1426 VirtualLocation new_virt_loc;
1428 gboolean abort_move;
1432 g_return_val_if_fail (widget != NULL, TRUE);
1433 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1434 g_return_val_if_fail (event != NULL, TRUE);
1436 sheet = GNUCASH_SHEET(widget);
1437 table = sheet->table;
1439 if (sheet->button && (sheet->button != event->button))
1442 sheet->button =
event->button;
1443 if (sheet->button == 3)
1446 if (!gtk_widget_has_focus (widget))
1447 gtk_widget_grab_focus (widget);
1452 switch (event->button)
1458 if (event->type != GDK_BUTTON_PRESS)
1460 gnc_item_edit_paste_clipboard (GNC_ITEM_EDIT(sheet->item_editor));
1463 do_popup = (sheet->popup != NULL);
1469 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1471 sheet->button_x = -1;
1472 sheet->button_y = -1;
1474 if (!gnucash_sheet_find_loc_by_pixel (sheet, event->x, event->y,
1478 sheet->button_x =
event->x;
1479 sheet->button_y =
event->y;
1485 if (event->type != GDK_BUTTON_PRESS)
1490 gtk_grab_add (widget);
1491 sheet->grabbed = TRUE;
1494 if (virt_loc_equal (new_virt_loc, cur_virt_loc) &&
1495 sheet->editing && do_popup)
1497 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1502 abort_move = gnc_table_traverse_update (
table,
1504 GNC_TABLE_TRAVERSE_POINTER,
1508 gnucash_sheet_check_grab (sheet);
1513 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1516 if (g_strcmp0 (gnc_table_get_cell_name (
table, new_virt_loc), DOCLINK_CELL) == 0)
1518 if (sheet->open_doclink_cb)
1519 (sheet->open_doclink_cb)(sheet->open_doclink_cb_data, NULL);
1523 gnucash_sheet_check_grab (sheet);
1526 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1528 return button_1 || do_popup;
1532gnucash_sheet_refresh_from_prefs (GnucashSheet *sheet)
1534 GtkStyleContext *stylectxt;
1536 GList *classes = NULL;
1538 g_return_if_fail (sheet != NULL);
1539 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1542 GNC_PREF_USE_GNUCASH_COLOR_THEME);
1544 GNC_PREF_DRAW_HOR_LINES);
1546 GNC_PREF_DRAW_VERT_LINES);
1548 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1550 stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
1553 classes = gtk_style_context_list_classes (stylectxt);
1555 for (GList *l = classes; l; l = l->next)
1557 if (g_str_has_prefix (l->data,
"gnc-class-"))
1558 gtk_style_context_remove_class (stylectxt, l->data);
1560 g_list_free (classes);
1562 gtk_style_context_remove_class (stylectxt, GTK_STYLE_CLASS_VIEW);
1570gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
1573 gboolean handled = FALSE;
1575 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1577 switch (event->keyval)
1581 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1583 gnc_item_edit_copy_clipboard (item_edit);
1589 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1591 gnc_item_edit_cut_clipboard (item_edit);
1597 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1599 gnc_item_edit_paste_clipboard (item_edit);
1603 case GDK_KEY_Insert:
1604 if (event->state & GDK_SHIFT_MASK)
1606 gnc_item_edit_paste_clipboard (item_edit);
1609 else if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1611 gnc_item_edit_copy_clipboard (item_edit);
1620gnucash_sheet_need_horizontal_scroll (GnucashSheet *sheet,
1621 VirtualLocation *new_virt_loc)
1624 gint cell_width = 0;
1627 if (sheet->window_width == sheet->width)
1631 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
1634 offset = gnc_header_get_cell_offset (GNC_HEADER(sheet->header_item),
1635 new_virt_loc->phys_col_offset, &cell_width);
1637 if (((offset + cell_width) > sheet->window_width) || (offset < hscroll_val))
1638 gtk_adjustment_set_value (sheet->hadj, offset);
1642process_motion_keys (GnucashSheet *sheet, GdkEventKey *event, gboolean *pass_on,
1643 gncTableTraversalDir *direction,
1644 VirtualLocation* new_virt_loc)
1647 VirtualLocation cur_virt_loc = *new_virt_loc;
1649 switch (event->keyval)
1651 case GDK_KEY_Return:
1652 case GDK_KEY_KP_Enter:
1653 g_signal_emit_by_name (sheet->reg,
"activate_cursor");
1655 sheet->pos = sheet->bound;
1659 case GDK_KEY_ISO_Left_Tab:
1660 if (event->state & GDK_SHIFT_MASK)
1662 *direction = GNC_TABLE_TRAVERSE_LEFT;
1663 gnc_table_move_tab (sheet->table, new_virt_loc, FALSE);
1667 *direction = GNC_TABLE_TRAVERSE_RIGHT;
1668 gnc_table_move_tab (sheet->table, new_virt_loc, TRUE);
1671 case GDK_KEY_KP_Page_Up:
1672 case GDK_KEY_Page_Up:
1673 *direction = GNC_TABLE_TRAVERSE_UP;
1674 new_virt_loc->phys_col_offset = 0;
1675 if (event->state & GDK_SHIFT_MASK)
1676 new_virt_loc->vcell_loc.virt_row = 1;
1679 distance = sheet->num_visible_phys_rows - 1;
1681 (sheet->table, new_virt_loc, -distance);
1684 case GDK_KEY_KP_Page_Down:
1685 case GDK_KEY_Page_Down:
1686 *direction = GNC_TABLE_TRAVERSE_DOWN;
1687 new_virt_loc->phys_col_offset = 0;
1688 if (event->state & GDK_SHIFT_MASK)
1689 new_virt_loc->vcell_loc.virt_row =
1690 sheet->num_virt_rows - 1;
1693 distance = sheet->num_visible_phys_rows - 1;
1695 (sheet->table, new_virt_loc, distance);
1700 *direction = GNC_TABLE_TRAVERSE_UP;
1704 case GDK_KEY_KP_Down:
1707 if (event->keyval == GDK_KEY_Menu ||
1708 (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR))
1710 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1712 if (gnc_table_confirm_change (sheet->table, cur_virt_loc))
1713 gnc_item_edit_show_popup (item_edit);
1716 sheet->pos = sheet->bound;
1720 *direction = GNC_TABLE_TRAVERSE_DOWN;
1724 case GDK_KEY_KP_Right:
1726 case GDK_KEY_KP_Left:
1731 sheet->pos = sheet->bound;
1735 if (gnucash_sheet_clipboard_event (sheet, event))
1738 sheet->pos = sheet->bound;
1745 gnucash_sheet_need_horizontal_scroll (sheet, new_virt_loc);
1751pass_to_entry_handler (GnucashSheet *sheet, GdkEventKey *event)
1753 gboolean result = FALSE;
1754 GtkEditable *editable = GTK_EDITABLE(sheet->entry);
1757 if (gtk_widget_get_realized (GTK_WIDGET(editable)))
1759 result = gtk_widget_event (GTK_WIDGET(editable), (GdkEvent*)event);
1760 gnucash_sheet_set_selection_from_entry (sheet);
1766gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
1769 GnucashSheet *sheet;
1770 gboolean pass_on = FALSE;
1771 gboolean abort_move;
1772 VirtualLocation cur_virt_loc;
1773 VirtualLocation new_virt_loc;
1774 gncTableTraversalDir direction = 0;
1775 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
1777 g_return_val_if_fail (widget != NULL, TRUE);
1778 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1779 g_return_val_if_fail (event != NULL, TRUE);
1781 sheet = GNUCASH_SHEET(widget);
1782 table = sheet->table;
1784 if (event->is_modifier)
1789 gnucash_sheet_set_selection_from_entry (sheet);
1791 if (gnucash_sheet_direct_event (sheet, (GdkEvent *) event))
1794 if (gtk_entry_im_context_filter_keypress (GTK_ENTRY(sheet->entry), event))
1796#if !(defined(__APPLE__) || defined(__WIN32__))
1806 gnucash_sheet_set_entry_selection (sheet);
1810 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1811 new_virt_loc = cur_virt_loc;
1816 if (event->state & modifiers & (GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK))
1818 else if (process_motion_keys (sheet, event, &pass_on,
1819 &direction, &new_virt_loc))
1825 return pass_to_entry_handler (sheet, event);
1828 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1829 direction, &new_virt_loc);
1835 if (!gtk_widget_has_focus (GTK_WIDGET(sheet)))
1836 gtk_widget_grab_focus (GTK_WIDGET(sheet));
1841 sheet->pos = sheet->bound;
1842 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1849gnucash_sheet_key_release_event (GtkWidget *widget, GdkEventKey *event)
1851 g_return_val_if_fail (widget != NULL, TRUE);
1852 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1853 g_return_val_if_fail (event != NULL, TRUE);
1860gnucash_sheet_goto_virt_loc (GnucashSheet *sheet, VirtualLocation virt_loc)
1863 gboolean abort_move;
1864 VirtualLocation cur_virt_loc;
1866 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1868 table = sheet->table;
1870 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1874 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1875 GNC_TABLE_TRAVERSE_POINTER,
1882 gnucash_sheet_need_horizontal_scroll (sheet, &virt_loc);
1884 gnucash_sheet_cursor_move (sheet, virt_loc);
1888gnucash_sheet_get_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
1890 g_return_val_if_fail (sheet != NULL, NULL);
1891 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1895 vcell_loc.virt_col);
1898GncItemEdit *gnucash_sheet_get_item_edit (GnucashSheet *sheet)
1900 g_return_val_if_fail (sheet != NULL, NULL);
1901 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1903 if (sheet->item_editor == NULL)
1906 return GNC_ITEM_EDIT(sheet->item_editor);
1910void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window)
1912 g_return_if_fail (sheet != NULL);
1913 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1916 g_return_if_fail (GTK_IS_WIDGET(window));
1918 sheet->window = window;
1925gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
1926 VirtualCellLocation vcell_loc)
1930 SheetBlockStyle *style;
1933 block = gnucash_sheet_get_block (sheet, vcell_loc);
1934 style = gnucash_sheet_get_style_from_table (sheet, vcell_loc);
1939 table = sheet->table;
1945 gnucash_sheet_style_unref (sheet, block->
style);
1946 block->
style = NULL;
1951 if (block->
style == NULL)
1953 block->
style = style;
1954 gnucash_sheet_style_ref (sheet, block->
style);
1962gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
1969 SheetBlockStyle *style;
1970 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
"");
1971 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1972 const gchar *type_name;
1974 g_return_val_if_fail (virt_col >= 0, 0);
1975 g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
1976 g_return_val_if_fail (cell_col >= 0, 0);
1978 for (virt_row = 0; virt_row < sheet->num_virt_rows ; virt_row++)
1980 VirtualCellLocation vcell_loc = { virt_row, virt_col };
1982 block = gnucash_sheet_get_block (sheet, vcell_loc);
1986 style = block->
style;
1991 if (cell_col < style->ncols)
1993 for (cell_row = 0; cell_row < style->nrows; cell_row++)
1995 VirtualLocation virt_loc;
1999 virt_loc.vcell_loc = sheet->table->current_cursor_loc.vcell_loc;
2001 virt_loc.vcell_loc = vcell_loc;
2003 virt_loc.phys_row_offset = cell_row;
2004 virt_loc.phys_col_offset = cell_col;
2008 text = gnc_table_get_label
2009 (sheet->table, virt_loc);
2013 text = gnc_table_get_entry
2014 (sheet->table, virt_loc);
2017 pango_layout_set_text (layout, text, strlen (text));
2018 pango_layout_get_pixel_size (layout, &width, NULL);
2020 width += (gnc_item_edit_get_margin (item_edit, left_right) +
2021 gnc_item_edit_get_padding_border (item_edit, left_right));
2025 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
2026 if ((g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
2027 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0))
2029 width += gnc_item_edit_get_button_width (item_edit) + 2;
2031 max = MAX(max, width);
2036 g_object_unref (layout);
2042gnucash_sheet_set_scroll_region (GnucashSheet *sheet)
2045 GtkAllocation alloc;
2051 if (!sheet->header_item || !GNC_HEADER(sheet->header_item)->style)
2054 gtk_layout_get_size (GTK_LAYOUT(sheet), &old_w, &old_h);
2056 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
2057 new_h = MAX(sheet->height, alloc.height);
2058 new_w = MAX(sheet->width, alloc.width);
2060 if (new_w != old_w || new_h != old_h)
2061 gtk_layout_set_size (GTK_LAYOUT(sheet), new_w, new_h);
2065gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
2068 GnucashSheet *sheet = GNUCASH_SHEET(user_data);
2075 gnucash_sheet_style_unref (sheet, block->
style);
2081gnucash_sheet_block_construct (gpointer _block, gpointer user_data)
2085 block->
style = NULL;
2090gnucash_sheet_resize (GnucashSheet *sheet)
2092 g_return_if_fail (sheet != NULL);
2093 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2095 if (sheet->table->num_virt_cols > 1)
2096 g_warning (
"num_virt_cols > 1");
2098 sheet->num_virt_cols = 1;
2102 sheet->num_virt_rows = sheet->table->num_virt_rows;
2106gnucash_sheet_recompute_block_offsets (GnucashSheet *sheet)
2114 g_return_if_fail (sheet != NULL);
2115 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2116 g_return_if_fail (sheet->table != NULL);
2118 table = sheet->table;
2122 for (i = 0; i <
table->num_virt_rows; i++)
2126 for (j = 0; j <
table->num_virt_cols; j++)
2128 VirtualCellLocation vcell_loc = { i, j };
2130 block = gnucash_sheet_get_block (sheet, vcell_loc);
2135 block->origin_x = width;
2139 width += block->
style->dimensions->width;
2142 if (i > 0 && block && block->
visible)
2143 height += block->
style->dimensions->height;
2145 sheet->height = height;
2149gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
2152 gint num_header_phys_rows;
2155 g_return_if_fail (sheet != NULL);
2156 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2157 g_return_if_fail (sheet->table != NULL);
2159 table = sheet->table;
2161 gnucash_sheet_stop_editing (sheet);
2163 gnucash_sheet_resize (sheet);
2165 num_header_phys_rows = 0;
2168 for (i = 0; i <
table->num_virt_rows; i++)
2169 for (j = 0; j <
table->num_virt_cols; j++)
2171 VirtualCellLocation vcell_loc = { i, j };
2174 gnucash_sheet_block_set_from_table (sheet, vcell_loc);
2178 num_header_phys_rows =
2179 MAX (num_header_phys_rows,
2180 vcell->cellblock->num_rows);
2183 gnc_header_set_header_rows (GNC_HEADER(sheet->header_item),
2184 num_header_phys_rows);
2185 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
2187 gnucash_sheet_recompute_block_offsets (sheet);
2189 gnucash_sheet_set_scroll_region (sheet);
2193 VirtualLocation virt_loc;
2195 virt_loc =
table->current_cursor_loc;
2197 if (gnucash_sheet_cell_valid (sheet, virt_loc))
2198 gnucash_sheet_show_row (sheet,
2199 virt_loc.vcell_loc.virt_row);
2202 gnucash_sheet_cursor_set_from_table (sheet, do_scroll);
2203 gnucash_sheet_activate_cursor_cell (sheet, TRUE);
2213 gchar *full_class, *style_class = NULL;
2215 if (field_type >= COLOR_NEGATIVE)
2218 gtk_style_context_add_class (stylectxt,
"gnc-class-negative-numbers");
2219 field_type -= COLOR_NEGATIVE;
2223 if (sheet->use_gnc_color_theme)
2224 gtk_style_context_add_class (stylectxt,
"gnc-class-register-foreground");
2230 case COLOR_UNDEFINED:
2231 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
2235 style_class =
"header";
2239 style_class =
"primary";
2242 case COLOR_PRIMARY_ACTIVE:
2243 case COLOR_SECONDARY_ACTIVE:
2244 case COLOR_SPLIT_ACTIVE:
2245 gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
2246 style_class =
"cursor";
2249 case COLOR_SECONDARY:
2250 style_class =
"secondary";
2254 style_class =
"split";
2258 if (sheet->use_gnc_color_theme)
2259 full_class = g_strconcat (
"gnc-class-register-", style_class, NULL);
2262 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_VIEW);
2263 full_class = g_strconcat (
"gnc-class-user-register-", style_class, NULL);
2266 gtk_style_context_add_class (stylectxt, full_class);
2268 g_free (full_class);
2274gnucash_sheet_class_init (GnucashSheetClass *klass)
2276 GObjectClass *gobject_class;
2277 GtkWidgetClass *widget_class;
2279 gobject_class = G_OBJECT_CLASS(klass);
2280 widget_class = GTK_WIDGET_CLASS(klass);
2282 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(klass),
"gnc-id-sheet");
2285 gobject_class->finalize = gnucash_sheet_finalize;
2287 widget_class->get_preferred_width = gnucash_sheet_get_preferred_width;
2288 widget_class->get_preferred_height = gnucash_sheet_get_preferred_height;
2289 widget_class->size_allocate = gnucash_sheet_size_allocate;
2291 widget_class->focus_in_event = gnucash_sheet_focus_in_event;
2292 widget_class->focus_out_event = gnucash_sheet_focus_out_event;
2294 widget_class->key_press_event = gnucash_sheet_key_press_event;
2295 widget_class->key_release_event = gnucash_sheet_key_release_event;
2296 widget_class->button_press_event = gnucash_sheet_button_press_event;
2297 widget_class->button_release_event = gnucash_sheet_button_release_event;
2298 widget_class->scroll_event = gnucash_scroll_event;
2303gnucash_sheet_init (GnucashSheet *sheet)
2305 gtk_widget_set_can_focus (GTK_WIDGET(sheet), TRUE);
2306 gtk_widget_set_can_default (GTK_WIDGET(sheet), TRUE);
2308 sheet->num_visible_blocks = 1;
2309 sheet->num_visible_phys_rows = 1;
2311 sheet->input_cancelled = FALSE;
2313 sheet->popup = NULL;
2314 sheet->num_virt_rows = 0;
2315 sheet->num_virt_cols = 0;
2316 sheet->item_editor = NULL;
2317 sheet->entry = NULL;
2318 sheet->editing = FALSE;
2320 sheet->grabbed = FALSE;
2321 sheet->window_width = -1;
2322 sheet->window_height = -1;
2326 sheet->cursor_styles = g_hash_table_new (g_str_hash, g_str_equal);
2329 gnucash_sheet_block_construct,
2330 gnucash_sheet_block_destroy, sheet);
2332 gtk_widget_add_events (GTK_WIDGET(sheet),
2334 | GDK_BUTTON_PRESS_MASK
2335 | GDK_BUTTON_RELEASE_MASK
2336 | GDK_POINTER_MOTION_MASK
2337 | GDK_POINTER_MOTION_HINT_MASK));
2339 sheet->bound = sheet->pos = 0;
2343gnucash_sheet_tooltip (GtkWidget *widget, gint x, gint y,
2344 gboolean keyboard_mode,
2345 GtkTooltip *tooltip,
2348 GnucashSheet *sheet = GNUCASH_SHEET(widget);
2349 Table *
table = sheet->table;
2350 VirtualLocation virt_loc;
2351 gchar *tooltip_text;
2352 gint cx, cy, cw, ch;
2356 gint hscroll_val, vscroll_val;
2362 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
2363 vscroll_val = (gint) gtk_adjustment_get_value (sheet->vadj);
2365 if (!gnucash_sheet_find_loc_by_pixel (sheet, x + hscroll_val, y + vscroll_val, &virt_loc))
2368 tooltip_text = gnc_table_get_tooltip (
table, virt_loc);
2371 if (!tooltip_text || (g_strcmp0 (tooltip_text,
"") == 0))
2373 gtk_tooltip_set_text (tooltip, NULL);
2377 block = gnucash_sheet_get_block (sheet, virt_loc.vcell_loc);
2380 g_free (tooltip_text);
2384 bx = block->origin_x;
2388 gnucash_sheet_style_get_cell_pixel_rel_coords (block->
style,
2389 virt_loc.phys_row_offset, virt_loc.phys_col_offset,
2390 &cx, &cy, &cw, &ch);
2392 rect.x = cx + bx - hscroll_val;
2393 rect.y = cy + by - vscroll_val;
2397 gtk_tooltip_set_tip_area (tooltip, &rect);
2398 gtk_tooltip_set_text (tooltip, tooltip_text);
2399 g_free (tooltip_text);
2409 g_free (dimensions);
2414gnucash_sheet_new (Table *
table)
2416 GnucashSheet *sheet;
2418 g_return_val_if_fail (
table != NULL, NULL);
2420 sheet = gnucash_sheet_create (
table);
2423 sheet->sheet_has_focus = TRUE;
2426 sheet->cursor = gnucash_cursor_new (sheet);
2429 sheet->item_editor = gnc_item_edit_new (sheet);
2432 sheet->dimensions_hash_table = g_hash_table_new_full (g_int_hash,
2434 g_free, (GDestroyNotify)dimensions_destroy);
2437 gtk_widget_set_has_tooltip (GTK_WIDGET(sheet), TRUE);
2438 g_signal_connect (G_OBJECT(sheet),
"query-tooltip",
2439 G_CALLBACK(gnucash_sheet_tooltip), NULL);
2441 gnucash_sheet_refresh_from_prefs (sheet);
2443 return GTK_WIDGET(sheet);
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
Convenience wrapper around GdkRGBA for use in Register Gnome classes.
Public declarations for GnucashCursor class.
Public declarations for GncItemEdit class.
Private declarations for GnucashSheet class.
Public declarations of GnucashRegister class.
Styling functions for RegisterGnome.
void gnucash_get_style_classes(GnucashSheet *sheet, GtkStyleContext *stylectxt, RegisterColor field_type, gboolean use_neg_class)
Map a cell color type to a css style class.
#define DEBUG(format, args...)
Print a debugging message.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define ENTER(format, args...)
Print a function entry debugging message.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void g_table_destroy(GTable *gtable)
Free the table and all associated table elements.
void g_table_resize(GTable *gtable, int rows, int cols)
Resize the table, allocating and deallocating extra table members if needed.
RegisterColor
Color definitions used for table elements.
gboolean gnc_table_move_vertical_position(Table *table, VirtualLocation *virt_loc, int phys_row_offset)
Moves away from virtual location virt_loc by phys_row_offset physical rows.
gpointer g_table_index(GTable *gtable, int row, int col)
Return the element at the given row and column.
GTable * g_table_new(guint entry_size, g_table_entry_constructor constructor, g_table_entry_destroyer destroyer, gpointer user_data)
Create a new table with the given entry constructor and destroyer.
#define CURSOR_HEADER
Standard Cursor Names.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
API for checkbook register display area.
SheetBlockStyle * style
The style for this block.
gboolean visible
y origin of block
gint origin_y
x origin of block
holds information about each virtual cell.
unsigned int visible
Used by higher-level code.