GnuCash c935c2f+
Loading...
Searching...
No Matches
gnucash-register.c
1/********************************************************************\
2 * This program is free software; you can redistribute it and/or *
3 * modify it under the terms of the GNU General Public License as *
4 * published by the Free Software Foundation; either version 2 of *
5 * the License, or (at your option) any later version. *
6 * *
7 * This program is distributed in the hope that it will be useful, *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10 * GNU General Public License for more details. *
11 * *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact: *
14 * *
15 * Free Software Foundation Voice: +1-617-542-5942 *
16 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17 * Boston, MA 02110-1301, USA gnu@gnu.org *
18 * *
19\********************************************************************/
20
21/*
22 * The Gnucash Register widget
23 *
24 * Based heavily on the Gnumeric Sheet widget.
25 *
26 * Authors:
27 * Heath Martin <martinh@pegasus.cc.ucf.edu>
28 * Dave Peticolas <dave@krondo.com>
29 */
30
31#include <config.h>
32#include <glib.h>
33#include <glib/gprintf.h>
34#include <gdk/gdkkeysyms.h>
35
36#include "gnucash-register.h"
37#include "gnucash-sheet.h"
38#include "gnucash-sheetP.h"
39
40#include "gnucash-cursor.h"
41#include "gnucash-style.h"
42#include "gnucash-header.h"
43#include "gnucash-item-edit.h"
44#include "split-register.h"
45#include "gnc-engine.h" // For debugging, e.g. ENTER(), LEAVE()
46#include "gnc-prefs.h"
47#include "gnc-state.h"
48
49#include "combocell.h"
50#include "completioncell.h"
51#include "datecell.h"
52#include "formulacell-gnome.h"
53#include "pricecell-gnome.h"
54#include "quickfillcell-gnome.h"
55#include "table-gnome.h"
56
57
58/* Register signals */
59enum
60{
61 ACTIVATE_CURSOR,
62 REDRAW_ALL,
63 REDRAW_HELP,
64 SHOW_POPUP_MENU,
65 LAST_SIGNAL
66};
67
68
71/* This static indicates the debugging module that this .o belongs to. */
72static QofLogModule log_module = GNC_MOD_REGISTER;
73static guint register_signals[LAST_SIGNAL];
74
75
77{
78 GtkGrid table;
79
80 GtkWidget *hscrollbar;
81 GtkWidget *sheet;
82 gboolean hscrollbar_visible;
83};
84
85
87{
88 GtkGridClass parent_class;
89
90 void (*activate_cursor) (GnucashRegister *reg);
91 void (*redraw_all) (GnucashRegister *reg);
92 void (*redraw_help) (GnucashRegister *reg);
93 void (*show_popup_menu) (GnucashRegister *reg);
94};
95
98G_DEFINE_TYPE (GnucashRegister, gnucash_register, GTK_TYPE_GRID)
99
100void
102{
103 gnc_register_add_cell_type (COMBO_CELL_TYPE_NAME, gnc_combo_cell_new);
104 gnc_register_add_cell_type (COMPLETION_CELL_TYPE_NAME, gnc_completion_cell_new);
105 gnc_register_add_cell_type (DATE_CELL_TYPE_NAME, gnc_date_cell_new);
106 gnc_register_add_cell_type (PRICE_CELL_TYPE_NAME,
107 gnc_price_cell_gnome_new);
108 gnc_register_add_cell_type (QUICKFILL_CELL_TYPE_NAME,
109 gnc_quickfill_cell_gnome_new);
110 gnc_register_add_cell_type( FORMULA_CELL_TYPE_NAME,
111 gnc_formula_cell_gnome_new );
112 gnc_table_gnome_init ();
113}
114
115gboolean
116gnucash_register_has_selection (GnucashRegister *reg)
117{
118 GnucashSheet *sheet;
119 GncItemEdit *item_edit;
120
121 g_return_val_if_fail((reg != NULL), FALSE);
122 g_return_val_if_fail(GNUCASH_IS_REGISTER(reg), FALSE);
123
124 sheet = GNUCASH_SHEET(reg->sheet);
125 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
126
127 return gnc_item_edit_get_has_selection(item_edit);
128}
129
130void
131gnucash_register_cut_clipboard (GnucashRegister *reg)
132{
133 GnucashSheet *sheet;
134 GncItemEdit *item_edit;
135
136 g_return_if_fail(reg != NULL);
137 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
138
139 sheet = GNUCASH_SHEET(reg->sheet);
140 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
141
142 gnc_item_edit_cut_clipboard(item_edit);
143}
144
145void
146gnucash_register_copy_clipboard (GnucashRegister *reg)
147{
148 GnucashSheet *sheet;
149 GncItemEdit *item_edit;
150
151 g_return_if_fail(reg != NULL);
152 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
153
154 sheet = GNUCASH_SHEET(reg->sheet);
155 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
156
157 gnc_item_edit_copy_clipboard(item_edit);
158}
159
160void
161gnucash_register_paste_clipboard (GnucashRegister *reg)
162{
163 GnucashSheet *sheet;
164 GncItemEdit *item_edit;
165
166 g_return_if_fail(reg != NULL);
167 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
168
169 sheet = GNUCASH_SHEET(reg->sheet);
170 item_edit = GNC_ITEM_EDIT(sheet->item_editor);
171
172 gnc_item_edit_paste_clipboard (item_edit);
173}
174
175void
176gnucash_register_refresh_from_prefs (GnucashRegister *reg)
177{
178 GnucashSheet *sheet;
179
180 g_return_if_fail(reg != NULL);
181 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
182
183 sheet = GNUCASH_SHEET(reg->sheet);
184 gnucash_sheet_refresh_from_prefs(sheet);
185 gnc_header_request_redraw (GNC_HEADER(sheet->header_item));
186}
187
188void
189gnucash_register_reset_sheet_layout (GnucashRegister *reg)
190{
191 GNCHeaderWidths widths;
192 GnucashSheet *sheet;
193 gint current_width;
194
195 g_return_if_fail (reg != NULL);
196
197 sheet = GNUCASH_SHEET(reg->sheet);
198
199 g_return_if_fail (sheet != NULL);
200 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
201
202 current_width = sheet->window_width - 1;
203
204 widths = gnc_header_widths_new ();
205 gnucash_sheet_set_header_widths (sheet, widths);
206
207 gnucash_sheet_styles_set_dimensions (sheet, current_width);
208
209 gnucash_sheet_compile_styles (sheet);
210 gnucash_sheet_table_load (sheet, TRUE);
211 gnucash_sheet_cursor_set_from_table (sheet, TRUE);
212 gnucash_sheet_redraw_all (sheet);
213 gnc_header_widths_destroy (widths);
214}
215
216void
217gnucash_register_goto_virt_cell (GnucashRegister *reg,
218 VirtualCellLocation vcell_loc)
219{
220 GnucashSheet *sheet;
221 VirtualLocation virt_loc;
222
223 g_return_if_fail(reg != NULL);
224 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
225
226 sheet = GNUCASH_SHEET(reg->sheet);
227
228 virt_loc.vcell_loc = vcell_loc;
229 virt_loc.phys_row_offset = 0;
230 virt_loc.phys_col_offset = 0;
231
232 gnucash_sheet_goto_virt_loc(sheet, virt_loc);
233}
234
235void
236gnucash_register_goto_virt_loc (GnucashRegister *reg,
237 VirtualLocation virt_loc)
238{
239 GnucashSheet *sheet;
240
241 g_return_if_fail(reg != NULL);
242 g_return_if_fail(GNUCASH_IS_REGISTER(reg));
243
244 sheet = GNUCASH_SHEET(reg->sheet);
245
246 gnucash_sheet_goto_virt_loc(sheet, virt_loc);
247}
248
249void
250gnucash_register_goto_next_virt_row (GnucashRegister *reg)
251{
252 GnucashSheet *sheet;
253 VirtualLocation virt_loc;
254 int start_virt_row;
255
256 g_return_if_fail (reg != NULL);
257 g_return_if_fail (GNUCASH_IS_REGISTER(reg));
258
259 sheet = GNUCASH_SHEET(reg->sheet);
260
261 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
262
263 /* Move down one physical row at a time until we
264 * reach the next visible virtual cell. */
265 start_virt_row = virt_loc.vcell_loc.virt_row;
266 do
267 {
268 if (!gnc_table_move_vertical_position (sheet->table, &virt_loc, 1))
269 return;
270 }
271 while (start_virt_row == virt_loc.vcell_loc.virt_row);
272
273 if (virt_loc.vcell_loc.virt_row >= sheet->num_virt_rows)
274 return;
275
276 virt_loc.phys_row_offset = 0;
277 virt_loc.phys_col_offset = 0;
278
279 gnucash_sheet_goto_virt_loc (sheet, virt_loc);
280}
281
282void
283gnucash_register_goto_next_matching_row (GnucashRegister *reg,
284 VirtualLocationMatchFunc match,
285 gpointer user_data)
286{
287 GnucashSheet *sheet;
288 SheetBlockStyle *style;
289 VirtualLocation virt_loc;
290
291 g_return_if_fail (reg != NULL);
292 g_return_if_fail (GNUCASH_IS_REGISTER(reg));
293 g_return_if_fail (match != NULL);
294
295 sheet = GNUCASH_SHEET (reg->sheet);
296
297 gnucash_cursor_get_virt (GNUCASH_CURSOR(sheet->cursor), &virt_loc);
298
299 do
300 {
301 if (!gnc_table_move_vertical_position (sheet->table,
302 &virt_loc, 1))
303 return;
304
305 if (virt_loc.vcell_loc.virt_row >= sheet->num_virt_rows)
306 return;
307
308 style = gnucash_sheet_get_style (sheet, virt_loc.vcell_loc);
309 if (!style || !style->cursor)
310 return;
311 }
312 while (!match (virt_loc, user_data));
313
314 virt_loc.phys_row_offset = 0;
315 virt_loc.phys_col_offset = 0;
316
317 gnucash_sheet_goto_virt_loc (sheet, virt_loc);
318}
319
320static gboolean
321gnucash_register_sheet_resize (GnucashRegister *reg)
322{
323 // Sometimes the space left by the horizontal scrollbar does
324 // not get filled on load, this makes sure it does
325 if (!reg->hscrollbar_visible)
326 gtk_widget_queue_resize (GTK_WIDGET (reg->sheet));
327
328 return FALSE;
329}
330
331static void
332gnucash_register_update_hadjustment (GtkAdjustment *adj,
333 GnucashRegister *reg)
334{
335 g_return_if_fail (reg != NULL);
336 g_return_if_fail (GNUCASH_IS_REGISTER(reg));
337
338 if (gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj)
339 > gtk_adjustment_get_page_size (adj))
340 {
341 if (!reg->hscrollbar_visible)
342 {
343 gtk_widget_show(reg->hscrollbar);
344 reg->hscrollbar_visible = TRUE;
345 }
346 }
347 else
348 {
349 if (reg->hscrollbar_visible)
350 {
351 gtk_widget_hide(reg->hscrollbar);
352 reg->hscrollbar_visible = FALSE;
353 // When sheet first loaded and the scrollbar is hidden, the space left
354 // is not always automatically taken up by the sheet so queue a resize
355 // when all is idle
356 g_idle_add ((GSourceFunc) gnucash_register_sheet_resize, reg);
357 }
358 }
359}
360
361/*************************************************************/
362
363
364static void
365gnucash_register_class_init (GnucashRegisterClass *klass)
366{
367 GObjectClass *gobject_class;
368
369 gobject_class = G_OBJECT_CLASS (klass);
370
371 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(klass), "gnc-id-register");
372
373 register_signals[ACTIVATE_CURSOR] =
374 g_signal_new("activate_cursor",
375 G_TYPE_FROM_CLASS(gobject_class),
376 G_SIGNAL_RUN_LAST,
377 G_STRUCT_OFFSET(GnucashRegisterClass,
378 activate_cursor),
379 NULL, NULL,
380 g_cclosure_marshal_VOID__VOID,
381 G_TYPE_NONE, 0);
382
383 register_signals[REDRAW_ALL] =
384 g_signal_new("redraw_all",
385 G_TYPE_FROM_CLASS(gobject_class),
386 G_SIGNAL_RUN_LAST,
387 G_STRUCT_OFFSET(GnucashRegisterClass,
388 redraw_all),
389 NULL, NULL,
390 g_cclosure_marshal_VOID__VOID,
391 G_TYPE_NONE, 0);
392
393 register_signals[REDRAW_HELP] =
394 g_signal_new("redraw_help",
395 G_TYPE_FROM_CLASS(gobject_class),
396 G_SIGNAL_RUN_LAST,
397 G_STRUCT_OFFSET(GnucashRegisterClass,
398 redraw_help),
399 NULL, NULL,
400 g_cclosure_marshal_VOID__VOID,
401 G_TYPE_NONE, 0);
402
403 register_signals[SHOW_POPUP_MENU] =
404 g_signal_new("show_popup_menu",
405 G_TYPE_FROM_CLASS(gobject_class),
406 G_SIGNAL_RUN_LAST,
407 G_STRUCT_OFFSET(GnucashRegisterClass,
408 show_popup_menu),
409 NULL, NULL,
410 g_cclosure_marshal_VOID__VOID,
411 G_TYPE_NONE, 0);
412
413 klass->activate_cursor = NULL;
414 klass->redraw_all = NULL;
415 klass->redraw_help = NULL;
416 klass->show_popup_menu = NULL;
417}
418
419
420static void
421gnucash_register_init (GnucashRegister *g_reg)
422{
423 GtkGrid *table = GTK_GRID(g_reg);
424
425 gtk_widget_set_can_focus (GTK_WIDGET(table), FALSE);
426 gtk_widget_set_can_default (GTK_WIDGET(table), FALSE);
427
428 gtk_grid_set_row_homogeneous (GTK_GRID(table), FALSE);
429 gtk_grid_set_column_homogeneous (GTK_GRID(table), FALSE);
430}
431
432void
433gnucash_register_attach_popup (GnucashRegister *reg,
434 GtkWidget *popup,
435 gpointer data)
436{
437 g_return_if_fail (GNUCASH_IS_REGISTER(reg));
438 g_return_if_fail (reg->sheet != NULL);
439 if (popup)
440 g_return_if_fail (GTK_IS_WIDGET(popup));
441
442 gnucash_sheet_set_popup (GNUCASH_SHEET (reg->sheet), popup, data);
443}
444
445
446/* Um, this function checks that data is not null but never uses it.
447 * Weird. Also, since this function only works with a GnucashRegister
448 * widget, maybe some of it should be moved to gnucash-sheet.c. */
449/* Adding to previous note: Since data doesn't appear do anything and to
450 * align the function with save_state() I've removed the check for
451 * NULL and changed two calls in dialog_order.c and dialog_invoice.c
452 * to pass NULL as second parameter. */
453
454static void
455gnucash_register_configure (GnucashSheet *sheet, const gchar * state_section)
456{
457 GNCHeaderWidths widths;
458 Table *table;
459 GList *node;
460 gchar *key;
461 guint value;
462 GKeyFile *state_file = gnc_state_get_current();
463
464 // Stuff for per-register settings load.
465 g_return_if_fail (sheet != NULL);
466 g_return_if_fail (GNUCASH_IS_SHEET (sheet));
467
468 PINFO("state_section=%s",state_section);
469
470 ENTER("sheet=%p, data=%p", sheet, "");
471
472 table = sheet->table;
474 table->ui_data = sheet;
475
476 g_object_ref (sheet);
477
478 /* config the cell-block styles */
479
480 widths = gnc_header_widths_new ();
481
482 if (state_section && gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_SAVE_GEOMETRY))
483 {
484 node = gnc_table_layout_get_cells (table->layout);
485 for (; node; node = node->next)
486 {
487 BasicCell *cell = node->data;
488
489 if (cell->expandable)
490 continue;
491
492 /* Remember whether the column is visible */
493 key = g_strdup_printf("%s_width", cell->cell_name);
494 value = g_key_file_get_integer (state_file, state_section, key, NULL);
495 if (value != 0)
496 gnc_header_widths_set_width (widths, cell->cell_name, value);
497 g_free(key);
498 }
499 }
500
501 gnucash_sheet_create_styles (sheet);
502
503 gnucash_sheet_set_header_widths (sheet, widths);
504
505 gnucash_sheet_compile_styles (sheet);
506
507 gnucash_sheet_table_load (sheet, TRUE);
508 gnucash_sheet_cursor_set_from_table (sheet, TRUE);
509 gnucash_sheet_redraw_all (sheet);
510
511 gnc_header_widths_destroy (widths);
512
513 LEAVE(" ");
514}
515
516
517static GtkWidget *
518gnucash_register_create_widget (Table *table)
519{
520 GnucashRegister *reg;
521 GtkWidget *header;
522 GtkWidget *widget;
523 GtkWidget *sheet;
524 GtkWidget *scrollbar;
525
526 reg = g_object_new (GNUCASH_TYPE_REGISTER, NULL);
527 widget = GTK_WIDGET(reg);
528
529 sheet = gnucash_sheet_new (table);
530 reg->sheet = sheet;
531 GNUCASH_SHEET(sheet)->reg = widget;
532
533 header = gnc_header_new (GNUCASH_SHEET(sheet));
534
535 gtk_grid_attach (GTK_GRID(widget), header, 0, 0, 1, 1);
536 gtk_widget_set_hexpand (header, TRUE);
537 gtk_widget_set_halign (header, GTK_ALIGN_FILL);
538 gtk_widget_set_vexpand (header, FALSE);
539 gtk_widget_set_valign (header, GTK_ALIGN_FILL);
540 g_object_set (header, "margin", 0, NULL);
541 gtk_widget_show (header);
542
543 gtk_grid_attach (GTK_GRID(widget), sheet, 0, 1, 1, 1);
544 gtk_widget_set_hexpand (sheet, TRUE);
545 gtk_widget_set_halign (sheet, GTK_ALIGN_FILL);
546 gtk_widget_set_vexpand (sheet, TRUE);
547 gtk_widget_set_valign (sheet, GTK_ALIGN_FILL);
548 g_object_set (sheet, "margin", 0, NULL);
549 gtk_widget_show (sheet);
550
551 scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GNUCASH_SHEET(sheet)->vadj);
552 gtk_grid_attach (GTK_GRID(widget), GTK_WIDGET(scrollbar), 1, 0, 1, 2);
553 gtk_widget_set_hexpand (GTK_WIDGET(scrollbar), FALSE);
554 gtk_widget_set_halign (GTK_WIDGET(scrollbar), GTK_ALIGN_FILL);
555 gtk_widget_set_vexpand (GTK_WIDGET(scrollbar), TRUE);
556 gtk_widget_set_valign (GTK_WIDGET(scrollbar), GTK_ALIGN_FILL);
557 g_object_set (GTK_WIDGET(scrollbar), "margin", 0, NULL);
558 gtk_widget_show (scrollbar);
559 GNUCASH_SHEET(sheet)->vscrollbar = scrollbar;
560
561 scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GNUCASH_SHEET(sheet)->hadj);
562 gtk_grid_attach (GTK_GRID(widget), GTK_WIDGET(scrollbar), 0, 2, 1, 1);
563 gtk_widget_set_hexpand (GTK_WIDGET(scrollbar), TRUE);
564 gtk_widget_set_halign (GTK_WIDGET(scrollbar), GTK_ALIGN_FILL);
565 gtk_widget_set_vexpand (GTK_WIDGET(scrollbar), FALSE);
566 gtk_widget_set_valign (GTK_WIDGET(scrollbar), GTK_ALIGN_FILL);
567 g_object_set (GTK_WIDGET(scrollbar), "margin", 0, NULL);
568 reg->hscrollbar = scrollbar;
569 gtk_widget_show (reg->hscrollbar);
570 reg->hscrollbar_visible = TRUE;
571 GNUCASH_SHEET(sheet)->hscrollbar = scrollbar;
572
573 g_signal_connect (GNUCASH_SHEET(sheet)->hadj, "changed",
574 G_CALLBACK (gnucash_register_update_hadjustment), reg);
575
576 return widget;
577}
578
579
580GtkWidget *
581gnucash_register_new (Table *table, const gchar *state_section)
582{
583 GnucashRegister *reg;
584 GtkWidget *widget;
585
586 widget = gnucash_register_create_widget(table);
587 reg = GNUCASH_REGISTER(widget);
588
589 gnucash_register_configure (GNUCASH_SHEET(reg->sheet), state_section);
590
591 return widget;
592}
593
594
595void gnucash_register_set_moved_cb (GnucashRegister *reg,
596 GFunc cb, gpointer cb_data)
597{
598 GnucashSheet *sheet;
599
600 if (!reg || !reg->sheet)
601 return;
602 sheet = GNUCASH_SHEET(reg->sheet);
603 sheet->moved_cb = cb;
604 sheet->moved_cb_data = cb_data;
605}
606
607
608GnucashSheet *gnucash_register_get_sheet (GnucashRegister *reg)
609{
610 g_return_val_if_fail (reg != NULL, NULL);
611 g_return_val_if_fail (GNUCASH_IS_REGISTER(reg), NULL);
612
613 return GNUCASH_SHEET(reg->sheet);
614}
615
616
617void
618gnucash_register_set_open_doclink_cb (GnucashRegister *reg,
619 GFunc cb, gpointer cb_data)
620{
621 GnucashSheet *sheet;
622
623 if (!reg || !reg->sheet)
624 return;
625 sheet = GNUCASH_SHEET(reg->sheet);
626 sheet->open_doclink_cb = cb;
627 sheet->open_doclink_cb_data = cb_data;
628}
629
630
Implements gnome dependent formula cell functions.
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
Functions to load, save and get gui state.
Public declarations for GnucashCursor class.
Public declarations for GnucashHeader class.
Public declarations for GncItemEdit class.
Private declarations for GnucashSheet class.
Public declarations of GnucashRegister class.
Styling functions for RegisterGnome.
BasicCell * gnc_date_cell_new(void)
installs a callback to handle date recording
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition gnc-state.c:248
void gnucash_register_add_cell_types(void)
Implementation.
GtkWidget * gnucash_register_new(Table *table, const gchar *state_section)
this already has scrollbars attached
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_table_init_gui(Table *table)
UI-specific functions.
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.
API for checkbook register display area.