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),
1110 delete_text (GnucashSheet *sheet,
int pos,
int bound)
1112 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1113 int old_length = g_utf8_strlen (old_text, -1);
1115 char *retval = NULL;
1117 normalize_selection_bounds (&pos, &bound, old_length);
1119 return g_strdup (old_text);
1121 if (pos == 0 && bound == old_length)
1122 return g_strdup (
"");
1124 if (bound == old_length)
1125 return g_utf8_substring (old_text, 0, pos);
1128 return g_utf8_substring (old_text, bound, old_length);
1130 begin = g_utf8_substring (old_text, 0, pos);
1131 end = g_utf8_substring (old_text, bound, old_length);
1132 retval = g_strdup_printf (
"%s%s", begin, end);
1139 gnucash_sheet_delete_cb (GtkWidget *widget,
1140 const gint start_pos,
1142 GnucashSheet *sheet)
1144 GtkEditable *editable;
1145 Table *
table = sheet->table;
1146 VirtualLocation virt_loc;
1147 char *new_text = NULL;
1150 int cursor_position = start_pos;
1151 int start_sel, end_sel;
1153 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1155 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1158 if (gnc_table_model_read_only (
table->model))
1161 new_text = delete_text (sheet, start_pos, end_pos);
1162 new_text_len = strlen (new_text);
1163 editable = GTK_EDITABLE(sheet->entry);
1164 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
1165 retval = gnc_table_modify_update (
table, virt_loc,
1167 new_text, new_text_len,
1169 &start_sel, &end_sel,
1170 &sheet->input_cancelled);
1173 gnucash_sheet_set_entry_value (sheet, retval);
1175 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
"delete_text");
1177 DEBUG(
"%s", retval ? retval :
"nothing");
1178 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
1179 start_sel, end_sel);
1183 gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer data)
1185 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1186 GtkStyleContext *context = gtk_widget_get_style_context (widget);
1187 GtkAllocation alloc;
1189 gtk_widget_get_allocation (widget, &alloc);
1191 gtk_style_context_save (context);
1192 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
1193 gtk_render_background (context, cr, 0, 0, alloc.width, alloc.height);
1194 gtk_style_context_restore (context);
1196 gnucash_sheet_draw_internal (sheet, cr, &alloc);
1197 gnucash_sheet_draw_cursor (sheet->cursor, cr);
1204 gnucash_sheet_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
1206 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1208 ENTER(
"widget=%p, allocation=%p", widget, allocation);
1210 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1211 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->size_allocate)
1212 (widget, allocation);
1214 if (allocation->height == sheet->window_height &&
1215 allocation->width == sheet->window_width)
1217 LEAVE(
"size unchanged");
1221 if (allocation->width != sheet->window_width)
1223 gnucash_sheet_styles_set_dimensions (sheet, allocation->width);
1224 gnucash_sheet_recompute_block_offsets (sheet);
1227 sheet->window_height = allocation->height;
1228 sheet->window_width = allocation->width;
1230 gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
1231 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
1232 gnucash_sheet_set_scroll_region (sheet);
1234 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1235 gnucash_sheet_update_adjustments (sheet);
1239 VirtualLocation virt_loc;
1241 virt_loc = sheet->table->current_cursor_loc;
1243 if (gnucash_sheet_cell_valid (sheet, virt_loc))
1244 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
1246 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
1251 gnucash_sheet_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1253 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1255 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1256 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_in_event)
1259 gnc_item_edit_focus_in (GNC_ITEM_EDIT(sheet->item_editor));
1265 gnucash_sheet_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1267 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1269 if (GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1270 (*GTK_WIDGET_CLASS(gnucash_sheet_parent_class)->focus_out_event)
1273 gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
1278 gnucash_sheet_check_direct_update_cell (GnucashSheet *sheet,
1279 const VirtualLocation virt_loc)
1281 const gchar *type_name;
1283 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
1285 if ( (g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
1286 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0)
1287 || (g_strcmp0 (type_name, NUM_CELL_TYPE_NAME) == 0)
1288 || (g_strcmp0 (type_name, PRICE_CELL_TYPE_NAME) == 0)
1289 || (g_strcmp0 (type_name, FORMULA_CELL_TYPE_NAME) == 0))
return TRUE;
1295 gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
1298 VirtualLocation virt_loc;
1300 g_return_if_fail (sheet != NULL);
1301 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1303 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1305 text = gnc_table_get_entry (sheet->table, virt_loc);
1307 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1308 gtk_widget_show (GTK_WIDGET(sheet->item_editor));
1310 gtk_entry_set_text (GTK_ENTRY(sheet->entry), text);
1312 sheet->editing = TRUE;
1315 sheet->insert_signal =
1316 g_signal_connect (G_OBJECT(sheet->entry),
"insert_text",
1317 G_CALLBACK(gnucash_sheet_insert_cb), sheet);
1318 sheet->delete_signal =
1319 g_signal_connect (G_OBJECT(sheet->entry),
"delete_text",
1320 G_CALLBACK(gnucash_sheet_delete_cb), sheet);
1324 gnucash_sheet_button_release_event (GtkWidget *widget, GdkEventButton *event)
1326 GnucashSheet *sheet;
1328 g_return_val_if_fail (widget != NULL, TRUE);
1329 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1330 g_return_val_if_fail (event != NULL, TRUE);
1332 sheet = GNUCASH_SHEET(widget);
1334 if (sheet->button != event->button)
1339 if (event->button != 1)
1342 gtk_grab_remove (widget);
1343 sheet->grabbed = FALSE;
1349 clamp_scrollable_value (
float value, GtkAdjustment* adj)
1351 float lower = gtk_adjustment_get_lower (adj);
1352 float upper = gtk_adjustment_get_upper (adj);
1353 float size = gtk_adjustment_get_page_size (adj);
1354 return CLAMP(value, lower, upper - size);
1358 gnucash_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1360 GnucashSheet *sheet;
1361 GtkAdjustment *vadj;
1362 gfloat h_value, v_value;
1364 g_return_val_if_fail (widget != NULL, TRUE);
1365 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1366 g_return_val_if_fail (event != NULL, TRUE);
1368 sheet = GNUCASH_SHEET(widget);
1370 v_value = gtk_adjustment_get_value (vadj);
1372 switch (event->direction)
1375 v_value -= gtk_adjustment_get_step_increment (vadj);
1377 case GDK_SCROLL_DOWN:
1378 v_value += gtk_adjustment_get_step_increment (vadj);
1385 case GDK_SCROLL_SMOOTH:
1386 h_value = gtk_adjustment_get_value (sheet->hadj);
1387 h_value +=
event->delta_x;
1388 h_value = clamp_scrollable_value (h_value, sheet->hadj);
1389 gtk_adjustment_set_value (sheet->hadj, h_value);
1390 #if defined MAC_INTEGRATION 1391 v_value +=
event->delta_y;
1393 int direction =
event->delta_y > 0 ? 1 :
event->delta_y < 0 ? -1 : 0;
1394 v_value += gtk_adjustment_get_step_increment (vadj) * direction;
1400 v_value = clamp_scrollable_value (v_value, vadj);
1401 gtk_adjustment_set_value (vadj, v_value);
1403 if (event->delta_y == 0)
1408 gtk_widget_hide (GTK_WIDGET(sheet->vscrollbar));
1409 gtk_widget_show (GTK_WIDGET(sheet->vscrollbar));
1415 gnucash_sheet_check_grab (GnucashSheet *sheet)
1417 GdkModifierType mods;
1422 if (!sheet->grabbed)
1425 window = gtk_widget_get_window (GTK_WIDGET(sheet));
1427 seat = gdk_display_get_default_seat (gdk_window_get_display (window));
1428 device = gdk_seat_get_pointer (seat);
1430 gdk_device_get_state (device, window, 0, &mods);
1432 if (!(mods & GDK_BUTTON1_MASK))
1434 gtk_grab_remove (GTK_WIDGET(sheet));
1435 sheet->grabbed = FALSE;
1440 gnucash_sheet_button_press_event (GtkWidget *widget, GdkEventButton *event)
1442 GnucashSheet *sheet;
1444 VirtualLocation cur_virt_loc;
1445 VirtualLocation new_virt_loc;
1447 gboolean abort_move;
1451 g_return_val_if_fail (widget != NULL, TRUE);
1452 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1453 g_return_val_if_fail (event != NULL, TRUE);
1455 sheet = GNUCASH_SHEET(widget);
1456 table = sheet->table;
1458 if (sheet->button && (sheet->button != event->button))
1461 sheet->button =
event->button;
1462 if (sheet->button == 3)
1465 if (!gtk_widget_has_focus (widget))
1466 gtk_widget_grab_focus (widget);
1471 switch (event->button)
1477 if (event->type != GDK_BUTTON_PRESS)
1479 gnc_item_edit_paste_clipboard (GNC_ITEM_EDIT(sheet->item_editor));
1482 do_popup = (sheet->popup != NULL);
1488 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1490 sheet->button_x = -1;
1491 sheet->button_y = -1;
1493 if (!gnucash_sheet_find_loc_by_pixel (sheet, event->x, event->y,
1497 sheet->button_x =
event->x;
1498 sheet->button_y =
event->y;
1504 if (event->type != GDK_BUTTON_PRESS)
1509 gtk_grab_add (widget);
1510 sheet->grabbed = TRUE;
1513 if (virt_loc_equal (new_virt_loc, cur_virt_loc) &&
1514 sheet->editing && do_popup)
1516 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1521 abort_move = gnc_table_traverse_update (
table,
1523 GNC_TABLE_TRAVERSE_POINTER,
1527 gnucash_sheet_check_grab (sheet);
1532 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1535 if (g_strcmp0 (gnc_table_get_cell_name (
table, new_virt_loc), DOCLINK_CELL) == 0)
1537 if (sheet->open_doclink_cb)
1538 (sheet->open_doclink_cb)(sheet->open_doclink_cb_data, NULL);
1542 gnucash_sheet_check_grab (sheet);
1545 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1547 return button_1 || do_popup;
1551 gnucash_sheet_refresh_from_prefs (GnucashSheet *sheet)
1553 GtkStyleContext *stylectxt;
1555 GList *classes = NULL;
1557 g_return_if_fail (sheet != NULL);
1558 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1561 GNC_PREF_USE_GNUCASH_COLOR_THEME);
1563 GNC_PREF_DRAW_HOR_LINES);
1565 GNC_PREF_DRAW_VERT_LINES);
1567 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1569 stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
1572 classes = gtk_style_context_list_classes (stylectxt);
1574 for (GList *l = classes; l; l = l->next)
1576 if (g_str_has_prefix (l->data,
"gnc-class-"))
1577 gtk_style_context_remove_class (stylectxt, l->data);
1579 g_list_free (classes);
1581 gtk_style_context_remove_class (stylectxt, GTK_STYLE_CLASS_VIEW);
1589 gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
1592 gboolean handled = FALSE;
1594 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1596 switch (event->keyval)
1600 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1602 gnc_item_edit_copy_clipboard (item_edit);
1608 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1610 gnc_item_edit_cut_clipboard (item_edit);
1616 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1618 gnc_item_edit_paste_clipboard (item_edit);
1622 case GDK_KEY_Insert:
1623 if (event->state & GDK_SHIFT_MASK)
1625 gnc_item_edit_paste_clipboard (item_edit);
1628 else if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1630 gnc_item_edit_copy_clipboard (item_edit);
1639 gnucash_sheet_need_horizontal_scroll (GnucashSheet *sheet,
1640 VirtualLocation *new_virt_loc)
1643 gint cell_width = 0;
1646 if (sheet->window_width == sheet->width)
1650 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
1653 offset = gnc_header_get_cell_offset (GNC_HEADER(sheet->header_item),
1654 new_virt_loc->phys_col_offset, &cell_width);
1656 if (((offset + cell_width) > sheet->window_width) || (offset < hscroll_val))
1657 gtk_adjustment_set_value (sheet->hadj, offset);
1661 process_motion_keys (GnucashSheet *sheet, GdkEventKey *event, gboolean *pass_on,
1662 gncTableTraversalDir *direction,
1663 VirtualLocation* new_virt_loc)
1666 VirtualLocation cur_virt_loc = *new_virt_loc;
1668 switch (event->keyval)
1670 case GDK_KEY_Return:
1671 case GDK_KEY_KP_Enter:
1672 g_signal_emit_by_name (sheet->reg,
"activate_cursor");
1674 sheet->pos = sheet->bound;
1678 case GDK_KEY_ISO_Left_Tab:
1679 if (event->state & GDK_SHIFT_MASK)
1681 *direction = GNC_TABLE_TRAVERSE_LEFT;
1682 gnc_table_move_tab (sheet->table, new_virt_loc, FALSE);
1686 *direction = GNC_TABLE_TRAVERSE_RIGHT;
1687 gnc_table_move_tab (sheet->table, new_virt_loc, TRUE);
1690 case GDK_KEY_KP_Page_Up:
1691 case GDK_KEY_Page_Up:
1692 *direction = GNC_TABLE_TRAVERSE_UP;
1693 new_virt_loc->phys_col_offset = 0;
1694 if (event->state & GDK_SHIFT_MASK)
1695 new_virt_loc->vcell_loc.virt_row = 1;
1698 distance = sheet->num_visible_phys_rows - 1;
1700 (sheet->table, new_virt_loc, -distance);
1703 case GDK_KEY_KP_Page_Down:
1704 case GDK_KEY_Page_Down:
1705 *direction = GNC_TABLE_TRAVERSE_DOWN;
1706 new_virt_loc->phys_col_offset = 0;
1707 if (event->state & GDK_SHIFT_MASK)
1708 new_virt_loc->vcell_loc.virt_row =
1709 sheet->num_virt_rows - 1;
1712 distance = sheet->num_visible_phys_rows - 1;
1714 (sheet->table, new_virt_loc, distance);
1719 *direction = GNC_TABLE_TRAVERSE_UP;
1723 case GDK_KEY_KP_Down:
1726 if (event->keyval == GDK_KEY_Menu ||
1727 (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR))
1729 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1731 if (gnc_table_confirm_change (sheet->table, cur_virt_loc))
1732 gnc_item_edit_show_popup (item_edit);
1735 sheet->pos = sheet->bound;
1739 *direction = GNC_TABLE_TRAVERSE_DOWN;
1743 case GDK_KEY_KP_Right:
1745 case GDK_KEY_KP_Left:
1750 sheet->pos = sheet->bound;
1754 if (gnucash_sheet_clipboard_event (sheet, event))
1757 sheet->pos = sheet->bound;
1764 gnucash_sheet_need_horizontal_scroll (sheet, new_virt_loc);
1770 pass_to_entry_handler (GnucashSheet *sheet, GdkEventKey *event)
1772 gboolean result = FALSE;
1773 GtkEditable *editable = GTK_EDITABLE(sheet->entry);
1776 if (gtk_widget_get_realized (GTK_WIDGET(editable)))
1778 result = gtk_widget_event (GTK_WIDGET(editable), (GdkEvent*)event);
1779 gnucash_sheet_set_selection_from_entry (sheet);
1785 gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event)
1788 GnucashSheet *sheet;
1789 gboolean pass_on = FALSE;
1790 gboolean abort_move;
1791 VirtualLocation cur_virt_loc;
1792 VirtualLocation new_virt_loc;
1793 gncTableTraversalDir direction = 0;
1794 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
1796 g_return_val_if_fail (widget != NULL, TRUE);
1797 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1798 g_return_val_if_fail (event != NULL, TRUE);
1800 sheet = GNUCASH_SHEET(widget);
1801 table = sheet->table;
1803 if (event->is_modifier)
1808 gnucash_sheet_set_selection_from_entry (sheet);
1810 if (gnucash_sheet_direct_event (sheet, (GdkEvent *) event))
1813 if (gtk_entry_im_context_filter_keypress (GTK_ENTRY(sheet->entry), event))
1815 #if !(defined(__APPLE__) || defined(__WIN32__)) 1825 gnucash_sheet_set_entry_selection (sheet);
1829 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1830 new_virt_loc = cur_virt_loc;
1835 if (event->state & modifiers & (GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK))
1837 else if (process_motion_keys (sheet, event, &pass_on,
1838 &direction, &new_virt_loc))
1844 return pass_to_entry_handler (sheet, event);
1847 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1848 direction, &new_virt_loc);
1854 if (!gtk_widget_has_focus (GTK_WIDGET(sheet)))
1855 gtk_widget_grab_focus (GTK_WIDGET(sheet));
1860 sheet->pos = sheet->bound;
1861 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1868 gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
1870 GnucashSheet *sheet;
1872 g_return_val_if_fail (widget != NULL, TRUE);
1873 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1874 g_return_val_if_fail (event != NULL, TRUE);
1876 sheet = GNUCASH_SHEET(widget);
1881 sheet->shift_state =
event->state & GDK_SHIFT_MASK;
1882 sheet->keyval_state =
1883 (
event->keyval == GDK_KEY_KP_Decimal) ? GDK_KEY_KP_Decimal : 0;
1885 return gnucash_sheet_key_press_event_internal (widget, event);
1889 gnucash_sheet_key_release_event (GtkWidget *widget, GdkEventKey *event)
1891 g_return_val_if_fail (widget != NULL, TRUE);
1892 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1893 g_return_val_if_fail (event != NULL, TRUE);
1900 gnucash_sheet_goto_virt_loc (GnucashSheet *sheet, VirtualLocation virt_loc)
1903 gboolean abort_move;
1904 VirtualLocation cur_virt_loc;
1906 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1908 table = sheet->table;
1910 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1914 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1915 GNC_TABLE_TRAVERSE_POINTER,
1922 gnucash_sheet_need_horizontal_scroll (sheet, &virt_loc);
1924 gnucash_sheet_cursor_move (sheet, virt_loc);
1928 gnucash_sheet_get_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
1930 g_return_val_if_fail (sheet != NULL, NULL);
1931 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1935 vcell_loc.virt_col);
1938 GncItemEdit *gnucash_sheet_get_item_edit (GnucashSheet *sheet)
1940 g_return_val_if_fail (sheet != NULL, NULL);
1941 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1943 if (sheet->item_editor == NULL)
1946 return GNC_ITEM_EDIT(sheet->item_editor);
1950 void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window)
1952 g_return_if_fail (sheet != NULL);
1953 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1956 g_return_if_fail (GTK_IS_WIDGET(window));
1958 sheet->window = window;
1965 gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
1966 VirtualCellLocation vcell_loc)
1970 SheetBlockStyle *style;
1973 block = gnucash_sheet_get_block (sheet, vcell_loc);
1974 style = gnucash_sheet_get_style_from_table (sheet, vcell_loc);
1979 table = sheet->table;
1985 gnucash_sheet_style_unref (sheet, block->
style);
1986 block->
style = NULL;
1991 if (block->
style == NULL)
1993 block->
style = style;
1994 gnucash_sheet_style_ref (sheet, block->
style);
2002 gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
2009 SheetBlockStyle *style;
2010 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
"");
2011 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
2012 const gchar *type_name;
2014 g_return_val_if_fail (virt_col >= 0, 0);
2015 g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
2016 g_return_val_if_fail (cell_col >= 0, 0);
2018 for (virt_row = 0; virt_row < sheet->num_virt_rows ; virt_row++)
2020 VirtualCellLocation vcell_loc = { virt_row, virt_col };
2022 block = gnucash_sheet_get_block (sheet, vcell_loc);
2026 style = block->
style;
2031 if (cell_col < style->ncols)
2033 for (cell_row = 0; cell_row < style->nrows; cell_row++)
2035 VirtualLocation virt_loc;
2039 virt_loc.vcell_loc = sheet->table->current_cursor_loc.vcell_loc;
2041 virt_loc.vcell_loc = vcell_loc;
2043 virt_loc.phys_row_offset = cell_row;
2044 virt_loc.phys_col_offset = cell_col;
2048 text = gnc_table_get_label
2049 (sheet->table, virt_loc);
2053 text = gnc_table_get_entry
2054 (sheet->table, virt_loc);
2057 pango_layout_set_text (layout, text, strlen (text));
2058 pango_layout_get_pixel_size (layout, &width, NULL);
2060 width += (gnc_item_edit_get_margin (item_edit, left_right) +
2061 gnc_item_edit_get_padding_border (item_edit, left_right));
2065 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
2066 if ((g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
2067 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0))
2069 width += gnc_item_edit_get_button_width (item_edit) + 2;
2071 max = MAX(max, width);
2076 g_object_unref (layout);
2082 gnucash_sheet_set_scroll_region (GnucashSheet *sheet)
2085 GtkAllocation alloc;
2091 if (!sheet->header_item || !GNC_HEADER(sheet->header_item)->style)
2094 gtk_layout_get_size (GTK_LAYOUT(sheet), &old_w, &old_h);
2096 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
2097 new_h = MAX(sheet->height, alloc.height);
2098 new_w = MAX(sheet->width, alloc.width);
2100 if (new_w != old_w || new_h != old_h)
2101 gtk_layout_set_size (GTK_LAYOUT(sheet), new_w, new_h);
2105 gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
2108 GnucashSheet *sheet = GNUCASH_SHEET(user_data);
2115 gnucash_sheet_style_unref (sheet, block->
style);
2121 gnucash_sheet_block_construct (gpointer _block, gpointer user_data)
2125 block->
style = NULL;
2130 gnucash_sheet_resize (GnucashSheet *sheet)
2132 g_return_if_fail (sheet != NULL);
2133 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2135 if (sheet->table->num_virt_cols > 1)
2136 g_warning (
"num_virt_cols > 1");
2138 sheet->num_virt_cols = 1;
2142 sheet->num_virt_rows = sheet->table->num_virt_rows;
2146 gnucash_sheet_recompute_block_offsets (GnucashSheet *sheet)
2154 g_return_if_fail (sheet != NULL);
2155 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2156 g_return_if_fail (sheet->table != NULL);
2158 table = sheet->table;
2162 for (i = 0; i <
table->num_virt_rows; i++)
2166 for (j = 0; j <
table->num_virt_cols; j++)
2168 VirtualCellLocation vcell_loc = { i, j };
2170 block = gnucash_sheet_get_block (sheet, vcell_loc);
2175 block->origin_x = width;
2179 width += block->
style->dimensions->width;
2182 if (i > 0 && block && block->
visible)
2183 height += block->
style->dimensions->height;
2185 sheet->height = height;
2189 gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
2192 gint num_header_phys_rows;
2195 g_return_if_fail (sheet != NULL);
2196 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2197 g_return_if_fail (sheet->table != NULL);
2199 table = sheet->table;
2201 gnucash_sheet_stop_editing (sheet);
2203 gnucash_sheet_resize (sheet);
2205 num_header_phys_rows = 0;
2208 for (i = 0; i <
table->num_virt_rows; i++)
2209 for (j = 0; j <
table->num_virt_cols; j++)
2211 VirtualCellLocation vcell_loc = { i, j };
2214 gnucash_sheet_block_set_from_table (sheet, vcell_loc);
2218 num_header_phys_rows =
2219 MAX (num_header_phys_rows,
2220 vcell->cellblock->num_rows);
2223 gnc_header_set_header_rows (GNC_HEADER(sheet->header_item),
2224 num_header_phys_rows);
2225 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
2227 gnucash_sheet_recompute_block_offsets (sheet);
2229 gnucash_sheet_set_scroll_region (sheet);
2233 VirtualLocation virt_loc;
2235 virt_loc =
table->current_cursor_loc;
2237 if (gnucash_sheet_cell_valid (sheet, virt_loc))
2238 gnucash_sheet_show_row (sheet,
2239 virt_loc.vcell_loc.virt_row);
2242 gnucash_sheet_cursor_set_from_table (sheet, do_scroll);
2243 gnucash_sheet_activate_cursor_cell (sheet, TRUE);
2253 gchar *full_class, *style_class = NULL;
2255 if (field_type >= COLOR_NEGATIVE)
2258 gtk_style_context_add_class (stylectxt,
"gnc-class-negative-numbers");
2259 field_type -= COLOR_NEGATIVE;
2263 if (sheet->use_gnc_color_theme)
2264 gtk_style_context_add_class (stylectxt,
"gnc-class-register-foreground");
2270 case COLOR_UNDEFINED:
2271 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
2275 style_class =
"header";
2279 style_class =
"primary";
2282 case COLOR_PRIMARY_ACTIVE:
2283 case COLOR_SECONDARY_ACTIVE:
2284 case COLOR_SPLIT_ACTIVE:
2285 gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
2286 style_class =
"cursor";
2289 case COLOR_SECONDARY:
2290 style_class =
"secondary";
2294 style_class =
"split";
2298 if (sheet->use_gnc_color_theme)
2299 full_class = g_strconcat (
"gnc-class-register-", style_class, NULL);
2302 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_VIEW);
2303 full_class = g_strconcat (
"gnc-class-user-register-", style_class, NULL);
2306 gtk_style_context_add_class (stylectxt, full_class);
2308 g_free (full_class);
2314 gnucash_sheet_class_init (GnucashSheetClass *klass)
2316 GObjectClass *gobject_class;
2317 GtkWidgetClass *widget_class;
2319 gobject_class = G_OBJECT_CLASS(klass);
2320 widget_class = GTK_WIDGET_CLASS(klass);
2322 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(klass),
"gnc-id-sheet");
2325 gobject_class->finalize = gnucash_sheet_finalize;
2327 widget_class->get_preferred_width = gnucash_sheet_get_preferred_width;
2328 widget_class->get_preferred_height = gnucash_sheet_get_preferred_height;
2329 widget_class->size_allocate = gnucash_sheet_size_allocate;
2331 widget_class->focus_in_event = gnucash_sheet_focus_in_event;
2332 widget_class->focus_out_event = gnucash_sheet_focus_out_event;
2334 widget_class->key_press_event = gnucash_sheet_key_press_event;
2335 widget_class->key_release_event = gnucash_sheet_key_release_event;
2336 widget_class->button_press_event = gnucash_sheet_button_press_event;
2337 widget_class->button_release_event = gnucash_sheet_button_release_event;
2338 widget_class->scroll_event = gnucash_scroll_event;
2343 gnucash_sheet_init (GnucashSheet *sheet)
2345 gtk_widget_set_can_focus (GTK_WIDGET(sheet), TRUE);
2346 gtk_widget_set_can_default (GTK_WIDGET(sheet), TRUE);
2348 sheet->num_visible_blocks = 1;
2349 sheet->num_visible_phys_rows = 1;
2351 sheet->input_cancelled = FALSE;
2353 sheet->popup = NULL;
2354 sheet->num_virt_rows = 0;
2355 sheet->num_virt_cols = 0;
2356 sheet->item_editor = NULL;
2357 sheet->entry = NULL;
2358 sheet->editing = FALSE;
2360 sheet->grabbed = FALSE;
2361 sheet->window_width = -1;
2362 sheet->window_height = -1;
2366 sheet->cursor_styles = g_hash_table_new (g_str_hash, g_str_equal);
2369 gnucash_sheet_block_construct,
2370 gnucash_sheet_block_destroy, sheet);
2372 gtk_widget_add_events (GTK_WIDGET(sheet),
2374 | GDK_BUTTON_PRESS_MASK
2375 | GDK_BUTTON_RELEASE_MASK
2376 | GDK_POINTER_MOTION_MASK
2377 | GDK_POINTER_MOTION_HINT_MASK));
2380 sheet->direct_update_cell = FALSE;
2381 sheet->shift_state = 0;
2382 sheet->keyval_state = 0;
2383 sheet->bound = sheet->pos = 0;
2387 gnucash_sheet_tooltip (GtkWidget *widget, gint x, gint y,
2388 gboolean keyboard_mode,
2389 GtkTooltip *tooltip,
2392 GnucashSheet *sheet = GNUCASH_SHEET(widget);
2393 Table *
table = sheet->table;
2394 VirtualLocation virt_loc;
2395 gchar *tooltip_text;
2396 gint cx, cy, cw, ch;
2400 gint hscroll_val, vscroll_val;
2406 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
2407 vscroll_val = (gint) gtk_adjustment_get_value (sheet->vadj);
2409 if (!gnucash_sheet_find_loc_by_pixel (sheet, x + hscroll_val, y + vscroll_val, &virt_loc))
2412 tooltip_text = gnc_table_get_tooltip (
table, virt_loc);
2415 if (!tooltip_text || (g_strcmp0 (tooltip_text,
"") == 0))
2417 gtk_tooltip_set_text (tooltip, NULL);
2421 block = gnucash_sheet_get_block (sheet, virt_loc.vcell_loc);
2424 g_free (tooltip_text);
2428 bx = block->origin_x;
2432 gnucash_sheet_style_get_cell_pixel_rel_coords (block->
style,
2433 virt_loc.phys_row_offset, virt_loc.phys_col_offset,
2434 &cx, &cy, &cw, &ch);
2436 rect.x = cx + bx - hscroll_val;
2437 rect.y = cy + by - vscroll_val;
2441 gtk_tooltip_set_tip_area (tooltip, &rect);
2442 gtk_tooltip_set_text (tooltip, tooltip_text);
2443 g_free (tooltip_text);
2449 gnucash_sheet_new (Table *
table)
2451 GnucashSheet *sheet;
2453 g_return_val_if_fail (
table != NULL, NULL);
2455 sheet = gnucash_sheet_create (
table);
2458 sheet->sheet_has_focus = TRUE;
2461 sheet->cursor = gnucash_cursor_new (sheet);
2464 sheet->item_editor = gnc_item_edit_new (sheet);
2467 sheet->dimensions_hash_table = g_hash_table_new_full (g_int_hash,
2472 gtk_widget_set_has_tooltip (GTK_WIDGET(sheet), TRUE);
2473 g_signal_connect (G_OBJECT(sheet),
"query-tooltip",
2474 G_CALLBACK(gnucash_sheet_tooltip), NULL);
2476 gnucash_sheet_refresh_from_prefs (sheet);
2478 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