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 73 static GtkLayout *sheet_parent_class;
78 static void gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet);
80 static gboolean gnucash_sheet_cursor_move (GnucashSheet *sheet,
81 VirtualLocation virt_loc);
83 static void gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet);
84 static void gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
85 gboolean changed_cells);
86 static void gnucash_sheet_stop_editing (GnucashSheet *sheet);
87 static gboolean gnucash_sheet_check_direct_update_cell (GnucashSheet *sheet,
88 const VirtualLocation virt_loc);
89 gboolean gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr,
90 G_GNUC_UNUSED gpointer data);
104 gnucash_sheet_set_entry_selection (GnucashSheet *sheet)
106 DEBUG(
"Set entry selection to sheet: %d:%d", sheet->bound, sheet->pos);
107 gtk_editable_select_region (GTK_EDITABLE(sheet->entry),
108 sheet->bound, sheet->pos);
112 gnucash_sheet_set_selection_from_entry (GnucashSheet *sheet)
114 gtk_editable_get_selection_bounds (GTK_EDITABLE(sheet->entry),
115 &sheet->bound, &sheet->pos);
119 gnucash_sheet_set_selection (GnucashSheet *sheet,
int pos,
int bound)
121 DEBUG(
"Set sheet selection %d:%d", bound, pos);
123 sheet->bound = bound;
124 gnucash_sheet_set_entry_selection (sheet);
129 gnucash_sheet_set_position_and_selection (GnucashSheet* sheet,
int pos,
132 if (pos == end || start == -1)
133 gnucash_sheet_set_selection (sheet, pos, start);
134 else if (pos == start || end == -1)
135 gnucash_sheet_set_selection (sheet, start, end);
136 else if (start == end)
137 gnucash_sheet_set_selection (sheet, pos, pos);
139 gnucash_sheet_set_selection (sheet, pos, end);
143 gnucash_sheet_set_position (GnucashSheet* sheet,
int pos)
145 gnucash_sheet_set_position_and_selection (sheet, pos, pos, pos);
149 gnucash_sheet_get_selection (GnucashSheet *sheet,
int *start,
int *end)
156 gnucash_sheet_clear_selection (GnucashSheet *sheet)
158 gnucash_sheet_set_selection (sheet, sheet->pos, sheet->pos);
162 gnucash_sheet_set_entry_value (GnucashSheet *sheet,
const char* value)
164 g_signal_handler_block (G_OBJECT(sheet->entry),
165 sheet->insert_signal);
166 g_signal_handler_block (G_OBJECT(sheet->entry),
167 sheet->delete_signal);
169 gtk_entry_set_text (GTK_ENTRY(sheet->entry), value);
171 g_signal_handler_unblock (G_OBJECT(sheet->entry),
172 sheet->delete_signal);
173 g_signal_handler_unblock (G_OBJECT(sheet->entry),
174 sheet->insert_signal);
178 static inline gboolean
179 gnucash_sheet_virt_cell_out_of_bounds (GnucashSheet *sheet,
180 VirtualCellLocation vcell_loc)
182 return (vcell_loc.virt_row < 1 ||
183 vcell_loc.virt_row >= sheet->num_virt_rows ||
184 vcell_loc.virt_col < 0 ||
185 vcell_loc.virt_col >= sheet->num_virt_cols);
189 gnucash_sheet_cell_valid (GnucashSheet *sheet, VirtualLocation virt_loc)
192 SheetBlockStyle *style;
194 valid = !gnucash_sheet_virt_cell_out_of_bounds (sheet,
199 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
201 valid = (virt_loc.phys_row_offset >= 0 &&
202 virt_loc.phys_row_offset < style->nrows &&
203 virt_loc.phys_col_offset >= 0 &&
204 virt_loc.phys_col_offset < style->ncols);
212 gnucash_sheet_cursor_set (GnucashSheet *sheet, VirtualLocation virt_loc)
214 g_return_if_fail (sheet != NULL);
215 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
217 g_return_if_fail (virt_loc.vcell_loc.virt_row >= 0 ||
218 virt_loc.vcell_loc.virt_row <= sheet->num_virt_rows);
219 g_return_if_fail (virt_loc.vcell_loc.virt_col >= 0 ||
220 virt_loc.vcell_loc.virt_col <= sheet->num_virt_cols);
222 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
223 sheet->cursor->x, sheet->cursor->y,
224 sheet->cursor->w, sheet->cursor->h);
226 gnucash_cursor_set (GNUCASH_CURSOR(sheet->cursor), virt_loc);
228 gtk_widget_queue_draw_area (GTK_WIDGET(sheet),
229 sheet->cursor->x, sheet->cursor->y,
230 sheet->cursor->w, sheet->cursor->h);
234 gnucash_sheet_cursor_set_from_table (GnucashSheet *sheet, gboolean do_scroll)
237 VirtualLocation v_loc;
239 g_return_if_fail (sheet != NULL);
240 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
242 table = sheet->table;
243 v_loc =
table->current_cursor_loc;
245 g_return_if_fail (gnucash_sheet_cell_valid (sheet, v_loc));
247 gnucash_sheet_cursor_set (sheet, v_loc);
250 gnucash_sheet_make_cell_visible (sheet, v_loc);
255 gnucash_sheet_set_popup (GnucashSheet *sheet, GtkWidget *popup, gpointer data)
258 g_object_ref (popup);
261 g_object_unref (sheet->popup);
263 sheet->popup = popup;
264 sheet->popup_data = data;
269 gnucash_sheet_hide_editing_cursor (GnucashSheet *sheet)
271 if (sheet->item_editor == NULL)
274 gtk_widget_hide (sheet->item_editor);
275 gnc_item_edit_hide_popup (GNC_ITEM_EDIT(sheet->item_editor));
279 gnucash_sheet_stop_editing (GnucashSheet *sheet)
284 if (sheet->insert_signal != 0)
285 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
286 sheet->insert_signal);
287 if (sheet->delete_signal != 0)
288 g_signal_handler_disconnect (G_OBJECT(sheet->entry),
289 sheet->delete_signal);
290 sheet->insert_signal = 0;
291 sheet->delete_signal = 0;
292 sheet->direct_update_cell = FALSE;
294 gnucash_sheet_hide_editing_cursor (sheet);
296 sheet->editing = FALSE;
297 sheet->input_cancelled = FALSE;
302 gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet)
304 VirtualLocation virt_loc;
306 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
308 gnucash_sheet_stop_editing (sheet);
310 if (!gnc_table_model_read_only (sheet->table->model))
311 gnc_table_leave_update (sheet->table, virt_loc);
313 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
317 gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
318 gint x, gint y, gint width, gint height)
320 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
322 rect->x = x + gnc_item_edit_get_margin (item_edit, left);
323 rect->y = y + gnc_item_edit_get_margin (item_edit, top);
324 rect->width = MAX (0, width - gnc_item_edit_get_margin (item_edit, left_right));
325 rect->height = height - gnc_item_edit_get_margin (item_edit, top_bottom);
329 gnucash_sheet_get_text_offset (GnucashSheet *sheet,
const VirtualLocation virt_loc,
330 gint rect_width, gint logical_width)
332 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
333 Table *
table = sheet->table;
337 switch (gnc_table_get_align (
table, virt_loc))
340 case CELL_ALIGN_LEFT:
341 x_offset = gnc_item_edit_get_padding_border (item_edit, left);
344 case CELL_ALIGN_RIGHT:
345 x_offset = rect_width - gnc_item_edit_get_padding_border (item_edit, right) - logical_width - 1;
348 case CELL_ALIGN_CENTER:
349 if (logical_width > rect_width)
352 x_offset = (rect_width - logical_width) / 2;
359 gnucash_sheet_activate_cursor_cell (GnucashSheet *sheet,
360 gboolean changed_cells)
362 Table *
table = sheet->table;
363 VirtualLocation virt_loc;
364 SheetBlockStyle *style;
365 GtkEditable *editable;
366 int cursor_pos, start_sel, end_sel;
367 gboolean allow_edits;
371 gnucash_sheet_deactivate_cursor_cell (sheet);
373 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
376 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
378 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
380 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
383 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
387 editable = GTK_EDITABLE(sheet->entry);
393 if (gnc_table_model_read_only (
table->model))
396 allow_edits = gnc_table_enter_update (
table, virt_loc,
398 &start_sel, &end_sel);
401 gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
404 gtk_entry_reset_im_context (GTK_ENTRY (sheet->entry));
405 gnucash_sheet_start_editing_at_cursor (sheet);
409 if (sheet->button != 1)
411 gnucash_sheet_set_position_and_selection (sheet, cursor_pos,
416 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
417 Table *
table = sheet->table;
418 const char *text = gnc_table_get_entry (
table, virt_loc);
420 PangoRectangle logical_rect;
422 gint x, y, width, height;
423 gint index = 0, trailing = 0;
430 gnc_item_edit_get_pixel_coords (item_edit, &x, &y,
432 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
435 pango_layout_set_width (layout, -1);
436 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
437 gnucash_sheet_set_text_bounds (sheet, &rect, x, y,
439 x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
442 pango_layout_xy_to_index (layout,
443 PANGO_SCALE * (sheet->button_x - rect.x - x_offset),
444 PANGO_SCALE * (height/2), &index, &trailing);
445 g_object_unref (layout);
447 gnucash_sheet_set_position (sheet, index + trailing);
449 sheet->direct_update_cell = gnucash_sheet_check_direct_update_cell (sheet, virt_loc);
453 if (sheet->sheet_has_focus)
454 gtk_widget_grab_focus (GTK_WIDGET(sheet));
459 gnucash_sheet_cursor_move (GnucashSheet *sheet, VirtualLocation virt_loc)
461 VirtualLocation old_virt_loc;
462 gboolean changed_cells;
465 table = sheet->table;
468 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &old_virt_loc);
471 gnucash_sheet_deactivate_cursor_cell (sheet);
475 gnc_table_wrap_verify_cursor_position (
table, virt_loc);
479 gnucash_sheet_deactivate_cursor_cell (sheet);
484 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
486 gnucash_sheet_cursor_set (sheet, virt_loc);
490 gnucash_sheet_make_cell_visible (sheet, virt_loc);
492 changed_cells = !virt_loc_equal (virt_loc, old_virt_loc);
497 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
498 gtk_widget_queue_draw (GTK_WIDGET(sheet));
502 gnucash_sheet_activate_cursor_cell (sheet, changed_cells);
505 (sheet->moved_cb)(sheet, sheet->moved_cb_data);
506 return changed_cells;
511 gnucash_sheet_y_pixel_to_block (GnucashSheet *sheet,
int y)
513 VirtualCellLocation vcell_loc = { 1, 0 };
516 vcell_loc.virt_row < sheet->num_virt_rows;
517 vcell_loc.virt_row++)
521 block = gnucash_sheet_get_block (sheet, vcell_loc);
528 return vcell_loc.virt_row;
533 gnucash_sheet_compute_visible_range (GnucashSheet *sheet)
535 VirtualCellLocation vcell_loc;
542 g_return_if_fail (sheet != NULL);
543 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
545 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
546 height = alloc.height;
548 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
549 cy = gtk_adjustment_get_value (adj);
551 top_block = gnucash_sheet_y_pixel_to_block (sheet, cy);
553 sheet->num_visible_blocks = 0;
554 sheet->num_visible_phys_rows = 0;
556 for (vcell_loc.virt_row = top_block, vcell_loc.virt_col = 0;
557 vcell_loc.virt_row < sheet->num_virt_rows;
558 vcell_loc.virt_row++)
562 block = gnucash_sheet_get_block (sheet, vcell_loc);
566 sheet->num_visible_blocks++;
567 sheet->num_visible_phys_rows += block->
style->nrows;
577 gnucash_sheet_show_row (GnucashSheet *sheet, gint virt_row)
579 VirtualCellLocation vcell_loc = { virt_row, 0 };
588 g_return_if_fail (virt_row >= 0);
589 g_return_if_fail (sheet != NULL);
590 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
592 vcell_loc.virt_row = MAX (vcell_loc.virt_row, 1);
593 vcell_loc.virt_row = MIN (vcell_loc.virt_row,
594 sheet->num_virt_rows - 1);
596 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
597 cx = gtk_adjustment_get_value (adj);
598 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
599 cy = gtk_adjustment_get_value (adj);
602 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
603 height = alloc.height;
605 block = gnucash_sheet_get_block (sheet, vcell_loc);
609 block_height = block->
style->dimensions->height;
611 if ((cy <= y) && (cy + height >= y + block_height))
613 gnucash_sheet_compute_visible_range (sheet);
618 y -= height - MIN (block_height, height);
620 if ((sheet->height - y) < height)
621 y = sheet->height - height;
627 gtk_adjustment_set_value (sheet->vadj, y);
629 gtk_adjustment_set_value (sheet->hadj, x);
631 gnucash_sheet_compute_visible_range (sheet);
632 gnucash_sheet_update_adjustments (sheet);
637 gnucash_sheet_make_cell_visible (GnucashSheet *sheet, VirtualLocation virt_loc)
639 g_return_if_fail (sheet != NULL);
640 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
642 if (!gnucash_sheet_cell_valid (sheet, virt_loc))
645 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
647 gnucash_sheet_update_adjustments (sheet);
652 gnucash_sheet_show_range (GnucashSheet *sheet,
653 VirtualCellLocation start_loc,
654 VirtualCellLocation end_loc)
665 g_return_if_fail (sheet != NULL);
666 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
668 start_loc.virt_row = MAX(start_loc.virt_row, 1);
669 start_loc.virt_row = MIN(start_loc.virt_row,
670 sheet->num_virt_rows - 1);
672 end_loc.virt_row = MAX(end_loc.virt_row, 1);
673 end_loc.virt_row = MIN(end_loc.virt_row,
674 sheet->num_virt_rows - 1);
676 adj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
677 cx = gtk_adjustment_get_value (adj);
678 adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
679 cy = gtk_adjustment_get_value (adj);
682 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
683 height = alloc.height;
685 start_block = gnucash_sheet_get_block (sheet, start_loc);
686 end_block = gnucash_sheet_get_block (sheet, end_loc);
687 if (!(start_block && end_block))
691 block_height = (end_block->
origin_y +
692 end_block->
style->dimensions->height) - y;
694 if ((cy <= y) && (cy + height >= y + block_height))
696 gnucash_sheet_compute_visible_range (sheet);
701 y -= height - MIN(block_height, height);
703 if ((sheet->height - y) < height)
704 y = sheet->height - height;
710 gtk_adjustment_set_value (sheet->vadj, y);
712 gtk_adjustment_set_value (sheet->hadj, x);
714 gnucash_sheet_compute_visible_range (sheet);
715 gnucash_sheet_update_adjustments (sheet);
720 gnucash_sheet_update_adjustments (GnucashSheet *sheet)
724 g_return_if_fail (sheet != NULL);
725 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
726 g_return_if_fail (sheet->vadj != NULL);
730 if (sheet->num_visible_blocks > 0)
731 gtk_adjustment_set_step_increment (vadj,
732 gtk_adjustment_get_page_size (vadj) / sheet->num_visible_blocks);
734 gtk_adjustment_set_step_increment (vadj, 0);
739 gnucash_sheet_vadjustment_value_changed (GtkAdjustment *adj,
742 gnucash_sheet_compute_visible_range (sheet);
747 gnucash_sheet_redraw_all (GnucashSheet *sheet)
749 g_return_if_fail (sheet != NULL);
750 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
752 gtk_widget_queue_draw (GTK_WIDGET(sheet));
754 g_signal_emit_by_name (sheet->reg,
"redraw_all");
758 gnucash_sheet_redraw_help (GnucashSheet *sheet)
760 g_return_if_fail (sheet != NULL);
761 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
763 g_signal_emit_by_name (sheet->reg,
"redraw_help");
767 gnucash_sheet_redraw_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
773 g_return_if_fail (sheet != NULL);
774 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
776 block = gnucash_sheet_get_block (sheet, vcell_loc);
777 if (!block || !block->
style)
783 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
784 h = block->
style->dimensions->height;
785 w = MIN(block->
style->dimensions->width, alloc.width);
787 gtk_widget_queue_draw_area (GTK_WIDGET(sheet), x, y, w + 1, h + 1);
791 gnucash_sheet_is_read_only (GnucashSheet *sheet)
793 g_return_val_if_fail (sheet != NULL, TRUE);
794 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), TRUE);
795 return gnc_table_model_read_only (sheet->table->model);
799 gnucash_sheet_set_has_focus (GnucashSheet *sheet, gboolean has_focus)
801 sheet->sheet_has_focus = has_focus;
805 gnucash_sheet_finalize (GObject *
object)
809 sheet = GNUCASH_SHEET(
object);
813 sheet->blocks = NULL;
815 gnucash_sheet_clear_styles (sheet);
817 g_hash_table_destroy (sheet->cursor_styles);
818 g_hash_table_destroy (sheet->dimensions_hash_table);
820 g_object_unref (sheet->cursor);
822 if (G_OBJECT_CLASS(sheet_parent_class)->finalize)
823 (*G_OBJECT_CLASS(sheet_parent_class)->finalize)(
object);
827 static GnucashSheet *
828 gnucash_sheet_create (Table *
table)
834 sheet = g_object_new (GNUCASH_TYPE_SHEET, NULL);
835 sheet->table =
table;
837 sheet->vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE(sheet));
838 sheet->hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE(sheet));
840 g_signal_connect (G_OBJECT(sheet->vadj),
"value_changed",
841 G_CALLBACK(gnucash_sheet_vadjustment_value_changed), sheet);
842 g_signal_connect (G_OBJECT(sheet),
"draw",
843 G_CALLBACK(gnucash_sheet_draw_cb), sheet);
850 gnucash_sheet_get_preferred_width (G_GNUC_UNUSED GtkWidget *widget,
854 *minimal_width = *natural_width = DEFAULT_SHEET_WIDTH;
860 gnucash_sheet_get_preferred_height (G_GNUC_UNUSED GtkWidget *widget,
864 GnucashSheet *sheet = GNUCASH_SHEET(widget);
865 SheetBlockStyle *style;
869 *minimal_width = *natural_width = DEFAULT_SHEET_HEIGHT;
874 style = gnucash_sheet_get_style_from_cursor (sheet,
CURSOR_HEADER);
878 cd = gnucash_style_get_cell_dimensions (style, 0, 0);
882 row_height = cd->pixel_height;
884 *minimal_width = *natural_width = row_height * DEFAULT_SHEET_INITIAL_ROWS;
888 gnucash_sheet_modify_current_cell (GnucashSheet *sheet,
const gchar *new_text)
890 GtkEditable *editable;
891 Table *
table = sheet->table;
892 VirtualLocation virt_loc;
893 int new_text_len = 0;
895 int cursor_position, start_sel, end_sel;
897 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
899 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
902 if (gnc_table_model_read_only (
table->model))
905 editable = GTK_EDITABLE(sheet->entry);
907 cursor_position = gtk_editable_get_position (editable);
908 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
911 new_text_len = strlen (new_text);
913 retval = gnc_table_modify_update (
table, virt_loc,
914 new_text, new_text_len,
915 new_text, new_text_len,
917 &start_sel, &end_sel,
923 DEBUG(
"%s", retval ? retval :
"nothing");
924 gnucash_sheet_set_entry_value (sheet, retval);
925 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
933 GtkEditable *editable;
940 gnucash_sheet_direct_event (GnucashSheet *sheet, GdkEvent *event)
942 GtkEditable *editable;
943 Table *
table = sheet->table;
944 VirtualLocation virt_loc;
946 char *new_text = NULL;
947 int cursor_position, start_sel, end_sel;
948 int new_position, new_start, new_end;
950 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
952 if (!gnc_table_virtual_loc_valid (
table, virt_loc, TRUE))
955 if (gnc_table_model_read_only (
table->model))
958 editable = GTK_EDITABLE(sheet->entry);
960 cursor_position = gtk_editable_get_position (editable);
961 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
963 new_position = cursor_position;
964 new_start = start_sel;
966 result = gnc_table_direct_update (
table, virt_loc,
969 &new_start, &new_end,
973 DEBUG(
"%s", new_text ? new_text :
"nothing");
974 if (new_text != NULL)
975 gnucash_sheet_set_entry_value (sheet, new_text);
976 gnucash_sheet_set_position_and_selection (sheet, new_position,
983 normalize_selection_bounds (
int *pos,
int *bound,
int length)
985 *bound = *bound < 0 ? length : *bound;
986 *pos = *pos < 0 ? length : *pos;
997 insert_text (
const char* old_text,
const char* new_text,
int pos,
int bound)
999 int old_len = g_utf8_strlen (old_text, -1);
1000 char* begin = g_utf8_substring (old_text, 0, pos);
1001 char* end = g_utf8_substring (old_text, bound, old_len);
1002 char *retval = g_strdup_printf (
"%s%s%s", begin, new_text, end);
1009 make_new_text (GnucashSheet *sheet,
const char* new_text,
int *position)
1011 GtkEditable* editable = (GTK_EDITABLE(sheet->entry));
1013 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1014 int old_length = g_utf8_strlen (old_text, -1);
1015 int insert_length = g_utf8_strlen (new_text, -1);
1017 if (!old_text || old_length == 0)
1019 *position = insert_length;
1020 return g_strdup (new_text);
1023 gtk_editable_get_selection_bounds (editable, &bound, &pos);
1024 normalize_selection_bounds (&pos, &bound, old_length);
1026 if (*position != pos)
1027 bound = pos = *position;
1029 if (pos == 0 && bound == old_length)
1031 *position = insert_length;
1032 return g_strdup (new_text);
1039 *position = insert_length;
1040 return g_strdup_printf (
"%s%s", new_text, old_text);
1042 else if (pos == old_length)
1044 *position = old_length + insert_length;
1045 return g_strdup_printf (
"%s%s", old_text, new_text);
1049 *position = pos + insert_length;
1050 return insert_text (old_text, new_text, pos, bound);
1054 gnucash_sheet_insert_cb (GtkEditable *editable,
1055 const gchar *insert_text,
1056 const gint insert_text_len,
1058 GnucashSheet *sheet)
1061 Table *
table = sheet->table;
1062 VirtualLocation virt_loc;
1063 char *new_text = NULL;
1064 glong new_text_len = 0;
1066 int start_sel = 0, end_sel = 0;
1067 int old_position = *position;
1068 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1070 g_assert (GTK_WIDGET(editable) == sheet->entry);
1071 if (sheet->input_cancelled)
1073 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1078 if (insert_text_len <= 0)
1081 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1083 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1086 if (gnc_table_model_read_only (
table->model))
1089 new_text = make_new_text (sheet, insert_text, position);
1090 new_text_len = strlen (new_text);
1093 retval = gnc_table_modify_update (
table, virt_loc,
1094 insert_text, insert_text_len,
1095 new_text, new_text_len,
1096 position, &start_sel, &end_sel,
1097 &sheet->input_cancelled);
1105 DEBUG(
"%s, got %s", new_text, retval);
1106 gnucash_sheet_set_position_and_selection (sheet, *position, start_sel,
1109 if ((strcmp (retval, new_text) != 0) || (*position != old_position))
1111 gnucash_sheet_set_entry_value (sheet, retval);
1112 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1116 else if (retval == NULL)
1121 gtk_entry_reset_im_context (GTK_ENTRY(sheet->entry));
1123 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
1129 delete_text (GnucashSheet *sheet,
int pos,
int bound)
1131 const char* old_text = gtk_entry_get_text (GTK_ENTRY(sheet->entry));
1132 int old_length = g_utf8_strlen (old_text, -1);
1134 char *retval = NULL;
1136 normalize_selection_bounds (&pos, &bound, old_length);
1138 return g_strdup (old_text);
1140 if (pos == 0 && bound == old_length)
1141 return g_strdup (
"");
1143 if (bound == old_length)
1144 return g_utf8_substring (old_text, 0, pos);
1147 return g_utf8_substring (old_text, bound, old_length);
1149 begin = g_utf8_substring (old_text, 0, pos);
1150 end = g_utf8_substring (old_text, bound, old_length);
1151 retval = g_strdup_printf (
"%s%s", begin, end);
1158 gnucash_sheet_delete_cb (GtkWidget *widget,
1159 const gint start_pos,
1161 GnucashSheet *sheet)
1163 GtkEditable *editable;
1164 Table *
table = sheet->table;
1165 VirtualLocation virt_loc;
1166 char *new_text = NULL;
1169 int cursor_position = start_pos;
1170 int start_sel, end_sel;
1172 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1174 if (!gnc_table_virtual_loc_valid (
table, virt_loc, FALSE))
1177 if (gnc_table_model_read_only (
table->model))
1180 new_text = delete_text (sheet, start_pos, end_pos);
1181 new_text_len = strlen (new_text);
1182 editable = GTK_EDITABLE(sheet->entry);
1183 gtk_editable_get_selection_bounds (editable, &start_sel, &end_sel);
1184 retval = gnc_table_modify_update (
table, virt_loc,
1186 new_text, new_text_len,
1188 &start_sel, &end_sel,
1189 &sheet->input_cancelled);
1192 gnucash_sheet_set_entry_value (sheet, retval);
1194 g_signal_stop_emission_by_name (G_OBJECT(sheet->entry),
"delete_text");
1196 DEBUG(
"%s", retval ? retval :
"nothing");
1197 gnucash_sheet_set_position_and_selection (sheet, cursor_position,
1198 start_sel, end_sel);
1202 gnucash_sheet_draw_cb (GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer data)
1204 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1205 GtkStyleContext *context = gtk_widget_get_style_context (widget);
1206 GtkAllocation alloc;
1208 gtk_widget_get_allocation (widget, &alloc);
1210 gtk_style_context_save (context);
1211 gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
1212 gtk_render_background (context, cr, 0, 0, alloc.width, alloc.height);
1213 gtk_style_context_restore (context);
1215 gnucash_sheet_draw_internal (sheet, cr, &alloc);
1216 gnucash_sheet_draw_cursor (sheet->cursor, cr);
1223 gnucash_sheet_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
1225 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1227 ENTER(
"widget=%p, allocation=%p", widget, allocation);
1229 if (GTK_WIDGET_CLASS(sheet_parent_class)->size_allocate)
1230 (*GTK_WIDGET_CLASS(sheet_parent_class)->size_allocate)
1231 (widget, allocation);
1233 if (allocation->height == sheet->window_height &&
1234 allocation->width == sheet->window_width)
1236 LEAVE(
"size unchanged");
1240 if (allocation->width != sheet->window_width)
1242 gnucash_sheet_styles_set_dimensions (sheet, allocation->width);
1243 gnucash_sheet_recompute_block_offsets (sheet);
1246 sheet->window_height = allocation->height;
1247 sheet->window_width = allocation->width;
1249 gnucash_cursor_configure (GNUCASH_CURSOR(sheet->cursor));
1250 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
1251 gnucash_sheet_set_scroll_region (sheet);
1253 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1254 gnucash_sheet_update_adjustments (sheet);
1258 VirtualLocation virt_loc;
1260 virt_loc = sheet->table->current_cursor_loc;
1262 if (gnucash_sheet_cell_valid (sheet, virt_loc))
1263 gnucash_sheet_show_row (sheet, virt_loc.vcell_loc.virt_row);
1265 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
1270 gnucash_sheet_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
1272 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1274 if (GTK_WIDGET_CLASS(sheet_parent_class)->focus_in_event)
1275 (*GTK_WIDGET_CLASS(sheet_parent_class)->focus_in_event)
1278 gnc_item_edit_focus_in (GNC_ITEM_EDIT(sheet->item_editor));
1284 gnucash_sheet_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
1286 GnucashSheet *sheet = GNUCASH_SHEET(widget);
1288 if (GTK_WIDGET_CLASS(sheet_parent_class)->focus_out_event)
1289 (*GTK_WIDGET_CLASS(sheet_parent_class)->focus_out_event)
1292 gnc_item_edit_focus_out (GNC_ITEM_EDIT(sheet->item_editor));
1297 gnucash_sheet_check_direct_update_cell (GnucashSheet *sheet,
1298 const VirtualLocation virt_loc)
1300 const gchar *type_name;
1302 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
1304 if ( (g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
1305 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0)
1306 || (g_strcmp0 (type_name, NUM_CELL_TYPE_NAME) == 0)
1307 || (g_strcmp0 (type_name, PRICE_CELL_TYPE_NAME) == 0)
1308 || (g_strcmp0 (type_name, FORMULA_CELL_TYPE_NAME) == 0))
return TRUE;
1314 gnucash_sheet_start_editing_at_cursor (GnucashSheet *sheet)
1317 VirtualLocation virt_loc;
1319 g_return_if_fail (sheet != NULL);
1320 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1322 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
1324 text = gnc_table_get_entry (sheet->table, virt_loc);
1326 gnc_item_edit_configure (GNC_ITEM_EDIT(sheet->item_editor));
1327 gtk_widget_show (GTK_WIDGET(sheet->item_editor));
1329 gtk_entry_set_text (GTK_ENTRY(sheet->entry), text);
1331 sheet->editing = TRUE;
1334 sheet->insert_signal =
1335 g_signal_connect (G_OBJECT(sheet->entry),
"insert_text",
1336 G_CALLBACK(gnucash_sheet_insert_cb), sheet);
1337 sheet->delete_signal =
1338 g_signal_connect (G_OBJECT(sheet->entry),
"delete_text",
1339 G_CALLBACK(gnucash_sheet_delete_cb), sheet);
1343 gnucash_sheet_button_release_event (GtkWidget *widget, GdkEventButton *event)
1345 GnucashSheet *sheet;
1347 g_return_val_if_fail (widget != NULL, TRUE);
1348 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1349 g_return_val_if_fail (event != NULL, TRUE);
1351 sheet = GNUCASH_SHEET(widget);
1353 if (sheet->button != event->button)
1358 if (event->button != 1)
1361 gtk_grab_remove (widget);
1362 sheet->grabbed = FALSE;
1368 clamp_scrollable_value (
float value, GtkAdjustment* adj)
1370 float lower = gtk_adjustment_get_lower (adj);
1371 float upper = gtk_adjustment_get_upper (adj);
1372 float size = gtk_adjustment_get_page_size (adj);
1373 return CLAMP(value, lower, upper - size);
1377 gnucash_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1379 GnucashSheet *sheet;
1380 GtkAdjustment *vadj;
1381 gfloat h_value, v_value;
1384 g_return_val_if_fail (widget != NULL, TRUE);
1385 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1386 g_return_val_if_fail (event != NULL, TRUE);
1388 sheet = GNUCASH_SHEET(widget);
1390 v_value = gtk_adjustment_get_value (vadj);
1392 switch (event->direction)
1395 v_value -= gtk_adjustment_get_step_increment (vadj);
1397 case GDK_SCROLL_DOWN:
1398 v_value += gtk_adjustment_get_step_increment (vadj);
1405 case GDK_SCROLL_SMOOTH:
1406 h_value = gtk_adjustment_get_value (sheet->hadj);
1407 h_value +=
event->delta_x;
1408 h_value = clamp_scrollable_value (h_value, sheet->hadj);
1409 gtk_adjustment_set_value (sheet->hadj, h_value);
1410 #if defined MAC_INTEGRATION 1411 v_value +=
event->delta_y;
1413 direction =
event->delta_y > 0 ? 1 :
event->delta_y < 0 ? -1 : 0;
1414 v_value += gtk_adjustment_get_step_increment (vadj) * direction;
1420 v_value = clamp_scrollable_value (v_value, vadj);
1421 gtk_adjustment_set_value (vadj, v_value);
1423 if (event->delta_y == 0)
1428 gtk_widget_hide (GTK_WIDGET(sheet->vscrollbar));
1429 gtk_widget_show (GTK_WIDGET(sheet->vscrollbar));
1435 gnucash_sheet_check_grab (GnucashSheet *sheet)
1437 GdkModifierType mods;
1442 if (!sheet->grabbed)
1445 window = gtk_widget_get_window (GTK_WIDGET(sheet));
1447 seat = gdk_display_get_default_seat (gdk_window_get_display (window));
1448 device = gdk_seat_get_pointer (seat);
1450 gdk_device_get_state (device, window, 0, &mods);
1452 if (!(mods & GDK_BUTTON1_MASK))
1454 gtk_grab_remove (GTK_WIDGET(sheet));
1455 sheet->grabbed = FALSE;
1460 gnucash_sheet_button_press_event (GtkWidget *widget, GdkEventButton *event)
1462 GnucashSheet *sheet;
1464 VirtualLocation cur_virt_loc;
1465 VirtualLocation new_virt_loc;
1467 gboolean abort_move;
1471 g_return_val_if_fail (widget != NULL, TRUE);
1472 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1473 g_return_val_if_fail (event != NULL, TRUE);
1475 sheet = GNUCASH_SHEET(widget);
1476 table = sheet->table;
1478 if (sheet->button && (sheet->button != event->button))
1481 sheet->button =
event->button;
1482 if (sheet->button == 3)
1485 if (!gtk_widget_has_focus (widget))
1486 gtk_widget_grab_focus (widget);
1491 switch (event->button)
1497 if (event->type != GDK_BUTTON_PRESS)
1499 gnc_item_edit_paste_clipboard (GNC_ITEM_EDIT(sheet->item_editor));
1502 do_popup = (sheet->popup != NULL);
1508 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1510 sheet->button_x = -1;
1511 sheet->button_y = -1;
1513 if (!gnucash_sheet_find_loc_by_pixel (sheet, event->x, event->y,
1517 sheet->button_x =
event->x;
1518 sheet->button_y =
event->y;
1524 if (event->type != GDK_BUTTON_PRESS)
1529 gtk_grab_add (widget);
1530 sheet->grabbed = TRUE;
1533 if (virt_loc_equal (new_virt_loc, cur_virt_loc) &&
1534 sheet->editing && do_popup)
1536 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1541 abort_move = gnc_table_traverse_update (
table,
1543 GNC_TABLE_TRAVERSE_POINTER,
1547 gnucash_sheet_check_grab (sheet);
1552 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1555 if (g_strcmp0 (gnc_table_get_cell_name (
table, new_virt_loc), DOCLINK_CELL) == 0)
1557 if (sheet->open_doclink_cb)
1558 (sheet->open_doclink_cb)(sheet->open_doclink_cb_data, NULL);
1562 gnucash_sheet_check_grab (sheet);
1565 gtk_menu_popup_at_pointer (GTK_MENU(sheet->popup), (GdkEvent *) event);
1567 return button_1 || do_popup;
1571 gnucash_sheet_refresh_from_prefs (GnucashSheet *sheet)
1573 GtkStyleContext *stylectxt;
1575 GList *classes = NULL;
1577 g_return_if_fail (sheet != NULL);
1578 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1581 GNC_PREF_USE_GNUCASH_COLOR_THEME);
1583 GNC_PREF_DRAW_HOR_LINES);
1585 GNC_PREF_DRAW_VERT_LINES);
1587 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1589 stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
1592 classes = gtk_style_context_list_classes (stylectxt);
1594 for (GList *l = classes; l; l = l->next)
1596 if (g_str_has_prefix (l->data,
"gnc-class-"))
1597 gtk_style_context_remove_class (stylectxt, l->data);
1599 g_list_free (classes);
1601 gtk_style_context_remove_class (stylectxt, GTK_STYLE_CLASS_VIEW);
1609 gnucash_sheet_clipboard_event (GnucashSheet *sheet, GdkEventKey *event)
1612 gboolean handled = FALSE;
1614 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1616 switch (event->keyval)
1620 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1622 gnc_item_edit_copy_clipboard (item_edit);
1628 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1630 gnc_item_edit_cut_clipboard (item_edit);
1636 if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1638 gnc_item_edit_paste_clipboard (item_edit);
1642 case GDK_KEY_Insert:
1643 if (event->state & GDK_SHIFT_MASK)
1645 gnc_item_edit_paste_clipboard (item_edit);
1648 else if (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR)
1650 gnc_item_edit_copy_clipboard (item_edit);
1659 gnucash_sheet_need_horizontal_scroll (GnucashSheet *sheet,
1660 VirtualLocation *new_virt_loc)
1663 gint cell_width = 0;
1666 if (sheet->window_width == sheet->width)
1670 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
1673 offset = gnc_header_get_cell_offset (GNC_HEADER(sheet->header_item),
1674 new_virt_loc->phys_col_offset, &cell_width);
1676 if (((offset + cell_width) > sheet->window_width) || (offset < hscroll_val))
1677 gtk_adjustment_set_value (sheet->hadj, offset);
1681 process_motion_keys (GnucashSheet *sheet, GdkEventKey *event, gboolean *pass_on,
1682 gncTableTraversalDir *direction,
1683 VirtualLocation* new_virt_loc)
1686 VirtualLocation cur_virt_loc = *new_virt_loc;
1688 switch (event->keyval)
1690 case GDK_KEY_Return:
1691 case GDK_KEY_KP_Enter:
1692 g_signal_emit_by_name (sheet->reg,
"activate_cursor");
1694 sheet->pos = sheet->bound;
1698 case GDK_KEY_ISO_Left_Tab:
1699 if (event->state & GDK_SHIFT_MASK)
1701 *direction = GNC_TABLE_TRAVERSE_LEFT;
1702 gnc_table_move_tab (sheet->table, new_virt_loc, FALSE);
1706 *direction = GNC_TABLE_TRAVERSE_RIGHT;
1707 gnc_table_move_tab (sheet->table, new_virt_loc, TRUE);
1710 case GDK_KEY_KP_Page_Up:
1711 case GDK_KEY_Page_Up:
1712 *direction = GNC_TABLE_TRAVERSE_UP;
1713 new_virt_loc->phys_col_offset = 0;
1714 if (event->state & GDK_SHIFT_MASK)
1715 new_virt_loc->vcell_loc.virt_row = 1;
1718 distance = sheet->num_visible_phys_rows - 1;
1720 (sheet->table, new_virt_loc, -distance);
1723 case GDK_KEY_KP_Page_Down:
1724 case GDK_KEY_Page_Down:
1725 *direction = GNC_TABLE_TRAVERSE_DOWN;
1726 new_virt_loc->phys_col_offset = 0;
1727 if (event->state & GDK_SHIFT_MASK)
1728 new_virt_loc->vcell_loc.virt_row =
1729 sheet->num_virt_rows - 1;
1732 distance = sheet->num_visible_phys_rows - 1;
1734 (sheet->table, new_virt_loc, distance);
1739 *direction = GNC_TABLE_TRAVERSE_UP;
1743 case GDK_KEY_KP_Down:
1746 if (event->keyval == GDK_KEY_Menu ||
1747 (event->state & GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR))
1749 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
1751 if (gnc_table_confirm_change (sheet->table, cur_virt_loc))
1752 gnc_item_edit_show_popup (item_edit);
1755 sheet->pos = sheet->bound;
1759 *direction = GNC_TABLE_TRAVERSE_DOWN;
1763 case GDK_KEY_KP_Right:
1765 case GDK_KEY_KP_Left:
1770 sheet->pos = sheet->bound;
1774 if (gnucash_sheet_clipboard_event (sheet, event))
1777 sheet->pos = sheet->bound;
1784 gnucash_sheet_need_horizontal_scroll (sheet, new_virt_loc);
1790 pass_to_entry_handler (GnucashSheet *sheet, GdkEventKey *event)
1792 gboolean result = FALSE;
1793 GtkEditable *editable = GTK_EDITABLE(sheet->entry);
1796 if (gtk_widget_get_realized (GTK_WIDGET(editable)))
1798 result = gtk_widget_event (GTK_WIDGET(editable), (GdkEvent*)event);
1799 gnucash_sheet_set_selection_from_entry (sheet);
1805 gnucash_sheet_key_press_event_internal (GtkWidget *widget, GdkEventKey *event)
1808 GnucashSheet *sheet;
1809 gboolean pass_on = FALSE;
1810 gboolean abort_move;
1811 VirtualLocation cur_virt_loc;
1812 VirtualLocation new_virt_loc;
1813 gncTableTraversalDir direction = 0;
1815 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
1817 g_return_val_if_fail (widget != NULL, TRUE);
1818 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1819 g_return_val_if_fail (event != NULL, TRUE);
1821 sheet = GNUCASH_SHEET(widget);
1822 table = sheet->table;
1824 if (event->is_modifier)
1829 gnucash_sheet_set_selection_from_entry (sheet);
1831 if (gnucash_sheet_direct_event (sheet, (GdkEvent *) event))
1834 if (gtk_entry_im_context_filter_keypress (GTK_ENTRY(sheet->entry), event))
1836 #if !(defined(__APPLE__) || defined(__WIN32__)) 1846 gnucash_sheet_set_entry_selection (sheet);
1850 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1851 new_virt_loc = cur_virt_loc;
1856 if (event->state & modifiers & (GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK))
1858 else if (process_motion_keys (sheet, event, &pass_on,
1859 &direction, &new_virt_loc))
1865 return pass_to_entry_handler (sheet, event);
1868 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1869 direction, &new_virt_loc);
1875 if (!gtk_widget_has_focus (GTK_WIDGET(sheet)))
1876 gtk_widget_grab_focus (GTK_WIDGET(sheet));
1881 sheet->pos = sheet->bound;
1882 gnucash_sheet_cursor_move (sheet, new_virt_loc);
1889 gnucash_sheet_key_press_event (GtkWidget *widget, GdkEventKey *event)
1891 GnucashSheet *sheet;
1892 GtkEditable *editable = NULL;
1894 g_return_val_if_fail (widget != NULL, TRUE);
1895 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1896 g_return_val_if_fail (event != NULL, TRUE);
1898 sheet = GNUCASH_SHEET(widget);
1899 editable = GTK_EDITABLE(sheet->entry);
1907 if (event->hardware_keycode == VK_DECIMAL)
1908 event->keyval = GDK_KEY_KP_Decimal;
1910 sheet->shift_state =
event->state & GDK_SHIFT_MASK;
1911 sheet->keyval_state =
1912 (
event->keyval == GDK_KEY_KP_Decimal) ? GDK_KEY_KP_Decimal : 0;
1914 return gnucash_sheet_key_press_event_internal (widget, event);
1918 gnucash_sheet_key_release_event (GtkWidget *widget, GdkEventKey *event)
1920 GnucashSheet *sheet;
1922 g_return_val_if_fail (widget != NULL, TRUE);
1923 g_return_val_if_fail (GNUCASH_IS_SHEET(widget), TRUE);
1924 g_return_val_if_fail (event != NULL, TRUE);
1931 gnucash_sheet_goto_virt_loc (GnucashSheet *sheet, VirtualLocation virt_loc)
1934 gboolean abort_move;
1935 VirtualLocation cur_virt_loc;
1937 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1939 table = sheet->table;
1941 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &cur_virt_loc);
1945 abort_move = gnc_table_traverse_update (
table, cur_virt_loc,
1946 GNC_TABLE_TRAVERSE_POINTER,
1953 gnucash_sheet_need_horizontal_scroll (sheet, &virt_loc);
1955 gnucash_sheet_cursor_move (sheet, virt_loc);
1959 gnucash_sheet_get_block (GnucashSheet *sheet, VirtualCellLocation vcell_loc)
1961 g_return_val_if_fail (sheet != NULL, NULL);
1962 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1966 vcell_loc.virt_col);
1969 GncItemEdit *gnucash_sheet_get_item_edit (GnucashSheet *sheet)
1971 g_return_val_if_fail (sheet != NULL, NULL);
1972 g_return_val_if_fail (GNUCASH_IS_SHEET(sheet), NULL);
1974 if (sheet->item_editor == NULL)
1977 return GNC_ITEM_EDIT(sheet->item_editor);
1981 void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window)
1983 g_return_if_fail (sheet != NULL);
1984 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
1987 g_return_if_fail (GTK_IS_WIDGET(window));
1989 sheet->window = window;
1996 gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
1997 VirtualCellLocation vcell_loc)
2001 SheetBlockStyle *style;
2004 block = gnucash_sheet_get_block (sheet, vcell_loc);
2005 style = gnucash_sheet_get_style_from_table (sheet, vcell_loc);
2010 table = sheet->table;
2016 gnucash_sheet_style_unref (sheet, block->
style);
2017 block->
style = NULL;
2022 if (block->
style == NULL)
2024 block->
style = style;
2025 gnucash_sheet_style_ref (sheet, block->
style);
2033 gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
2040 SheetBlockStyle *style;
2041 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet),
"");
2042 GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
2043 const gchar *type_name;
2045 g_return_val_if_fail (virt_col >= 0, 0);
2046 g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
2047 g_return_val_if_fail (cell_col >= 0, 0);
2049 for (virt_row = 0; virt_row < sheet->num_virt_rows ; virt_row++)
2051 VirtualCellLocation vcell_loc = { virt_row, virt_col };
2053 block = gnucash_sheet_get_block (sheet, vcell_loc);
2057 style = block->
style;
2062 if (cell_col < style->ncols)
2064 for (cell_row = 0; cell_row < style->nrows; cell_row++)
2066 VirtualLocation virt_loc;
2070 virt_loc.vcell_loc = sheet->table->current_cursor_loc.vcell_loc;
2072 virt_loc.vcell_loc = vcell_loc;
2074 virt_loc.phys_row_offset = cell_row;
2075 virt_loc.phys_col_offset = cell_col;
2079 text = gnc_table_get_label
2080 (sheet->table, virt_loc);
2084 text = gnc_table_get_entry
2085 (sheet->table, virt_loc);
2088 pango_layout_set_text (layout, text, strlen (text));
2089 pango_layout_get_pixel_size (layout, &width, NULL);
2091 width += (gnc_item_edit_get_margin (item_edit, left_right) +
2092 gnc_item_edit_get_padding_border (item_edit, left_right));
2096 type_name = gnc_table_get_cell_type_name (sheet->table, virt_loc);
2097 if ((g_strcmp0 (type_name, DATE_CELL_TYPE_NAME) == 0)
2098 || (g_strcmp0 (type_name, COMBO_CELL_TYPE_NAME) == 0))
2100 width += gnc_item_edit_get_button_width (item_edit) + 2;
2102 max = MAX(max, width);
2107 g_object_unref (layout);
2113 gnucash_sheet_set_scroll_region (GnucashSheet *sheet)
2116 GtkAllocation alloc;
2122 if (!sheet->header_item || !GNC_HEADER(sheet->header_item)->style)
2125 gtk_layout_get_size (GTK_LAYOUT(sheet), &old_w, &old_h);
2127 gtk_widget_get_allocation (GTK_WIDGET(sheet), &alloc);
2128 new_h = MAX(sheet->height, alloc.height);
2129 new_w = MAX(sheet->width, alloc.width);
2131 if (new_w != old_w || new_h != old_h)
2132 gtk_layout_set_size (GTK_LAYOUT(sheet), new_w, new_h);
2136 gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
2139 GnucashSheet *sheet = GNUCASH_SHEET(user_data);
2146 gnucash_sheet_style_unref (sheet, block->
style);
2152 gnucash_sheet_block_construct (gpointer _block, gpointer user_data)
2156 block->
style = NULL;
2161 gnucash_sheet_resize (GnucashSheet *sheet)
2163 g_return_if_fail (sheet != NULL);
2164 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2166 if (sheet->table->num_virt_cols > 1)
2167 g_warning (
"num_virt_cols > 1");
2169 sheet->num_virt_cols = 1;
2173 sheet->num_virt_rows = sheet->table->num_virt_rows;
2177 gnucash_sheet_recompute_block_offsets (GnucashSheet *sheet)
2185 g_return_if_fail (sheet != NULL);
2186 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2187 g_return_if_fail (sheet->table != NULL);
2189 table = sheet->table;
2193 for (i = 0; i <
table->num_virt_rows; i++)
2197 for (j = 0; j <
table->num_virt_cols; j++)
2199 VirtualCellLocation vcell_loc = { i, j };
2201 block = gnucash_sheet_get_block (sheet, vcell_loc);
2206 block->origin_x = width;
2210 width += block->
style->dimensions->width;
2213 if (i > 0 && block && block->
visible)
2214 height += block->
style->dimensions->height;
2216 sheet->height = height;
2220 gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
2223 gint num_header_phys_rows;
2226 g_return_if_fail (sheet != NULL);
2227 g_return_if_fail (GNUCASH_IS_SHEET(sheet));
2228 g_return_if_fail (sheet->table != NULL);
2230 table = sheet->table;
2232 gnucash_sheet_stop_editing (sheet);
2234 gnucash_sheet_resize (sheet);
2236 num_header_phys_rows = 0;
2239 for (i = 0; i <
table->num_virt_rows; i++)
2240 for (j = 0; j <
table->num_virt_cols; j++)
2242 VirtualCellLocation vcell_loc = { i, j };
2245 gnucash_sheet_block_set_from_table (sheet, vcell_loc);
2249 num_header_phys_rows =
2250 MAX (num_header_phys_rows,
2251 vcell->cellblock->num_rows);
2254 gnc_header_set_header_rows (GNC_HEADER(sheet->header_item),
2255 num_header_phys_rows);
2256 gnc_header_reconfigure (GNC_HEADER(sheet->header_item));
2258 gnucash_sheet_recompute_block_offsets (sheet);
2260 gnucash_sheet_set_scroll_region (sheet);
2264 VirtualLocation virt_loc;
2266 virt_loc =
table->current_cursor_loc;
2268 if (gnucash_sheet_cell_valid (sheet, virt_loc))
2269 gnucash_sheet_show_row (sheet,
2270 virt_loc.vcell_loc.virt_row);
2273 gnucash_sheet_cursor_set_from_table (sheet, do_scroll);
2274 gnucash_sheet_activate_cursor_cell (sheet, TRUE);
2284 gchar *full_class, *style_class = NULL;
2286 if (field_type >= COLOR_NEGATIVE)
2289 gtk_style_context_add_class (stylectxt,
"gnc-class-negative-numbers");
2290 field_type -= COLOR_NEGATIVE;
2294 if (sheet->use_gnc_color_theme)
2295 gtk_style_context_add_class (stylectxt,
"gnc-class-register-foreground");
2301 case COLOR_UNDEFINED:
2302 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
2306 style_class =
"header";
2310 style_class =
"primary";
2313 case COLOR_PRIMARY_ACTIVE:
2314 case COLOR_SECONDARY_ACTIVE:
2315 case COLOR_SPLIT_ACTIVE:
2316 gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
2317 style_class =
"cursor";
2320 case COLOR_SECONDARY:
2321 style_class =
"secondary";
2325 style_class =
"split";
2329 if (sheet->use_gnc_color_theme)
2330 full_class = g_strconcat (
"gnc-class-register-", style_class, NULL);
2333 gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_VIEW);
2334 full_class = g_strconcat (
"gnc-class-user-register-", style_class, NULL);
2337 gtk_style_context_add_class (stylectxt, full_class);
2339 g_free (full_class);
2345 gnucash_sheet_class_init (GnucashSheetClass *klass)
2347 GObjectClass *gobject_class;
2348 GtkWidgetClass *widget_class;
2350 gobject_class = G_OBJECT_CLASS(klass);
2351 widget_class = GTK_WIDGET_CLASS(klass);
2353 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(klass),
"gnc-id-sheet");
2355 sheet_parent_class = g_type_class_peek_parent (klass);
2358 gobject_class->finalize = gnucash_sheet_finalize;
2360 widget_class->get_preferred_width = gnucash_sheet_get_preferred_width;
2361 widget_class->get_preferred_height = gnucash_sheet_get_preferred_height;
2362 widget_class->size_allocate = gnucash_sheet_size_allocate;
2364 widget_class->focus_in_event = gnucash_sheet_focus_in_event;
2365 widget_class->focus_out_event = gnucash_sheet_focus_out_event;
2367 widget_class->key_press_event = gnucash_sheet_key_press_event;
2368 widget_class->key_release_event = gnucash_sheet_key_release_event;
2369 widget_class->button_press_event = gnucash_sheet_button_press_event;
2370 widget_class->button_release_event = gnucash_sheet_button_release_event;
2371 widget_class->scroll_event = gnucash_scroll_event;
2376 gnucash_sheet_init (GnucashSheet *sheet)
2378 gtk_widget_set_can_focus (GTK_WIDGET(sheet), TRUE);
2379 gtk_widget_set_can_default (GTK_WIDGET(sheet), TRUE);
2381 sheet->num_visible_blocks = 1;
2382 sheet->num_visible_phys_rows = 1;
2384 sheet->input_cancelled = FALSE;
2386 sheet->popup = NULL;
2387 sheet->num_virt_rows = 0;
2388 sheet->num_virt_cols = 0;
2389 sheet->item_editor = NULL;
2390 sheet->entry = NULL;
2391 sheet->editing = FALSE;
2393 sheet->grabbed = FALSE;
2394 sheet->window_width = -1;
2395 sheet->window_height = -1;
2399 sheet->cursor_styles = g_hash_table_new (g_str_hash, g_str_equal);
2402 gnucash_sheet_block_construct,
2403 gnucash_sheet_block_destroy, sheet);
2405 gtk_widget_add_events (GTK_WIDGET(sheet),
2407 | GDK_BUTTON_PRESS_MASK
2408 | GDK_BUTTON_RELEASE_MASK
2409 | GDK_POINTER_MOTION_MASK
2410 | GDK_POINTER_MOTION_HINT_MASK));
2413 sheet->direct_update_cell = FALSE;
2414 sheet->shift_state = 0;
2415 sheet->keyval_state = 0;
2416 sheet->bound = sheet->pos = 0;
2421 gnucash_sheet_get_type (
void)
2423 static GType gnucash_sheet_type = 0;
2425 if (!gnucash_sheet_type)
2427 static const GTypeInfo gnucash_sheet_info =
2429 sizeof (GnucashSheetClass),
2432 (GClassInitFunc) gnucash_sheet_class_init,
2435 sizeof (GnucashSheet),
2437 (GInstanceInitFunc) gnucash_sheet_init
2440 gnucash_sheet_type =
2441 g_type_register_static (GTK_TYPE_LAYOUT,
2443 &gnucash_sheet_info, 0);
2446 return gnucash_sheet_type;
2451 gnucash_sheet_tooltip (GtkWidget *widget, gint x, gint y,
2452 gboolean keyboard_mode,
2453 GtkTooltip *tooltip,
2456 GnucashSheet *sheet = GNUCASH_SHEET(widget);
2457 Table *
table = sheet->table;
2458 VirtualLocation virt_loc;
2459 gchar *tooltip_text;
2460 gint cx, cy, cw, ch;
2464 gint hscroll_val, vscroll_val;
2470 hscroll_val = (gint) gtk_adjustment_get_value (sheet->hadj);
2471 vscroll_val = (gint) gtk_adjustment_get_value (sheet->vadj);
2473 if (!gnucash_sheet_find_loc_by_pixel (sheet, x + hscroll_val, y + vscroll_val, &virt_loc))
2476 tooltip_text = gnc_table_get_tooltip (
table, virt_loc);
2479 if (!tooltip_text || (g_strcmp0 (tooltip_text,
"") == 0))
2481 gtk_tooltip_set_text (tooltip, NULL);
2485 block = gnucash_sheet_get_block (sheet, virt_loc.vcell_loc);
2488 g_free (tooltip_text);
2492 bx = block->origin_x;
2496 gnucash_sheet_style_get_cell_pixel_rel_coords (block->
style,
2497 virt_loc.phys_row_offset, virt_loc.phys_col_offset,
2498 &cx, &cy, &cw, &ch);
2500 rect.x = cx + bx - hscroll_val;
2501 rect.y = cy + by - vscroll_val;
2505 gtk_tooltip_set_tip_area (tooltip, &rect);
2506 gtk_tooltip_set_text (tooltip, tooltip_text);
2507 g_free (tooltip_text);
2513 gnucash_sheet_new (Table *
table)
2515 GnucashSheet *sheet;
2517 g_return_val_if_fail (
table != NULL, NULL);
2519 sheet = gnucash_sheet_create (
table);
2522 sheet->sheet_has_focus = TRUE;
2525 sheet->cursor = gnucash_cursor_new (sheet);
2528 sheet->item_editor = gnc_item_edit_new (sheet);
2531 sheet->dimensions_hash_table = g_hash_table_new_full (g_int_hash,
2536 gtk_widget_set_has_tooltip (GTK_WIDGET(sheet), TRUE);
2537 g_signal_connect (G_OBJECT(sheet),
"query-tooltip",
2538 G_CALLBACK(gnucash_sheet_tooltip), NULL);
2540 gnucash_sheet_refresh_from_prefs (sheet);
2542 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