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 76 static void gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet);
78 static gboolean gnucash_sheet_cursor_move (GnucashSheet *sheet,
79 VirtualLocation virt_loc);
81 static void gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet);
82 static void gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
83 gboolean changed_cells);
84 static void gnucash_sheet_stop_editing (GnucashSheet *sheet);
85 gboolean gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr,
86 G_GNUC_UNUSED gpointer data);
90 G_DEFINE_TYPE (GnucashSheet, gnucash_sheet, GTK_TYPE_LAYOUT);
101 gnucash_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);
109 gnucash_sheet_set_selection_from_entry (GnucashSheet *sheet)
111 gtk_editable_get_selection_bounds (GTK_EDITABLE(sheet->entry),
112 &sheet->bound, &sheet->pos);
116 gnucash_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);
126 gnucash_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);
140 gnucash_sheet_set_position (GnucashSheet* sheet,
int pos)
142 gnucash_sheet_set_position_and_selection (sheet, pos, pos, pos);
146 gnucash_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);
162 static inline gboolean
163 gnucash_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);
173 gnucash_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);
196 gnucash_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);
218 gnucash_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);
239 gnucash_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;
253 gnucash_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));
263 gnucash_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;
285 gnucash_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);
300 gnucash_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);
312 gnucash_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;
342 gnucash_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));
437 gnucash_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;
489 gnucash_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;
511 gnucash_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;
555 gnucash_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);
615 gnucash_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);
630 gnucash_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);
698 gnucash_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);
717 gnucash_sheet_vadjustment_value_changed (GtkAdjustment *adj,
720 gnucash_sheet_compute_visible_range (sheet);
725 gnucash_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");
736 gnucash_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");
745 gnucash_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);
769 gnucash_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);
777 gnucash_sheet_set_has_focus (GnucashSheet *sheet, gboolean has_focus)
779 sheet->sheet_has_focus = has_focus;
783 gnucash_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);
804 static GnucashSheet *
805 gnucash_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);
827 gnucash_sheet_get_preferred_width (G_GNUC_UNUSED GtkWidget *widget,
831 *minimal_width = *natural_width = DEFAULT_SHEET_WIDTH;
837 gnucash_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;
865 gnucash_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;
917 gnucash_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,
960 normalize_selection_bounds (
int *pos,
int *bound,
int length)
962 *bound = *bound < 0 ? length : *bound;
963 *pos = *pos < 0 ? length : *pos;
974 insert_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);
986 make_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);
1031 gnucash_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),
1108 delete_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);
1137 gnucash_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);
1181 gnucash_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);
1202 gnucash_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));
1249 gnucash_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));
1263 gnucash_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));
1276 gnucash_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);
1305 gnucash_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;
1330 clamp_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);
1339 gnucash_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));
1396 gnucash_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;
1421 gnucash_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;
1532 gnucash_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);
1570 gnucash_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);
1620 gnucash_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);
1642 process_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);
1751 pass_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);
1766 gnucash_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);
1849 gnucash_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);
1860 gnucash_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);
1888 gnucash_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);
1898 GncItemEdit *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);
1910 void 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;
1925 gnucash_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);
1962 gnucash_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);
2042 gnucash_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);
2065 gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
2068 GnucashSheet *sheet = GNUCASH_SHEET(user_data);
2075 gnucash_sheet_style_unref (sheet, block->
style);
2081 gnucash_sheet_block_construct (gpointer _block, gpointer user_data)
2085 block->
style = NULL;
2090 gnucash_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;
2106 gnucash_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;
2149 gnucash_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);
2274 gnucash_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;
2303 gnucash_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;
2343 gnucash_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);
2414 gnucash_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);
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 G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
gpointer g_table_index(GTable *gtable, int row, int col)
Return the element at the given row and column.
holds information about each virtual cell.
#define DEBUG(format, args...)
Print a debugging message.
Convenience wrapper around GdkRGBA for use in Register Gnome classes.
#define ENTER(format, args...)
Print a function entry debugging message.
Public declarations for GnucashCursor class.
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.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
#define CURSOR_HEADER
Standard Cursor Names.
gboolean visible
y origin of block
Public declarations of GnucashRegister class.
Private declarations for GnucashSheet class.
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.
All type declarations for the whole Gnucash engine.
API for checkbook register display area.
SheetBlockStyle * style
The style for this block.
Generic api to store and retrieve preferences.
unsigned int visible
Used by higher-level code.
void g_table_destroy(GTable *gtable)
Free the table and all associated table elements.
Public declarations for GncItemEdit class.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
#define LEAVE(format, args...)
Print a function exit debugging message.
RegisterColor
Color definitions used for table elements.
Styling functions for RegisterGnome.
void g_table_resize(GTable *gtable, int rows, int cols)
Resize the table, allocating and deallocating extra table members if needed.
gint origin_y
x origin of block