GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-utils.c
1/********************************************************************\
2 * dialog-utils.c -- utility functions for creating dialogs *
3 * for GnuCash *
4 * Copyright (C) 1999-2000 Linas Vepstas *
5 * Copyright (C) 2005 David Hampton <hampton@employees.org> *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License*
18 * along with this program; if not, contact: *
19 * *
20 * Free Software Foundation Voice: +1-617-542-5942 *
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22 * Boston, MA 02110-1301, USA gnu@gnu.org *
23 * *
24\********************************************************************/
25
26#include <config.h>
27
28#include <gtk/gtk.h>
29#include <gdk/gdkkeysyms.h>
30#include <glib/gi18n.h>
31#include <gmodule.h>
32#ifdef HAVE_DLFCN_H
33# include <dlfcn.h>
34#endif
35
36#include "dialog-utils.h"
37#include "gnc-commodity.h"
38#include "gnc-date.h"
39#include "gnc-path.h"
40#include "gnc-engine.h"
41#include "gnc-euro.h"
42#include "gnc-ui.h"
43#include "gnc-ui-util.h"
44#include "gnc-prefs.h"
45#include "gnc-main-window.h"
46
47/* This static indicates the debugging module that this .o belongs to. */
48static QofLogModule log_module = GNC_MOD_GUI;
49
50#define GNC_PREF_LAST_GEOMETRY "last-geometry"
51
52/********************************************************************\
53 * gnc_set_label_color *
54 * sets the color of the label given the value *
55 * *
56 * Args: label - gtk label widget *
57 * value - value to use to set color *
58 * Returns: none *
59 \*******************************************************************/
60void
61gnc_set_label_color(GtkWidget *label, gnc_numeric value)
62{
63 gboolean deficit;
64
65 if (!gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED))
66 return;
67
68 deficit = gnc_numeric_negative_p (value);
69
70 if (deficit)
71 {
72 gnc_widget_style_context_remove_class (GTK_WIDGET(label), "gnc-class-default-color");
73 gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-negative-numbers");
74 }
75 else
76 {
77 gnc_widget_style_context_remove_class (GTK_WIDGET(label), "gnc-class-negative-numbers");
78 gnc_widget_style_context_add_class (GTK_WIDGET(label), "gnc-class-default-color");
79 }
80}
81
82
83/********************************************************************\
84 * gnc_restore_window_size *
85 * restores the position and size of the given window, if these *
86 * these parameters have been saved earlier. Does nothing if no *
87 * saved values are found. *
88 * *
89 * Args: group - the preferences group to look in for saved coords *
90 * window - the window for which the coords are to be *
91 * restored *
92 * parent - the parent window that can be used to position *
93 * window when it still has default entries *
94 * Returns: nothing *
95 \*******************************************************************/
96void
97gnc_restore_window_size(const char *group, GtkWindow *window, GtkWindow *parent)
98{
99 gint wpos[2], wsize[2];
100 GVariant *geometry;
101
102 ENTER("");
103
104 g_return_if_fail(group != NULL);
105 g_return_if_fail(window != NULL);
106 g_return_if_fail(parent != NULL);
107
108 if (!gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_SAVE_GEOMETRY))
109 return;
110
111 geometry = gnc_prefs_get_value (group, GNC_PREF_LAST_GEOMETRY);
112
113 if (g_variant_is_of_type (geometry, (const GVariantType *) "(iiii)") )
114 {
115 GdkWindow *win = gtk_widget_get_window (GTK_WIDGET(parent));
116 GdkRectangle monitor_size;
117 GdkDisplay *display = gdk_window_get_display (win);
118 GdkMonitor *mon;
119
120 g_variant_get (geometry, "(iiii)",
121 &wpos[0], &wpos[1],
122 &wsize[0], &wsize[1]);
123
124 mon = gdk_display_get_monitor_at_point (display, wpos[0], wpos[1]);
125 gdk_monitor_get_geometry (mon, &monitor_size);
126
127 DEBUG("monitor left top corner x: %d, y: %d, width: %d, height: %d",
128 monitor_size.x, monitor_size.y, monitor_size.width, monitor_size.height);
129 DEBUG("geometry from preferences - group, %s, wpos[0]: %d, wpos[1]: %d, wsize[0]: %d, wsize[1]: %d",
130 group, wpos[0], wpos[1], wsize[0], wsize[1]);
131
132 /* (-1, -1) means no geometry was saved (default preferences value) */
133 if ((wpos[0] != -1) && (wpos[1] != -1))
134 {
135 /* Keep the window on screen if possible */
136 if (wpos[0] - monitor_size.x + wsize[0] > monitor_size.x + monitor_size.width)
137 wpos[0] = monitor_size.x + monitor_size.width - wsize[0];
138
139 if (wpos[1] - monitor_size.y + wsize[1] > monitor_size.y + monitor_size.height)
140 wpos[1] = monitor_size.y + monitor_size.height - wsize[1];
141
142 /* make sure the coordinates have not left the monitor */
143 if (wpos[0] < monitor_size.x)
144 wpos[0] = monitor_size.x;
145
146 if (wpos[1] < monitor_size.y)
147 wpos[1] = monitor_size.y;
148
149 DEBUG("geometry after screen adaption - wpos[0]: %d, wpos[1]: %d, wsize[0]: %d, wsize[1]: %d",
150 wpos[0], wpos[1], wsize[0], wsize[1]);
151
152 gtk_window_move(window, wpos[0], wpos[1]);
153 }
154 else
155 {
156 /* preference is at default value -1,-1,-1,-1 */
157 if (parent != NULL)
158 {
159 gint parent_wpos[2], parent_wsize[2], window_wsize[2];
160 gtk_window_get_position (GTK_WINDOW(parent), &parent_wpos[0], &parent_wpos[1]);
161 gtk_window_get_size (GTK_WINDOW(parent), &parent_wsize[0], &parent_wsize[1]);
162 gtk_window_get_size (GTK_WINDOW(window), &window_wsize[0], &window_wsize[1]);
163
164 DEBUG("parent window - wpos[0]: %d, wpos[1]: %d, wsize[0]: %d, wsize[1]: %d - window size is %dx%d",
165 parent_wpos[0], parent_wpos[1], parent_wsize[0], parent_wsize[1],
166 window_wsize[0], window_wsize[1]);
167
168 /* check for gtk default size, no window size specified, let gtk decide location */
169 if ((window_wsize[0] == 200) && (window_wsize[1] == 200))
170 DEBUG("window size not specified, let gtk locate it");
171 else
172 gtk_window_move (window, parent_wpos[0] + (parent_wsize[0] - window_wsize[0])/2,
173 parent_wpos[1] + (parent_wsize[1] - window_wsize[1])/2);
174 }
175 }
176
177 /* Don't attempt to restore invalid sizes */
178 if ((wsize[0] > 0) && (wsize[1] > 0))
179 {
180 wsize[0] = MIN(wsize[0], monitor_size.width - 10);
181 wsize[1] = MIN(wsize[1], monitor_size.height - 10);
182
183 gtk_window_resize(window, wsize[0], wsize[1]);
184 }
185 }
186 g_variant_unref (geometry);
187 LEAVE("");
188}
189
190
191/********************************************************************\
192 * gnc_save_window_size *
193 * save the window position and size into options whose names are *
194 * prefixed by the group name. *
195 * *
196 * Args: group - preferences group to save the options in *
197 * window - the window for which current position and size *
198 * are to be saved *
199 * Returns: nothing *
200\********************************************************************/
201void
202gnc_save_window_size(const char *group, GtkWindow *window)
203{
204 gint wpos[2], wsize[2];
205 GVariant *geometry;
206
207 ENTER("");
208
209 g_return_if_fail(group != NULL);
210 g_return_if_fail(window != NULL);
211
212 if (!gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_SAVE_GEOMETRY))
213 return;
214
215 gtk_window_get_position(GTK_WINDOW(window), &wpos[0], &wpos[1]);
216 gtk_window_get_size(GTK_WINDOW(window), &wsize[0], &wsize[1]);
217
218 DEBUG("save geometry - wpos[0]: %d, wpos[1]: %d, wsize[0]: %d, wsize[1]: %d",
219 wpos[0], wpos[1], wsize[0], wsize[1]);
220
221 geometry = g_variant_new ("(iiii)", wpos[0], wpos[1],
222 wsize[0], wsize[1]);
223 gnc_prefs_set_value (group, GNC_PREF_LAST_GEOMETRY, geometry);
224 /* Don't unref geometry here, it is consumed by gnc_prefs_set_value */
225 LEAVE("");
226}
227
228
229/********************************************************************\
230 * gnc_window_adjust_for_screen *
231 * adjust the window size if it is bigger than the screen size. *
232 * *
233 * Args: window - the window to adjust *
234 * Returns: nothing *
235\********************************************************************/
236void
237gnc_window_adjust_for_screen(GtkWindow * window)
238{
239 GdkWindow *win;
240 GdkDisplay *display;
241 GdkMonitor *mon;
242 GdkRectangle monitor_size;
243 gint wpos[2];
244 gint width;
245 gint height;
246
247 ENTER("");
248
249 if (window == NULL)
250 return;
251
252 g_return_if_fail(GTK_IS_WINDOW(window));
253 if (gtk_widget_get_window (GTK_WIDGET(window)) == NULL)
254 return;
255
256 win = gtk_widget_get_window (GTK_WIDGET(window));
257 display = gdk_window_get_display (win);
258
259 gtk_window_get_position(GTK_WINDOW(window), &wpos[0], &wpos[1]);
260 gtk_window_get_size(GTK_WINDOW(window), &width, &height);
261
262 mon = gdk_display_get_monitor_at_point (display, wpos[0], wpos[1]);
263 gdk_monitor_get_geometry (mon, &monitor_size);
264
265 DEBUG("monitor width is %d, height is %d; wwindow width is %d, height is %d",
266 monitor_size.width, monitor_size.height, width, height);
267
268 if ((width <= monitor_size.width) && (height <= monitor_size.height))
269 return;
270
271 /* Keep the window on screen if possible */
272 if (wpos[0] - monitor_size.x + width > monitor_size.x + monitor_size.width)
273 wpos[0] = monitor_size.x + monitor_size.width - width;
274
275 if (wpos[1] - monitor_size.y + height > monitor_size.y + monitor_size.height)
276 wpos[1] = monitor_size.y + monitor_size.height - height;
277
278 /* make sure the coordinates have not left the monitor */
279 if (wpos[0] < monitor_size.x)
280 wpos[0] = monitor_size.x;
281
282 if (wpos[1] < monitor_size.y)
283 wpos[1] = monitor_size.y;
284
285 DEBUG("move window to position %d, %d", wpos[0], wpos[1]);
286
287 gtk_window_move(window, wpos[0], wpos[1]);
288
289 /* if window is bigger, set it to monitor sizes */
290 width = MIN(width, monitor_size.width - 10);
291 height = MIN(height, monitor_size.height - 10);
292
293 DEBUG("resize window to width %d, height %d", width, height);
294
295 gtk_window_resize(GTK_WINDOW(window), width, height);
296 gtk_widget_queue_resize(GTK_WIDGET(window));
297 LEAVE("");
298}
299
300/********************************************************************\
301 * Sets the alignment of a Label Widget, GTK3 version specific. *
302 * *
303 * Args: widget - the label widget to set alignment on *
304 * xalign - x alignment *
305 * yalign - y alignment *
306 * Returns: nothing *
307\********************************************************************/
308void
309gnc_label_set_alignment (GtkWidget *widget, gfloat xalign, gfloat yalign)
310{
311 gtk_label_set_xalign (GTK_LABEL (widget), xalign);
312 gtk_label_set_yalign (GTK_LABEL (widget), yalign);
313}
314
315/********************************************************************\
316 * Get the preference for showing tree view grid lines *
317 * *
318 * Args: none *
319 * Returns: GtkTreeViewGridLines setting *
320\********************************************************************/
321GtkTreeViewGridLines
322gnc_tree_view_get_grid_lines_pref (void)
323{
324 GtkTreeViewGridLines grid_lines;
325 gboolean h_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_HORIZONTAL);
326 gboolean v_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_GRID_LINES_VERTICAL);
327
328 if (h_lines)
329 {
330 if (v_lines)
331 grid_lines = GTK_TREE_VIEW_GRID_LINES_BOTH;
332 else
333 grid_lines = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL;
334 }
335 else if (v_lines)
336 grid_lines = GTK_TREE_VIEW_GRID_LINES_VERTICAL;
337 else
338 grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
339 return grid_lines;
340}
341
342/********************************************************************\
343 * Add a style context to a Widget so it can be altered with css *
344 * *
345 * Args: widget - widget to add css style too *
346 * gnc_class - character string for css class name *
347 * Returns: nothing *
348\********************************************************************/
349void
350gnc_widget_style_context_add_class (GtkWidget *widget, const char *gnc_class)
351{
352 GtkStyleContext *context = gtk_widget_get_style_context (widget);
353 gtk_style_context_add_class (context, gnc_class);
354}
355
356/********************************************************************\
357 * Remove a style context class from a Widget *
358 * *
359 * Args: widget - widget to remove style class from *
360 * gnc_class - character string for css class name *
361 * Returns: nothing *
362\********************************************************************/
363void
364gnc_widget_style_context_remove_class (GtkWidget *widget, const char *gnc_class)
365{
366 GtkStyleContext *context = gtk_widget_get_style_context (widget);
367
368 if (gtk_style_context_has_class (context, gnc_class))
369 gtk_style_context_remove_class (context, gnc_class);
370}
371
372/********************************************************************\
373 * Draw an arrow on a Widget so it can be altered with css *
374 * *
375 * Args: widget - widget to add arrow to in the draw callback *
376 * cr - cairo context for the draw callback *
377 * direction - 0 for up, 1 for down *
378 * Returns: TRUE, stop other handlers being invoked for the event *
379\********************************************************************/
380gboolean
381gnc_draw_arrow_cb (GtkWidget *widget, cairo_t *cr, gpointer direction)
382{
383 GtkStyleContext *context = gtk_widget_get_style_context (widget);
384 gint width = gtk_widget_get_allocated_width (widget);
385 gint height = gtk_widget_get_allocated_height (widget);
386 gint size;
387
388 gtk_render_background (context, cr, 0, 0, width, height);
389 gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
390
391 size = MIN(width / 2, height / 2);
392
393 if (GPOINTER_TO_INT(direction) == 0)
394 gtk_render_arrow (context, cr, 0,
395 (width - size)/2, (height - size)/2, size);
396 else
397 gtk_render_arrow (context, cr, G_PI,
398 (width - size)/2, (height - size)/2, size);
399
400 return TRUE;
401}
402
403
404gboolean
405gnc_gdate_in_valid_range (GDate *test_date, gboolean warn)
406{
407 gboolean use_autoreadonly = qof_book_uses_autoreadonly (gnc_get_current_book());
408 GDate *max_date = g_date_new_dmy (1,1,10000);
409 GDate *min_date;
410 gboolean ret = FALSE;
411 gboolean max_date_ok = FALSE;
412 gboolean min_date_ok = FALSE;
413
414 if (use_autoreadonly)
415 min_date = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
416 else
417 min_date = g_date_new_dmy (1,1,1400);
418
419 // max date
420 if (g_date_compare (max_date, test_date) > 0)
421 max_date_ok = TRUE;
422
423 // min date
424 if (g_date_compare (min_date, test_date) <= 0)
425 min_date_ok = TRUE;
426
427 if (use_autoreadonly && warn)
428 ret = max_date_ok;
429 else
430 ret = min_date_ok & max_date_ok;
431
432 if (warn && !ret)
433 {
434 // Translators: Use your locale date format here!
435 gchar *dialog_msg = _("The entered date is out of the range "
436 "01/01/1400 - 31/12/9999, resetting to this year");
437 gchar *dialog_title = _("Date out of range");
438 GtkWidget *dialog = gtk_message_dialog_new (gnc_ui_get_main_window (NULL),
439 0,
440 GTK_MESSAGE_ERROR,
441 GTK_BUTTONS_OK,
442 "%s", dialog_title);
443 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
444 "%s", dialog_msg);
445 gtk_dialog_run (GTK_DIALOG(dialog));
446 gtk_widget_destroy (dialog);
447 }
448 g_date_free (max_date);
449 g_date_free (min_date);
450 return ret;
451}
452
453
454gboolean
455gnc_handle_date_accelerator (GdkEventKey *event,
456 struct tm *tm,
457 const char *date_str)
458{
459 GDate gdate;
460
461 g_return_val_if_fail (event != NULL, FALSE);
462 g_return_val_if_fail (tm != NULL, FALSE);
463 g_return_val_if_fail (date_str != NULL, FALSE);
464
465 if (event->type != GDK_KEY_PRESS)
466 return FALSE;
467
468 if ((tm->tm_mday <= 0) || (tm->tm_mon == -1) || (tm->tm_year == -1))
469 return FALSE;
470
471 // Make sure we have a valid date before we proceed
472 if (!g_date_valid_dmy (tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900))
473 return FALSE;
474
475 g_date_set_dmy (&gdate,
476 tm->tm_mday,
477 tm->tm_mon + 1,
478 tm->tm_year + 1900);
479
480 /*
481 * Check those keys where the code does different things depending
482 * upon the modifiers.
483 */
484 switch (event->keyval)
485 {
486 case GDK_KEY_KP_Add:
487 case GDK_KEY_plus:
488 case GDK_KEY_equal:
489 case GDK_KEY_semicolon: // See https://bugs.gnucash.org/show_bug.cgi?id=798386
490 if (event->state & GDK_SHIFT_MASK)
491 g_date_add_days (&gdate, 7);
492 else if (event->state & GDK_MOD1_MASK)
493 g_date_add_months (&gdate, 1);
494 else if (event->state & GDK_CONTROL_MASK)
495 g_date_add_years (&gdate, 1);
496 else
497 g_date_add_days (&gdate, 1);
498
499 if (gnc_gdate_in_valid_range (&gdate, FALSE))
500 g_date_to_struct_tm (&gdate, tm);
501 return TRUE;
502
503 case GDK_KEY_minus:
504 case GDK_KEY_KP_Subtract:
505 case GDK_KEY_underscore:
506 if ((strlen (date_str) != 0) && (dateSeparator () == '-'))
507 {
508 const char *c;
509 gunichar uc;
510 int count = 0;
511
512 /* rough check for existing date */
513 c = date_str;
514 while (*c)
515 {
516 uc = g_utf8_get_char (c);
517 if (uc == '-')
518 count++;
519 c = g_utf8_next_char (c);
520 }
521
522 if (count < 2)
523 return FALSE;
524 }
525
526 if (event->state & GDK_SHIFT_MASK)
527 g_date_subtract_days (&gdate, 7);
528 else if (event->state & GDK_MOD1_MASK)
529 g_date_subtract_months (&gdate, 1);
530 else if (event->state & GDK_CONTROL_MASK)
531 g_date_subtract_years (&gdate, 1);
532 else
533 g_date_subtract_days (&gdate, 1);
534
535 if (gnc_gdate_in_valid_range (&gdate, FALSE))
536 g_date_to_struct_tm (&gdate, tm);
537 return TRUE;
538
539 default:
540 break;
541 }
542
543 /*
544 * Control and Alt key combinations should be ignored by this
545 * routine so that the menu system gets to handle them. This
546 * prevents weird behavior of the menu accelerators (i.e. work in
547 * some widgets but not others.)
548 */
549 if (event->state & (GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK))
550 return FALSE;
551
552 /* Now check for the remaining keystrokes. */
553 switch (event->keyval)
554 {
555 case GDK_KEY_braceright:
556 case GDK_KEY_bracketright:
557 /* increment month */
558 g_date_add_months (&gdate, 1);
559 break;
560
561 case GDK_KEY_braceleft:
562 case GDK_KEY_bracketleft:
563 /* decrement month */
564 g_date_subtract_months (&gdate, 1);
565 break;
566
567 case GDK_KEY_M:
568 case GDK_KEY_m:
569 /* beginning of month */
570 g_date_set_day (&gdate, 1);
571 break;
572
573 case GDK_KEY_H:
574 case GDK_KEY_h:
575 /* end of month */
576 g_date_set_day (&gdate, 1);
577 g_date_add_months (&gdate, 1);
578 g_date_subtract_days (&gdate, 1);
579 break;
580
581 case GDK_KEY_Y:
582 case GDK_KEY_y:
583 /* beginning of year */
584 g_date_set_day (&gdate, 1);
585 g_date_set_month (&gdate, 1);
586 break;
587
588 case GDK_KEY_R:
589 case GDK_KEY_r:
590 /* end of year */
591 g_date_set_day (&gdate, 1);
592 g_date_set_month (&gdate, 1);
593 g_date_add_years (&gdate, 1);
594 g_date_subtract_days (&gdate, 1);
595 break;
596
597 case GDK_KEY_T:
598 case GDK_KEY_t:
599 /* today */
600 gnc_gdate_set_today (&gdate);
601 break;
602
603 default:
604 return FALSE;
605 }
606 if (gnc_gdate_in_valid_range (&gdate, FALSE))
607 g_date_to_struct_tm (&gdate, tm);
608
609 return TRUE;
610}
611
612
613/*--------------------------------------------------------------------------
614 * GtkBuilder support functions
615 *-------------------------------------------------------------------------*/
616
617GModule *allsymbols = NULL;
618
619/* gnc_builder_add_from_file:
620 *
621 * a convenience wrapper for gtk_builder_add_objects_from_file.
622 * It takes care of finding the directory for glade files and prints a
623 * warning message in case of an error.
624 */
625gboolean
626gnc_builder_add_from_file (GtkBuilder *builder, const char *filename, const char *root)
627{
628 GError* error = NULL;
629 char *fname;
630 gchar *gnc_builder_dir;
631 gboolean result;
632
633 g_return_val_if_fail (builder != NULL, FALSE);
634 g_return_val_if_fail (filename != NULL, FALSE);
635 g_return_val_if_fail (root != NULL, FALSE);
636
637 gnc_builder_dir = gnc_path_get_gtkbuilderdir ();
638 fname = g_build_filename(gnc_builder_dir, filename, (char *)NULL);
639 g_free (gnc_builder_dir);
640
641 {
642 gchar *localroot = g_strdup(root);
643 gchar *objects[] = { localroot, NULL };
644 result = gtk_builder_add_objects_from_file (builder, fname, objects, &error);
645 if (!result)
646 {
647 PWARN ("Couldn't load builder file: %s", error->message);
648 g_error_free (error);
649 }
650 g_free (localroot);
651 }
652
653 g_free (fname);
654
655 return result;
656}
657
658
659/*---------------------------------------------------------------------
660 * The following function is built from a couple of glade functions.
661 *--------------------------------------------------------------------*/
662void
663gnc_builder_connect_full_func(GtkBuilder *builder,
664 GObject *signal_object,
665 const gchar *signal_name,
666 const gchar *handler_name,
667 GObject *connect_object,
668 GConnectFlags flags,
669 gpointer user_data)
670{
671 GCallback func;
672 GCallback *p_func = &func;
673
674 if (allsymbols == NULL)
675 {
676 /* get a handle on the main executable -- use this to find symbols */
677 allsymbols = g_module_open(NULL, 0);
678 }
679
680 if (!g_module_symbol(allsymbols, handler_name, (gpointer *)p_func))
681 {
682#ifdef HAVE_DLSYM
683 /* Fallback to dlsym -- necessary for *BSD linkers */
684 func = dlsym(RTLD_DEFAULT, handler_name);
685#else
686 func = NULL;
687#endif
688 if (func == NULL)
689 {
690 PWARN("ggaff: could not find signal handler '%s'.", handler_name);
691 return;
692 }
693 }
694
695 if (connect_object)
696 g_signal_connect_object (signal_object, signal_name, func,
697 connect_object, flags);
698 else
699 g_signal_connect_data(signal_object, signal_name, func,
700 user_data, NULL , flags);
701}
702/*--------------------------------------------------------------------------
703 * End of GtkBuilder utilities
704 *-------------------------------------------------------------------------*/
705
706
707void
708gnc_gtk_dialog_add_button (GtkWidget *dialog, const gchar *label, const gchar *icon_name, guint response)
709{
710 GtkWidget *button;
711
712 button = gtk_button_new_with_mnemonic(label);
713 if (icon_name)
714 {
715 GtkWidget *image;
716
717 image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
718 gtk_button_set_image (GTK_BUTTON(button), image);
719 g_object_set (button, "always-show-image", TRUE, NULL);
720 }
721 g_object_set (button, "can-default", TRUE, NULL);
722 gtk_widget_show_all(button);
723 gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, response);
724}
725
726static void
727gnc_perm_button_cb (GtkButton *perm, gpointer user_data)
728{
729 gboolean perm_active;
730
731 perm_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(perm));
732 gtk_widget_set_sensitive(user_data, !perm_active);
733}
734
735gint
736gnc_dialog_run (GtkDialog *dialog, const gchar *pref_name)
737{
738 GtkWidget *perm, *temp;
739 gboolean ask = TRUE;
740 gint response;
741
742 /* Does the user want to see this question? If not, return the
743 * previous answer. */
744 response = gnc_prefs_get_int(GNC_PREFS_GROUP_WARNINGS_PERM, pref_name);
745 if (response != 0)
746 return response;
747 response = gnc_prefs_get_int(GNC_PREFS_GROUP_WARNINGS_TEMP, pref_name);
748 if (response != 0)
749 return response;
750
751 /* Add in the checkboxes to find out if the answer should be remembered. */
752 if (GTK_IS_MESSAGE_DIALOG(dialog))
753 {
754 GtkMessageType type;
755 g_object_get(dialog, "message-type", &type, (gchar*)NULL);
756 ask = (type == GTK_MESSAGE_QUESTION || type == GTK_MESSAGE_WARNING);
757 }
758 perm = gtk_check_button_new_with_mnemonic
759 (ask
760 ? _("Remember and don't _ask me again.")
761 : _("Don't _tell me again."));
762 temp = gtk_check_button_new_with_mnemonic
763 (ask
764 ? _("Remember and don't ask me again this _session.")
765 : _("Don't tell me again this _session."));
766 gtk_widget_show(perm);
767 gtk_widget_show(temp);
768 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (dialog)), perm, TRUE, TRUE, 0);
769 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (dialog)), temp, TRUE, TRUE, 0);
770 g_signal_connect(perm, "clicked", G_CALLBACK(gnc_perm_button_cb), temp);
771
772 /* OK. Present the dialog. */
773 GtkWidget *button_cancel = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
774 gtk_widget_grab_focus(button_cancel);
775 response = gtk_dialog_run(dialog);
776 if ((response == GTK_RESPONSE_NONE) || (response == GTK_RESPONSE_DELETE_EVENT))
777 {
778 return GTK_RESPONSE_CANCEL;
779 }
780
781 if (response != GTK_RESPONSE_CANCEL)
782 {
783 /* Save the answer? */
784 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(perm)))
785 {
786 gnc_prefs_set_int(GNC_PREFS_GROUP_WARNINGS_PERM, pref_name, response);
787 }
788 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(temp)))
789 {
790 gnc_prefs_set_int(GNC_PREFS_GROUP_WARNINGS_TEMP, pref_name, response);
791 }
792 }
793 return response;
794}
795
796/* If this is a new book, this function can be used to display book options
797 * dialog so user can specify options, before any transactions can be
798 * imported/entered, since the book options can affect how transactions are
799 * created. Note: This dialog is modal! */
800gboolean
801gnc_new_book_option_display (GtkWidget *parent)
802{
803 GtkWidget *window;
804 gint result = GTK_RESPONSE_HELP;
805
806 window = gnc_book_options_dialog_cb (TRUE, _( "New Book Options"),
807 GTK_WINDOW (parent));
808 if (window)
809 {
810 /* close dialog and proceed unless help button selected */
811 while (result == GTK_RESPONSE_HELP)
812 {
813 result = gtk_dialog_run(GTK_DIALOG(window));
814 }
815 return FALSE;
816 }
817 return TRUE;
818}
819
820gchar*
821gnc_get_negative_color (void)
822{
823 GdkRGBA color;
824 GtkWidget *label = gtk_label_new ("Color");
825 GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(label));
826 gtk_style_context_add_class (context, "gnc-class-negative-numbers");
827 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
828
829 return gdk_rgba_to_string (&color);
830}
831
832void
833gnc_owner_window_set_title (GtkWindow *window, const char *header,
834 GtkWidget *owner_entry, GtkWidget *id_entry)
835{
836 const char *name = gtk_entry_get_text (GTK_ENTRY (owner_entry));
837 if (!name || *name == '\0')
838 name = _("<No name>");
839
840 const char *id = gtk_entry_get_text (GTK_ENTRY (id_entry));
841
842 char *title = (id && *id) ?
843 g_strdup_printf ("%s - %s (%s)", header, name, id) :
844 g_strdup_printf ("%s - %s", header, name);
845
846 gtk_window_set_title (window, title);
847
848 g_free (title);
849}
Commodity handling public routines.
Date and Time handling routines.
All type declarations for the whole Gnucash engine.
Functions for adding content to a window.
Generic api to store and retrieve preferences.
utility functions for the GnuCash UI
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition qofbook.cpp:1006
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition qofbook.cpp:974
char dateSeparator(void)
dateSeparator Return the field separator for the current date format
Definition gnc-date.cpp:999
void gnc_gdate_set_today(GDate *gd)
Set a GDate to the current day.
GtkWidget * gnc_book_options_dialog_cb(gboolean modal, gchar *title, GtkWindow *parent)
Opens the Book Options dialog.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Get an integer value from the preferences backend.
GVariant * gnc_prefs_get_value(const gchar *group, const gchar *pref_name)
Get an arbitrary combination of values from the preferences backend.
gboolean gnc_prefs_set_value(const gchar *group, const gchar *pref_name, GVariant *value)
Store an arbitrary combination of values into the preferences backend.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Store an integer value into the preferences backend.