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 static gboolean gnucash_sheet_check_direct_update_cell (GnucashSheet *sheet,
86 const VirtualLocation virt_loc);
87 gboolean gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr,
88 G_GNUC_UNUSED gpointer data);
92 G_DEFINE_TYPE (GnucashSheet, gnucash_sheet, GTK_TYPE_LAYOUT);
103 gnucash_sheet_set_entry_selection (GnucashSheet *sheet)
105 DEBUG(
"Set entry selection to sheet: %d:%d", sheet->bound, sheet->pos);
106 gtk_editable_select_region (GTK_EDITABLE(sheet->entry),
107 sheet->bound, sheet->pos);
111 gnucash_sheet_set_selection_from_entry (GnucashSheet *sheet)
113 gtk_editable_get_selection_bounds (GTK_EDITABLE(sheet->entry),
114 &sheet->bound, &sheet->pos);
118 gnucash_sheet_set_selection (GnucashSheet *sheet,
int pos,
int bound)
120 DEBUG(
"Set sheet selection %d:%d", bound, pos);
122 sheet->bound = bound;
123 gnucash_sheet_set_entry_selection (sheet);
128 gnucash_sheet_set_position_and_selection (GnucashSheet* sheet,
int pos,
131 if (pos == end || start == -1)
132 gnucash_sheet_set_selection (sheet, pos, start);
133 else if (pos == start || end == -1)
134 gnucash_sheet_set_selection (sheet, start, end);
135 else if (start == end)
136 gnucash_sheet_set_selection (sheet, pos, pos);
138 gnucash_sheet_set_selection (sheet, pos, end);
142 gnucash_sheet_set_position (GnucashSheet* sheet,
int pos)
144 gnucash_sheet_set_position_and_selection (sheet, pos, pos, pos);
148 gnucash_sheet_set_entry_value (GnucashSheet *sheet,
const char* value)
150 g_signal_handler_block (G_OBJECT(sheet->entry),
151 sheet->insert_signal);
152 g_signal_handler_block (G_OBJECT(sheet->entry),
153 sheet->delete_signal);
155 gtk_entry_set_text (GTK_ENTRY(sheet->entry), value);
157 g_signal_handler_unblock (G_OBJECT(sheet->entry),
158 sheet->delete_signal);
159 g_signal_handler_unblock (G_OBJECT(sheet->entry),
160 sheet->insert_signal);
164 static inline gboolean
165 gnucash_sheet_virt_cell_out_of_bounds (GnucashSheet *sheet,
166 VirtualCellLocation vcell_loc)
168 return (vcell_loc.virt_row < 1 ||
169 vcell_loc.virt_row >= sheet->num_virt_rows ||
170 vcell_loc.virt_col < 0 ||
171 vcell_loc.virt_col >= sheet->num_virt_cols);
175 gnucash_sheet_cell_valid (GnucashSheet *sheet, VirtualLocation virt_loc)
178 SheetBlockStyle *style;
180 valid = !gnucash_sheet_virt_cell_out_of_bounds (sheet,
185 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
187 valid = (virt_loc.phys_row_offset >= 0 &&
188 virt_loc.phys_row_offset < style->nrows &&
189 virt_loc.phys_col_offset >= 0 &&
190 virt_loc.phys_col_offset < style->ncols);
198 gnucash_sheet_cursor_set (GnucashSheet *sheet, VirtualLocation virt_loc)
200 g_return_if_fail (sheet != NULL);
201 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
203 g_return_if_fail (virt_loc.vcell_loc.virt_row >= 0 ||
204 virt_loc.vcell_loc.virt_row <= sheet->num_virt_rows);
205 g_return_if_fail (virt_loc.vcell_loc.virt_col >= 0 ||
206 virt_loc.vcell_loc.virt_col <= sheet->num_virt_cols);
208 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
209 sheet->cursor->x, sheet->cursor->y,
210 sheet->cursor->w, sheet->cursor->h);
212 gnucash_cursor_set (GNUCASH_CURSOR(sheet->cursor), virt_loc);
214 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
215 sheet->cursor->x, sheet->cursor->y,
216 sheet->cursor->w, sheet->cursor->h);
220 gnucash_sheet_cursor_set_from_table (GnucashSheet *sheet, gboolean do_scroll)
223 VirtualLocation v_loc;
225 g_return_if_fail (sheet != NULL);
226 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
228 table = sheet->table;
229 v_loc =
table->current_cursor_loc;
231 g_return_if_fail (gnucash_sheet_cell_valid (sheet, v_loc));
233 gnucash_sheet_cursor_set (sheet, v_loc);
236 gnucash_sheet_make_cell_visible (sheet, v_loc);
241 gnucash_sheet_set_popup (GnucashSheet *sheet, GtkWidget *popup, gpointer data)
244 g_object_ref (popup);
247 g_object_unref (sheet->popup);
249 sheet->popup = popup;
250 sheet->popup_data = data;
255 gnucash_sheet_hide_editing_cursor (GnucashSheet *sheet)
257 if (sheet->item_editor == NULL)
260 gtk_widget_hide (sheet->item_editor);
261 gnc_item_edit_hide_popup (GNC_ITEM_EDIT(sheet->item_editor));
265 gnucash_sheet_stop_editing (GnucashSheet *sheet)
270 if (sheet->insert_signal != 0)
271 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
272 sheet->insert_signal);
273 if (sheet->delete_signal != 0)
274 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
275 sheet->delete_signal);
276 sheet->insert_signal = 0;
277 sheet->delete_signal = 0;
278 sheet->direct_update_cell = FALSE;
280 gnucash_sheet_hide_editing_cursor (sheet);
282 sheet->editing = FALSE;
283 sheet->input_cancelled = FALSE;
288 gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet)
290 VirtualLocation virt_loc;
292 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
294 gnucash_sheet_stop_editing (sheet);
296 if (!gnc_table_model_read_only (sheet->table->model))
297 gnc_table_leave_update (sheet->table, virt_loc);
299 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
303 gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
304 gint x, gint y, gint width, gint height)
306 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
308 rect->x = x + gnc_item_edit_get_margin (item_edit, left);
309 rect->y = y + gnc_item_edit_get_margin (item_edit, top);
310 rect->width = MAX (0, width - gnc_item_edit_get_margin (item_edit, left_right));
311 rect->height = height - gnc_item_edit_get_margin (item_edit, top_bottom);
315 gnucash_sheet_get_text_offset (GnucashSheet *sheet,
const VirtualLocation virt_loc,
316 gint rect_width, gint logical_width)
318 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
319 Table *
table = sheet->table;
323 switch (gnc_table_get_align (
table, virt_loc))
326 case CELL_ALIGN_LEFT:
327 x_offset = gnc_item_edit_get_padding_border (item_edit, left);
330 case CELL_ALIGN_RIGHT:
331 x_offset = rect_width - gnc_item_edit_get_padding_border (item_edit, right) - logical_width - 1;
334 case CELL_ALIGN_CENTER:
335 if (logical_width > rect_width)
338 x_offset = (rect_width - logical_width) / 2;
345 gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
346 gboolean changed_cells)
348 Table *
table = sheet->table;
349 VirtualLocation virt_loc;
350 SheetBlockStyle *style;
351 int cursor_pos, start_sel, end_sel;
352 gboolean allow_edits;
356 gnucash_sheet_deactivate_cursor_cell (sheet);
358 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
361 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
363 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
365 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
368 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
376 if (gnc_table_model_read_only (
table->model))
379 allow_edits = gnc_table_enter_update (
table, virt_loc,
381 &start_sel, &end_sel);
384 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
387 gtk_entry_reset_im_context (GTK_ENTRY (sheet->entry));
388 gnucash_sheet_start_editing_at_cursor (sheet);
392 if (sheet->button != 1)
394 gnucash_sheet_set_position_and_selection (sheet, cursor_pos,
399 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
400 Table *
table = sheet->table;
401 const char *text = gnc_table_get_entry (
table, virt_loc);
403 PangoRectangle logical_rect;
405 gint x, y, width, height;
406 gint index = 0, trailing = 0;
412 gnc_item_edit_get_pixel_coords (item_edit, &x, &y,
414 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
417 pango_layout_set_width (layout, -1);
418 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
419 gnucash_sheet_set_text_bounds (sheet, &rect, x, y,
421 x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
424 pango_layout_xy_to_index (layout,
425 PANGO_SCALE * (sheet->button_x - rect.x - x_offset),
426 PANGO_SCALE * (height/2), &index, &trailing);
427 g_object_unref (layout);
429 gnucash_sheet_set_position (sheet, index + trailing);
431 sheet->direct_update_cell = gnucash_sheet_check_direct_update_cell (sheet, virt_loc);
435 if (sheet->sheet_has_focus)
436 gtk_widget_grab_focus (GTK_WIDGET(sheet));
441 gnucash_sheet_cursor_move (GnucashSheet *sheet, VirtualLocation virt_loc)
443 VirtualLocation old_virt_loc;
444 gboolean changed_cells;
447 table = sheet->table;
450 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &old_virt_loc);
453 gnucash_sheet_deactivate_cursor_cell (sheet);
457 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
461 gnucash_sheet_deactivate_cursor_cell (sheet);
466 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
468 gnucash_sheet_cursor_set (sheet, virt_loc);
472 gnucash_sheet_make_cell_visible (sheet, virt_loc);
474 changed_cells = !virt_loc_equal (virt_loc, old_virt_loc);
479 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
480 gtk_widget_queue_draw (GTK_WIDGET(sheet));
484 gnucash_sheet_activate_cursor_cell (sheet, changed_cells);
487 (sheet->moved_cb)(sheet, sheet->moved_cb_data);
488 return changed_cells;
493 gnucash_sheet_y_pixel_to_block (GnucashSheet *sheet,
int y)
495 VirtualCellLocation vcell_loc = { 1, 0 };
498 vcell_loc.virt_row < sheet->num_virt_rows;
499 vcell_loc.virt_row++)
503 block = gnucash_sheet_get_block (sheet, vcell_loc);
510 return vcell_loc.virt_row;
515 gnucash_sheet_compute_visible_range (GnucashSheet *sheet)
517 VirtualCellLocation vcell_loc;
524 g_return_if_fail (sheet != NULL);
525 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
527 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
528 height = alloc.height;
530 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
531 cy = gtk_adjustment_get_value (adj);
533 top_block = gnucash_sheet_y_pixel_to_block (sheet, cy);
535 sheet->num_visible_blocks = 0;
536 sheet->num_visible_phys_rows = 0;
538 for (vcell_loc.virt_row = top_block, vcell_loc.virt_col = 0;
539 vcell_loc.virt_row < sheet->num_virt_rows;
540 vcell_loc.virt_row++)
544 block = gnucash_sheet_get_block (sheet, vcell_loc);
548 sheet->num_visible_blocks++;
549 sheet->num_visible_phys_rows += block->
style->nrows;
559 gnucash_sheet_show_row (GnucashSheet *sheet, gint virt_row)
561 VirtualCellLocation vcell_loc = { virt_row, 0 };
570 g_return_if_fail (virt_row >= 0);
571 g_return_if_fail (sheet != NULL);
572 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
574 vcell_loc.virt_row = MAX (vcell_loc.virt_row, 1);
575 vcell_loc.virt_row = MIN (vcell_loc.virt_row,
576 sheet->num_virt_rows - 1);
578 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
579 cx = gtk_adjustment_get_value (adj);
580 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
581 cy = gtk_adjustment_get_value (adj);
584 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
585 height = alloc.height;
587 block = gnucash_sheet_get_block (sheet, vcell_loc);
591 block_height = block->
style->dimensions->height;
593 if ((cy <= y) && (cy + height >= y + block_height))
595 gnucash_sheet_compute_visible_range (sheet);
600 y -= height - MIN (block_height, height);
602 if ((sheet->height - y) < height)
603 y = sheet->height - height;
609 gtk_adjustment_set_value (sheet->vadj, y);
611 gtk_adjustment_set_value (sheet->hadj, x);
613 gnucash_sheet_compute_visible_range (sheet);
614 gnucash_sheet_update_adjustments (sheet);
619 gnucash_sheet_make_cell_visible (GnucashSheet *sheet, VirtualLocation virt_loc)
621 g_return_if_fail (sheet != NULL);
622 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
624 if (!gnucash_sheet_cell_valid (sheet, virt_loc))
627 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
629 gnucash_sheet_update_adjustments (sheet);
634 gnucash_sheet_show_range (GnucashSheet *sheet,
635 VirtualCellLocation start_loc,
636 VirtualCellLocation end_loc)
647 g_return_if_fail (sheet != NULL);
648 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
650 start_loc.virt_row = MAX(start_loc.virt_row, 1);
651 start_loc.virt_row = MIN(start_loc.virt_row,
652 sheet->num_virt_rows - 1);
654 end_loc.virt_row = MAX(end_loc.virt_row, 1);
655 end_loc.virt_row = MIN(end_loc.virt_row,
656 sheet->num_virt_rows - 1);
658 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
659 cx = gtk_adjustment_get_value (adj);
660 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
661 cy = gtk_adjustment_get_value (adj);
664 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
665 height = alloc.height;
667 start_block = gnucash_sheet_get_block (sheet, start_loc);
668 end_block = gnucash_sheet_get_block (sheet, end_loc);
669 if (!(start_block && end_block))
673 block_height = (end_block->
origin_y +
674 end_block->
style->dimensions->height) - y;
676 if ((cy <= y) && (cy + height >= y + block_height))
678 gnucash_sheet_compute_visible_range (sheet);
683 y -= height - MIN(block_height, height);
685 if ((sheet->height - y) < height)
686 y = sheet->height - height;
692 gtk_adjustment_set_value (sheet->vadj, y);
694 gtk_adjustment_set_value (sheet->hadj, x);
696 gnucash_sheet_compute_visible_range (sheet);
697 gnucash_sheet_update_adjustments (sheet);
702 gnucash_sheet_update_adjustments (GnucashSheet *sheet)
706 g_return_if_fail (sheet != NULL);
707 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
708 g_return_if_fail (sheet->vadj != NULL);
712 if (sheet->num_visible_blocks > 0)
713 gtk_adjustment_set_step_increment (vadj,
714 gtk_adjustment_get_page_size (vadj) / sheet->num_visible_blocks);
716 gtk_adjustment_set_step_increment (vadj, 0);
721 gnucash_sheet_vadjustment_value_changed (GtkAdjustment *adj,
724 gnucash_sheet_compute_visible_range (sheet);
729 gnucash_sheet_redraw_all (GnucashSheet *sheet)
731 g_return_if_fail (sheet != NULL);
732 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
734 gtk_widget_queue_draw (GTK_WIDGET(sheet));
736 g_signal_emit_by_name (sheet->reg,
"redraw_all");
740 gnucash_sheet_redraw_help (GnucashSheet *sheet)
742 g_return_if_fail (sheet != NULL);
743 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
745 g_signal_emit_by_name (sheet->reg,
"redraw_help");
749 gnucash_sheet_redraw_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
755 g_return_if_fail (sheet != NULL);
756 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
758 block = gnucash_sheet_get_block (sheet, vcell_loc);
759 if (!block || !block->
style)
765 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
766 h = block->
style->dimensions->height;
767 w = MIN(block->
style->dimensions->width, alloc.width);
769 gtk_widget_queue_draw_area (GTK_WIDGET(sheet), x, y, w + 1, h + 1);
773 gnucash_sheet_is_read_only (GnucashSheet *sheet)
775 g_return_val_if_fail (sheet != NULL, TRUE);
776 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), TRUE);
777 return gnc_table_model_read_only (sheet->table->model);
781 gnucash_sheet_set_has_focus (GnucashSheet *sheet, gboolean has_focus)
783 sheet->sheet_has_focus = has_focus;
787 gnucash_sheet_finalize (GObject *
object)
791 sheet = GNUCASH_SHEET(
object);
795 sheet->blocks = NULL;
797 gnucash_sheet_clear_styles (sheet);
799 g_hash_table_destroy (sheet->cursor_styles);
800 g_hash_table_destroy (sheet->dimensions_hash_table);
802 g_object_unref (sheet->cursor);
804 (*G_OBJECT_CLASS(gnucash_sheet_parent_class)->finalize)(
object);
808 static GnucashSheet *
809 gnucash_sheet_create (Table *
table)
815 sheet = g_object_new (GNUCASH_TYPE_SHEET, NULL);
816 sheet->table =
table;
818 sheet->vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
819 sheet->hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
821 g_signal_connect (G_OBJECT(sheet->vadj),
"value_changed",
822 G_CALLBACK(gnucash_sheet_vadjustment_value_changed), sheet);
823 g_signal_connect (G_OBJECT(sheet),
"draw",
824 G_CALLBACK(gnucash_sheet_draw_cb), sheet);
831 gnucash_sheet_get_preferred_width (G_GNUC_UNUSED GtkWidget *widget,
835 *minimal_width = *natural_width = DEFAULT_SHEET_WIDTH;
841 gnucash_sheet_get_preferred_height (G_GNUC_UNUSED GtkWidget *widget,
845 GnucashSheet *sheet = GNUCASH_SHEET(widget);
846 SheetBlockStyle *style;
850 *minimal_width = *natural_width = DEFAULT_SHEET_HEIGHT;
855 style = gnucash_sheet_get_style_from_cursor (sheet,
CURSOR_HEADER);
859 cd = gnucash_style_get_cell_dimensions (style, 0, 0);
863 row_height = cd->pixel_height;
865 *minimal_width = *natural_width = row_height * DEFAULT_SHEET_INITIAL_ROWS;
869 gnucash_sheet_modify_current_cell (GnucashSheet *sheet,
const gchar *new_text)
871 GtkEditable *editable;
872 Table *
table = sheet->table;
873 VirtualLocation virt_loc;
874 int new_text_len = 0;
876 int cursor_position, start_sel, end_sel;
878 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
880 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
883 if (gnc_table_model_read_only (
table->model))
886 editable = GTK_EDITABLE(sheet->entry);
888 cursor_position = gtk_editable_get_position (editable);
889 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
892 new_text_len = strlen (new_text);
894 retval = gnc_table_modify_update (
table, virt_loc,
895 new_text, new_text_len,
896 new_text, new_text_len,
898 &start_sel, &end_sel,
904 DEBUG(
"%s", retval ? retval :
"nothing");
905 gnucash_sheet_set_entry_value (sheet, retval);
906 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
914 GtkEditable *editable;
921 gnucash_sheet_direct_event (GnucashSheet *sheet, GdkEvent *event)
923 GtkEditable *editable;
924 Table *
table = sheet->table;
925 VirtualLocation virt_loc;
927 char *new_text = NULL;
928 int cursor_position, start_sel, end_sel;
929 int new_position, new_start, new_end;
931 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
933 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
936 if (gnc_table_model_read_only (
table->model))
939 editable = GTK_EDITABLE(sheet->entry);
941 cursor_position = gtk_editable_get_position (editable);
942 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
944 new_position = cursor_position;
945 new_start = start_sel;
947 result = gnc_table_direct_update (
table, virt_loc,
950 &new_start, &new_end,
954 DEBUG(
"%s", new_text ? new_text :
"nothing");
955 if (new_text != NULL)
956 gnucash_sheet_set_entry_value (sheet, new_text);
957 gnucash_sheet_set_position_and_selection (sheet, new_position,
964 normalize_selection_bounds (
int *pos,
int *bound,
int length)
966 *bound = *bound < 0 ? length : *bound;
967 *pos = *pos < 0 ? length : *pos;
978 insert_text (
const char* old_text,
const char* new_text,
int pos,
int bound)
980 int old_len = g_utf8_strlen (old_text, -1);
981 char* begin = g_utf8_substring (old_text, 0, pos);
982 char* end = g_utf8_substring (old_text, bound, old_len);
983 char *retval = g_strdup_printf (
"%s%s%s", begin, new_text, end);
990 make_new_text (GnucashSheet *sheet,
const char* new_text,
int *position)
992 GtkEditable* editable = (GTK_EDITABLE(sheet->entry));
994 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
995 int old_length = g_utf8_strlen (old_text, -1);
996 int insert_length = g_utf8_strlen (new_text, -1);
998 if (!old_text || old_length == 0)
1000 *position = insert_length;
1001 return g_strdup (new_text);
1004 gtk_editable_get_selection_bounds (editable, &bound, &pos);
1005 normalize_selection_bounds (&pos, &bound, old_length);
1007 if (*position != pos)
1008 bound = pos = *position;
1010 if (pos == 0 && bound == old_length)
1012 *position = insert_length;
1013 return g_strdup (new_text);
1020 *position = insert_length;
1021 return g_strdup_printf (
"%s%s", new_text, old_text);
1023 else if (pos == old_length)
1025 *position = old_length + insert_length;
1026 return g_strdup_printf (
"%s%s", old_text, new_text);
1030 *position = pos + insert_length;
1031 return insert_text (old_text, new_text, pos, bound);
1035 gnucash_sheet_insert_cb (GtkEditable *editable,
1036 const gchar *insert_text,
1037 const gint insert_text_len,
1039 GnucashSheet *sheet)
1042 Table *
table = sheet->table;
1043 VirtualLocation virt_loc;
1044 char *new_text = NULL;
1045 glong new_text_len = 0;
1047 int start_sel = 0, end_sel = 0;
1048 int old_position = *position;
1049 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1051 g_assert (GTK_WIDGET(editable) == sheet->entry);
1052 if (sheet->input_cancelled)
1054 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1059 if (insert_text_len <= 0)
1062 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1064 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1067 if (gnc_table_model_read_only (
table->model))
1070 new_text = make_new_text (sheet, insert_text, position);
1071 new_text_len = strlen (new_text);
1074 retval = gnc_table_modify_update (
table, virt_loc,
1075 insert_text, insert_text_len,
1076 new_text, new_text_len,
1077 position, &start_sel, &end_sel,
1078 &sheet->input_cancelled);
1086 DEBUG(
"%s, got %s", new_text, retval);
1087 gnucash_sheet_set_position_and_selection (sheet, *position, start_sel,
1090 if ((strcmp (retval, new_text) != 0) || (*position != old_position))
1092 gnucash_sheet_set_entry_value (sheet, retval);
1093 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1097 else if (retval == NULL)
1102 gtk_entry_reset_im_context (GTK_ENTRY(sheet->entry));
1104 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1112 delete_text (GnucashSheet *sheet,
int pos,
int bound)
1114 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1115 int old_length = g_utf8_strlen (old_text, -1);
1117 char *retval = NULL;
1119 normalize_selection_bounds (&pos, &bound, old_length);
1121 return g_strdup (old_text);
1123 if (pos == 0 && bound == old_length)
1124 return g_strdup (
"");
1126 if (bound == old_length)
1127 return g_utf8_substring (old_text, 0, pos);
1130 return g_utf8_substring (old_text, bound, old_length);
1132 begin = g_utf8_substring (old_text, 0, pos);
1133 end = g_utf8_substring (old_text, bound, old_length);
1134 retval = g_strdup_printf (
"%s%s", begin, end);
1141 gnucash_sheet_delete_cb (GtkWidget *widget,
1142 const gint start_pos,
1144 GnucashSheet *sheet)
1146 GtkEditable *editable;
1147 Table *
table = sheet->table;
1148 VirtualLocation virt_loc;
1149 char *new_text = NULL;
1152 int cursor_position = start_pos;
1153 int start_sel, end_sel;
1155 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1157 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1160 if (gnc_table_model_read_only (
table->model))
1163 new_text = delete_text (sheet, start_pos, end_pos);
1164 new_text_len = strlen (new_text);
1165 editable = GTK_EDITABLE(sheet->entry);
1166 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
1167 retval = gnc_table_modify_update (
table, virt_loc,
1169 new_text, new_text_len,
1171 &start_sel, &end_sel,
1172 &sheet->input_cancelled);
1175 gnucash_sheet_set_entry_value (sheet, retval);
1177 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
"delete_text");
1179 DEBUG(
"%s", retval ? retval :
"nothing");
1180 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
1181 start_sel, end_sel);
1185 gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer data)
1187 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1188 GtkStyleContext *context = gtk_widget_get_style_context (widget);
1189 GtkAllocation alloc;
1191 gtk_widget_get_allocation (widget, &alloc);
1193 gtk_style_context_save (context);
1194 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
1195 gtk_render_background (context, cr, 0, 0, alloc.width, alloc.height);
1196 gtk_style_context_restore (context);
1198 gnucash_sheet_draw_internal (sheet, cr, &alloc);
1199 gnucash_sheet_draw_cursor (sheet->cursor, cr);
1206 gnucash_sheet_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
1208 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1210 ENTER(
"widget=%p, allocation=%p", widget, allocation);
1212 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1213 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1214 (widget, allocation);
1216 if (allocation->height == sheet->window_height &&
1217 allocation->width == sheet->window_width)
1219 LEAVE(
"size unchanged");
1223 if (allocation->width != sheet->window_width)
1225 gnucash_sheet_styles_set_dimensions (sheet, allocation->width);
1226 gnucash_sheet_recompute_block_offsets (sheet);
1229 sheet->window_height = allocation->height;
1230 sheet->window_width = allocation->width;
1232 gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
1233 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
1234 gnucash_sheet_set_scroll_region (sheet);
1236 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1237 gnucash_sheet_update_adjustments (sheet);
1241 VirtualLocation virt_loc;
1243 virt_loc = sheet->table->current_cursor_loc;
1245 if (gnucash_sheet_cell_valid (sheet, virt_loc))
1246 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
1248 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
1253 gnucash_sheet_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1255 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1257 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1258 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1261 gnc_item_edit_focus_in (GNC_ITEM_EDIT(sheet->item_editor));
1267 gnucash_sheet_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1269 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1271 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1272 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1275 gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
1280 gnucash_sheet_check_direct_update_cell (GnucashSheet *sheet,
1281 const VirtualLocation virt_loc)
1283 const gchar *type_name;
1285 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
1287 if ( (g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
1288 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0)
1289 || (g_strcmp0 (type_name, NUM_CELL_TYPE_NAME) == 0)
1290 || (g_strcmp0 (type_name, PRICE_CELL_TYPE_NAME) == 0)
1291 || (g_strcmp0 (type_name, FORMULA_CELL_TYPE_NAME) == 0))
return TRUE;
1297 gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
1300 VirtualLocation virt_loc;
1302 g_return_if_fail (sheet != NULL);
1303 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1305 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1307 text = gnc_table_get_entry (sheet->table, virt_loc);
1309 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1310 gtk_widget_show (GTK_WIDGET(sheet->item_editor));
1312 gtk_entry_set_text (GTK_ENTRY(sheet->entry), text);
1314 sheet->editing = TRUE;
1317 sheet->insert_signal =
1318 g_signal_connect (G_OBJECT(sheet->entry),
"insert_text",
1319 G_CALLBACK(gnucash_sheet_insert_cb), sheet);
1320 sheet->delete_signal =
1321 g_signal_connect (G_OBJECT(sheet->entry),
"delete_text",
1322 G_CALLBACK(gnucash_sheet_delete_cb), sheet);
1326 gnucash_sheet_button_release_event (GtkWidget *widget, GdkEventButton *event)
1328 GnucashSheet *sheet;
1330 g_return_val_if_fail (widget != NULL, TRUE);
1331 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1332 g_return_val_if_fail (event != NULL, TRUE);
1334 sheet = GNUCASH_SHEET(widget);
1336 if (sheet->button != event->button)
1341 if (event->button != 1)
1344 gtk_grab_remove (widget);
1345 sheet->grabbed = FALSE;
1351 clamp_scrollable_value (
float value, GtkAdjustment* adj)
1353 float lower = gtk_adjustment_get_lower (adj);
1354 float upper = gtk_adjustment_get_upper (adj);
1355 float size = gtk_adjustment_get_page_size (adj);
1356 return CLAMP(value, lower, upper - size);
1360 gnucash_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1362 GnucashSheet *sheet;
1363 GtkAdjustment *vadj;
1364 gfloat h_value, v_value;
1366 g_return_val_if_fail (widget != NULL, TRUE);
1367 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1368 g_return_val_if_fail (event != NULL, TRUE);
1370 sheet = GNUCASH_SHEET(widget);
1372 v_value = gtk_adjustment_get_value (vadj);
1374 switch (event->direction)
1377 v_value -= gtk_adjustment_get_step_increment (vadj);
1379 case GDK_SCROLL_DOWN:
1380 v_value += gtk_adjustment_get_step_increment (vadj);
1387 case GDK_SCROLL_SMOOTH:
1388 h_value = gtk_adjustment_get_value (sheet->hadj);
1389 h_value +=
event->delta_x;
1390 h_value = clamp_scrollable_value (h_value, sheet->hadj);
1391 gtk_adjustment_set_value (sheet->hadj, h_value);
1392 #if defined MAC_INTEGRATION 1393 v_value +=
event->delta_y;
1395 int direction =
event->delta_y > 0 ? 1 :
event->delta_y < 0 ? -1 : 0;
1396 v_value += gtk_adjustment_get_step_increment (vadj) * direction;
1402 v_value = clamp_scrollable_value (v_value, vadj);
1403 gtk_adjustment_set_value (vadj, v_value);
1405 if (event->delta_y == 0)
1410 gtk_widget_hide (GTK_WIDGET(sheet->vscrollbar));
1411 gtk_widget_show (GTK_WIDGET(sheet->vscrollbar));
1417 gnucash_sheet_check_grab (GnucashSheet *sheet)
1419 GdkModifierType mods;
1424 if (!sheet->grabbed)
1427 window = gtk_widget_get_window (GTK_WIDGET(sheet));
1429 seat = gdk_display_get_default_seat (gdk_window_get_display (window));
1430 device = gdk_seat_get_pointer (seat);
1432 gdk_device_get_state (device, window, 0, &mods);
1434 if (!(mods & GDK_BUTTON1_MASK))
1436 gtk_grab_remove (GTK_WIDGET(sheet));
1437 sheet->grabbed = FALSE;
1442 gnucash_sheet_button_press_event (GtkWidget *widget, GdkEventButton *event)
1444 GnucashSheet *sheet;
1446 VirtualLocation cur_virt_loc;
1447 VirtualLocation new_virt_loc;
1449 gboolean abort_move;
1453 g_return_val_if_fail (widget != NULL, TRUE);
1454 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1455 g_return_val_if_fail (event != NULL, TRUE);
1457 sheet = GNUCASH_SHEET(widget);
1458 table = sheet->table;
1460 if (sheet->button && (sheet->button != event->button))
1463 sheet->button =
event->button;
1464 if (sheet->button == 3)
1467 if (!gtk_widget_has_focus (widget))
1468 gtk_widget_grab_focus (widget);
1473 switch (event->button)
1479 if (event->type != GDK_BUTTON_PRESS)
1481 gnc_item_edit_paste_clipboard (GNC_ITEM_EDIT(sheet->item_editor));
1484 do_popup = (sheet->popup != NULL);
1490 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1492 sheet->button_x = -1;
1493 sheet->button_y = -1;
1495 if (!gnucash_sheet_find_loc_by_pixel (sheet, event->x, event->y,
1499 sheet->button_x =
event->x;
1500 sheet->button_y =
event->y;
1506 if (event->type != GDK_BUTTON_PRESS)
1511 gtk_grab_add (widget);
1512 sheet->grabbed = TRUE;
1515 if (virt_loc_equal (new_virt_loc, cur_virt_loc) &&
1516 sheet->editing && do_popup)
1518 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1523 abort_move = gnc_table_traverse_update (
table,
1525 GNC_TABLE_TRAVERSE_POINTER,
1529 gnucash_sheet_check_grab (sheet);
1534 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1537 if (g_strcmp0 (gnc_table_get_cell_name (
table, new_virt_loc), DOCLINK_CELL) == 0)
1539 if (sheet->open_doclink_cb)
1540 (sheet->open_doclink_cb)(sheet->open_doclink_cb_data, NULL);
1544 gnucash_sheet_check_grab (sheet);
1547 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1549 return button_1 || do_popup;
1553 gnucash_sheet_refresh_from_prefs (GnucashSheet *sheet)
1555 GtkStyleContext *stylectxt;
1557 GList *classes = NULL;
1559 g_return_if_fail (sheet != NULL);
1560 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1563 GNC_PREF_USE_GNUCASH_COLOR_THEME);
1565 GNC_PREF_DRAW_HOR_LINES);
1567 GNC_PREF_DRAW_VERT_LINES);
1569 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1571 stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
1574 classes = gtk_style_context_list_classes (stylectxt);
1576 for (GList *l = classes; l; l = l->next)
1578 if (g_str_has_prefix (l->data,
"gnc-class-"))
1579 gtk_style_context_remove_class (stylectxt, l->data);
1581 g_list_free (classes);
1583 gtk_style_context_remove_class (stylectxt, GTK_STYLE_CLASS_VIEW);
1591 gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
1594 gboolean handled = FALSE;
1596 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1598 switch (event->keyval)
1602 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1604 gnc_item_edit_copy_clipboard (item_edit);
1610 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1612 gnc_item_edit_cut_clipboard (item_edit);
1618 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1620 gnc_item_edit_paste_clipboard (item_edit);
1624 case GDK_KEY_Insert:
1625 if (event->state & GDK_SHIFT_MASK)
1627 gnc_item_edit_paste_clipboard (item_edit);
1630 else if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1632 gnc_item_edit_copy_clipboard (item_edit);
1641 gnucash_sheet_need_horizontal_scroll (GnucashSheet *sheet,
1642 VirtualLocation *new_virt_loc)
1645 gint cell_width = 0;
1648 if (sheet->window_width == sheet->width)
1652 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
1655 offset = gnc_header_get_cell_offset (GNC_HEADER(sheet->header_item),
1656 new_virt_loc->phys_col_offset, &cell_width);
1658 if (((offset + cell_width) > sheet->window_width) || (offset < hscroll_val))
1659 gtk_adjustment_set_value (sheet->hadj, offset);
1663 process_motion_keys (GnucashSheet *sheet, GdkEventKey *event, gboolean *pass_on,
1664 gncTableTraversalDir *direction,
1665 VirtualLocation* new_virt_loc)
1668 VirtualLocation cur_virt_loc = *new_virt_loc;
1670 switch (event->keyval)
1672 case GDK_KEY_Return:
1673 case GDK_KEY_KP_Enter:
1674 g_signal_emit_by_name (sheet->reg,
"activate_cursor");
1676 sheet->pos = sheet->bound;
1680 case GDK_KEY_ISO_Left_Tab:
1681 if (event->state & GDK_SHIFT_MASK)
1683 *direction = GNC_TABLE_TRAVERSE_LEFT;
1684 gnc_table_move_tab (sheet->table, new_virt_loc, FALSE);
1688 *direction = GNC_TABLE_TRAVERSE_RIGHT;
1689 gnc_table_move_tab (sheet->table, new_virt_loc, TRUE);
1692 case GDK_KEY_KP_Page_Up:
1693 case GDK_KEY_Page_Up:
1694 *direction = GNC_TABLE_TRAVERSE_UP;
1695 new_virt_loc->phys_col_offset = 0;
1696 if (event->state & GDK_SHIFT_MASK)
1697 new_virt_loc->vcell_loc.virt_row = 1;
1700 distance = sheet->num_visible_phys_rows - 1;
1702 (sheet->table, new_virt_loc, -distance);
1705 case GDK_KEY_KP_Page_Down:
1706 case GDK_KEY_Page_Down:
1707 *direction = GNC_TABLE_TRAVERSE_DOWN;
1708 new_virt_loc->phys_col_offset = 0;
1709 if (event->state & GDK_SHIFT_MASK)
1710 new_virt_loc->vcell_loc.virt_row =
1711 sheet->num_virt_rows - 1;
1714 distance = sheet->num_visible_phys_rows - 1;
1716 (sheet->table, new_virt_loc, distance);
1721 *direction = GNC_TABLE_TRAVERSE_UP;
1725 case GDK_KEY_KP_Down:
1728 if (event->keyval == GDK_KEY_Menu ||
1729 (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR))
1731 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1733 if (gnc_table_confirm_change (sheet->table, cur_virt_loc))
1734 gnc_item_edit_show_popup (item_edit);
1737 sheet->pos = sheet->bound;
1741 *direction = GNC_TABLE_TRAVERSE_DOWN;
1745 case GDK_KEY_KP_Right:
1747 case GDK_KEY_KP_Left:
1752 sheet->pos = sheet->bound;
1756 if (gnucash_sheet_clipboard_event (sheet, event))
1759 sheet->pos = sheet->bound;
1766 gnucash_sheet_need_horizontal_scroll (sheet, new_virt_loc);
1772 pass_to_entry_handler (GnucashSheet *sheet, GdkEventKey *event)
1774 gboolean result = FALSE;
1775 GtkEditable *editable = GTK_EDITABLE(sheet->entry);
1778 if (gtk_widget_get_realized (GTK_WIDGET(editable)))
1780 result = gtk_widget_event (GTK_WIDGET(editable), (GdkEvent*)event);
1781 gnucash_sheet_set_selection_from_entry (sheet);
1787 gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event)
1790 GnucashSheet *sheet;
1791 gboolean pass_on = FALSE;
1792 gboolean abort_move;
1793 VirtualLocation cur_virt_loc;
1794 VirtualLocation new_virt_loc;
1795 gncTableTraversalDir direction = 0;
1796 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
1798 g_return_val_if_fail (widget != NULL, TRUE);
1799 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1800 g_return_val_if_fail (event != NULL, TRUE);
1802 sheet = GNUCASH_SHEET(widget);
1803 table = sheet->table;
1805 if (event->is_modifier)
1810 gnucash_sheet_set_selection_from_entry (sheet);
1812 if (gnucash_sheet_direct_event (sheet, (GdkEvent *) event))
1815 if (gtk_entry_im_context_filter_keypress (GTK_ENTRY(sheet->entry), event))
1817 #if !(defined(__APPLE__) || defined(__WIN32__)) 1827 gnucash_sheet_set_entry_selection (sheet);
1831 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1832 new_virt_loc = cur_virt_loc;
1837 if (event->state & modifiers & (GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK))
1839 else if (process_motion_keys (sheet, event, &pass_on,
1840 &direction, &new_virt_loc))
1846 return pass_to_entry_handler (sheet, event);
1849 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1850 direction, &new_virt_loc);
1856 if (!gtk_widget_has_focus (GTK_WIDGET(sheet)))
1857 gtk_widget_grab_focus (GTK_WIDGET(sheet));
1862 sheet->pos = sheet->bound;
1863 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1870 gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
1872 GnucashSheet *sheet;
1874 g_return_val_if_fail (widget != NULL, TRUE);
1875 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1876 g_return_val_if_fail (event != NULL, TRUE);
1878 sheet = GNUCASH_SHEET(widget);
1883 sheet->shift_state =
event->state & GDK_SHIFT_MASK;
1884 sheet->keyval_state =
1885 (
event->keyval == GDK_KEY_KP_Decimal) ? GDK_KEY_KP_Decimal : 0;
1887 return gnucash_sheet_key_press_event_internal (widget, event);
1891 gnucash_sheet_key_release_event (GtkWidget *widget, GdkEventKey *event)
1893 g_return_val_if_fail (widget != NULL, TRUE);
1894 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1895 g_return_val_if_fail (event != NULL, TRUE);
1902 gnucash_sheet_goto_virt_loc (GnucashSheet *sheet, VirtualLocation virt_loc)
1905 gboolean abort_move;
1906 VirtualLocation cur_virt_loc;
1908 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1910 table = sheet->table;
1912 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1916 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1917 GNC_TABLE_TRAVERSE_POINTER,
1924 gnucash_sheet_need_horizontal_scroll (sheet, &virt_loc);
1926 gnucash_sheet_cursor_move (sheet, virt_loc);
1930 gnucash_sheet_get_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
1932 g_return_val_if_fail (sheet != NULL, NULL);
1933 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1937 vcell_loc.virt_col);
1940 GncItemEdit *gnucash_sheet_get_item_edit (GnucashSheet *sheet)
1942 g_return_val_if_fail (sheet != NULL, NULL);
1943 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1945 if (sheet->item_editor == NULL)
1948 return GNC_ITEM_EDIT(sheet->item_editor);
1952 void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window)
1954 g_return_if_fail (sheet != NULL);
1955 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1958 g_return_if_fail (GTK_IS_WIDGET(window));
1960 sheet->window = window;
1967 gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
1968 VirtualCellLocation vcell_loc)
1972 SheetBlockStyle *style;
1975 block = gnucash_sheet_get_block (sheet, vcell_loc);
1976 style = gnucash_sheet_get_style_from_table (sheet, vcell_loc);
1981 table = sheet->table;
1987 gnucash_sheet_style_unref (sheet, block->
style);
1988 block->
style = NULL;
1993 if (block->
style == NULL)
1995 block->
style = style;
1996 gnucash_sheet_style_ref (sheet, block->
style);
2004 gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
2011 SheetBlockStyle *style;
2012 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
"");
2013 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
2014 const gchar *type_name;
2016 g_return_val_if_fail (virt_col >= 0, 0);
2017 g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
2018 g_return_val_if_fail (cell_col >= 0, 0);
2020 for (virt_row = 0; virt_row < sheet->num_virt_rows ; virt_row++)
2022 VirtualCellLocation vcell_loc = { virt_row, virt_col };
2024 block = gnucash_sheet_get_block (sheet, vcell_loc);
2028 style = block->
style;
2033 if (cell_col < style->ncols)
2035 for (cell_row = 0; cell_row < style->nrows; cell_row++)
2037 VirtualLocation virt_loc;
2041 virt_loc.vcell_loc = sheet->table->current_cursor_loc.vcell_loc;
2043 virt_loc.vcell_loc = vcell_loc;
2045 virt_loc.phys_row_offset = cell_row;
2046 virt_loc.phys_col_offset = cell_col;
2050 text = gnc_table_get_label
2051 (sheet->table, virt_loc);
2055 text = gnc_table_get_entry
2056 (sheet->table, virt_loc);
2059 pango_layout_set_text (layout, text, strlen (text));
2060 pango_layout_get_pixel_size (layout, &width, NULL);
2062 width += (gnc_item_edit_get_margin (item_edit, left_right) +
2063 gnc_item_edit_get_padding_border (item_edit, left_right));
2067 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
2068 if ((g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
2069 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0))
2071 width += gnc_item_edit_get_button_width (item_edit) + 2;
2073 max = MAX(max, width);
2078 g_object_unref (layout);
2084 gnucash_sheet_set_scroll_region (GnucashSheet *sheet)
2087 GtkAllocation alloc;
2093 if (!sheet->header_item || !GNC_HEADER(sheet->header_item)->style)
2096 gtk_layout_get_size (GTK_LAYOUT(sheet), &old_w, &old_h);
2098 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
2099 new_h = MAX(sheet->height, alloc.height);
2100 new_w = MAX(sheet->width, alloc.width);
2102 if (new_w != old_w || new_h != old_h)
2103 gtk_layout_set_size (GTK_LAYOUT(sheet), new_w, new_h);
2107 gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
2110 GnucashSheet *sheet = GNUCASH_SHEET(user_data);
2117 gnucash_sheet_style_unref (sheet, block->
style);
2123 gnucash_sheet_block_construct (gpointer _block, gpointer user_data)
2127 block->
style = NULL;
2132 gnucash_sheet_resize (GnucashSheet *sheet)
2134 g_return_if_fail (sheet != NULL);
2135 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2137 if (sheet->table->num_virt_cols > 1)
2138 g_warning (
"num_virt_cols > 1");
2140 sheet->num_virt_cols = 1;
2144 sheet->num_virt_rows = sheet->table->num_virt_rows;
2148 gnucash_sheet_recompute_block_offsets (GnucashSheet *sheet)
2156 g_return_if_fail (sheet != NULL);
2157 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2158 g_return_if_fail (sheet->table != NULL);
2160 table = sheet->table;
2164 for (i = 0; i <
table->num_virt_rows; i++)
2168 for (j = 0; j <
table->num_virt_cols; j++)
2170 VirtualCellLocation vcell_loc = { i, j };
2172 block = gnucash_sheet_get_block (sheet, vcell_loc);
2177 block->origin_x = width;
2181 width += block->
style->dimensions->width;
2184 if (i > 0 && block && block->
visible)
2185 height += block->
style->dimensions->height;
2187 sheet->height = height;
2191 gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
2194 gint num_header_phys_rows;
2197 g_return_if_fail (sheet != NULL);
2198 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2199 g_return_if_fail (sheet->table != NULL);
2201 table = sheet->table;
2203 gnucash_sheet_stop_editing (sheet);
2205 gnucash_sheet_resize (sheet);
2207 num_header_phys_rows = 0;
2210 for (i = 0; i <
table->num_virt_rows; i++)
2211 for (j = 0; j <
table->num_virt_cols; j++)
2213 VirtualCellLocation vcell_loc = { i, j };
2216 gnucash_sheet_block_set_from_table (sheet, vcell_loc);
2220 num_header_phys_rows =
2221 MAX (num_header_phys_rows,
2222 vcell->cellblock->num_rows);
2225 gnc_header_set_header_rows (GNC_HEADER(sheet->header_item),
2226 num_header_phys_rows);
2227 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
2229 gnucash_sheet_recompute_block_offsets (sheet);
2231 gnucash_sheet_set_scroll_region (sheet);
2235 VirtualLocation virt_loc;
2237 virt_loc =
table->current_cursor_loc;
2239 if (gnucash_sheet_cell_valid (sheet, virt_loc))
2240 gnucash_sheet_show_row (sheet,
2241 virt_loc.vcell_loc.virt_row);
2244 gnucash_sheet_cursor_set_from_table (sheet, do_scroll);
2245 gnucash_sheet_activate_cursor_cell (sheet, TRUE);
2255 gchar *full_class, *style_class = NULL;
2257 if (field_type >= COLOR_NEGATIVE)
2260 gtk_style_context_add_class (stylectxt,
"gnc-class-negative-numbers");
2261 field_type -= COLOR_NEGATIVE;
2265 if (sheet->use_gnc_color_theme)
2266 gtk_style_context_add_class (stylectxt,
"gnc-class-register-foreground");
2272 case COLOR_UNDEFINED:
2273 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
2277 style_class =
"header";
2281 style_class =
"primary";
2284 case COLOR_PRIMARY_ACTIVE:
2285 case COLOR_SECONDARY_ACTIVE:
2286 case COLOR_SPLIT_ACTIVE:
2287 gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
2288 style_class =
"cursor";
2291 case COLOR_SECONDARY:
2292 style_class =
"secondary";
2296 style_class =
"split";
2300 if (sheet->use_gnc_color_theme)
2301 full_class = g_strconcat (
"gnc-class-register-", style_class, NULL);
2304 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_VIEW);
2305 full_class = g_strconcat (
"gnc-class-user-register-", style_class, NULL);
2308 gtk_style_context_add_class (stylectxt, full_class);
2310 g_free (full_class);
2316 gnucash_sheet_class_init (GnucashSheetClass *klass)
2318 GObjectClass *gobject_class;
2319 GtkWidgetClass *widget_class;
2321 gobject_class = G_OBJECT_CLASS(klass);
2322 widget_class = GTK_WIDGET_CLASS(klass);
2324 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(klass),
"gnc-id-sheet");
2327 gobject_class->finalize = gnucash_sheet_finalize;
2329 widget_class->get_preferred_width = gnucash_sheet_get_preferred_width;
2330 widget_class->get_preferred_height = gnucash_sheet_get_preferred_height;
2331 widget_class->size_allocate = gnucash_sheet_size_allocate;
2333 widget_class->focus_in_event = gnucash_sheet_focus_in_event;
2334 widget_class->focus_out_event = gnucash_sheet_focus_out_event;
2336 widget_class->key_press_event = gnucash_sheet_key_press_event;
2337 widget_class->key_release_event = gnucash_sheet_key_release_event;
2338 widget_class->button_press_event = gnucash_sheet_button_press_event;
2339 widget_class->button_release_event = gnucash_sheet_button_release_event;
2340 widget_class->scroll_event = gnucash_scroll_event;
2345 gnucash_sheet_init (GnucashSheet *sheet)
2347 gtk_widget_set_can_focus (GTK_WIDGET(sheet), TRUE);
2348 gtk_widget_set_can_default (GTK_WIDGET(sheet), TRUE);
2350 sheet->num_visible_blocks = 1;
2351 sheet->num_visible_phys_rows = 1;
2353 sheet->input_cancelled = FALSE;
2355 sheet->popup = NULL;
2356 sheet->num_virt_rows = 0;
2357 sheet->num_virt_cols = 0;
2358 sheet->item_editor = NULL;
2359 sheet->entry = NULL;
2360 sheet->editing = FALSE;
2362 sheet->grabbed = FALSE;
2363 sheet->window_width = -1;
2364 sheet->window_height = -1;
2368 sheet->cursor_styles = g_hash_table_new (g_str_hash, g_str_equal);
2371 gnucash_sheet_block_construct,
2372 gnucash_sheet_block_destroy, sheet);
2374 gtk_widget_add_events (GTK_WIDGET(sheet),
2376 | GDK_BUTTON_PRESS_MASK
2377 | GDK_BUTTON_RELEASE_MASK
2378 | GDK_POINTER_MOTION_MASK
2379 | GDK_POINTER_MOTION_HINT_MASK));
2382 sheet->direct_update_cell = FALSE;
2383 sheet->shift_state = 0;
2384 sheet->keyval_state = 0;
2385 sheet->bound = sheet->pos = 0;
2389 gnucash_sheet_tooltip (GtkWidget *widget, gint x, gint y,
2390 gboolean keyboard_mode,
2391 GtkTooltip *tooltip,
2394 GnucashSheet *sheet = GNUCASH_SHEET(widget);
2395 Table *
table = sheet->table;
2396 VirtualLocation virt_loc;
2397 gchar *tooltip_text;
2398 gint cx, cy, cw, ch;
2402 gint hscroll_val, vscroll_val;
2408 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
2409 vscroll_val = (gint) gtk_adjustment_get_value (sheet->vadj);
2411 if (!gnucash_sheet_find_loc_by_pixel (sheet, x + hscroll_val, y + vscroll_val, &virt_loc))
2414 tooltip_text = gnc_table_get_tooltip (
table, virt_loc);
2417 if (!tooltip_text || (g_strcmp0 (tooltip_text,
"") == 0))
2419 gtk_tooltip_set_text (tooltip, NULL);
2423 block = gnucash_sheet_get_block (sheet, virt_loc.vcell_loc);
2426 g_free (tooltip_text);
2430 bx = block->origin_x;
2434 gnucash_sheet_style_get_cell_pixel_rel_coords (block->
style,
2435 virt_loc.phys_row_offset, virt_loc.phys_col_offset,
2436 &cx, &cy, &cw, &ch);
2438 rect.x = cx + bx - hscroll_val;
2439 rect.y = cy + by - vscroll_val;
2443 gtk_tooltip_set_tip_area (tooltip, &rect);
2444 gtk_tooltip_set_text (tooltip, tooltip_text);
2445 g_free (tooltip_text);
2451 gnucash_sheet_new (Table *
table)
2453 GnucashSheet *sheet;
2455 g_return_val_if_fail (
table != NULL, NULL);
2457 sheet = gnucash_sheet_create (
table);
2460 sheet->sheet_has_focus = TRUE;
2463 sheet->cursor = gnucash_cursor_new (sheet);
2466 sheet->item_editor = gnc_item_edit_new (sheet);
2469 sheet->dimensions_hash_table = g_hash_table_new_full (g_int_hash,
2474 gtk_widget_set_has_tooltip (GTK_WIDGET(sheet), TRUE);
2475 g_signal_connect (G_OBJECT(sheet),
"query-tooltip",
2476 G_CALLBACK(gnucash_sheet_tooltip), NULL);
2478 gnucash_sheet_refresh_from_prefs (sheet);
2480 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