GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-report-combo.c
1/********************************************************************\
2 * gnc-report-combo.c -- report select widget for GnuCash *
3 * *
4 * Copyright (C) 2022 Bob Fewell *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23\********************************************************************/
24
25#include <config.h>
26#include <gtk/gtk.h>
27#include <glib/gi18n.h>
28
29#include "gnc-report-combo.h"
30#include "gnc-ui-util.h"
31#include "gnc-engine.h"
32#include "dialog-utils.h"
33
35__attribute__((unused)) static QofLogModule log_module = GNC_MOD_GUI;
36
37static void gnc_report_combo_dispose (GObject *object);
38static void gnc_report_combo_finalize (GObject *object);
39
40#define GNC_REPORT_COMBO_PATH "gnc-report-combo-path"
41
42enum
43{
44 RC_NAME,
45 RC_GUID,
46 RC_MISSING
47};
48
50{
51 GtkBox box;
52
53 GtkWidget *combo;
54 GtkWidget *warning_image;
55
56 const gchar *rpt_guids;
57
58 gboolean block_signal;
59 gboolean popup_shown;
60
61 gchar *active_report_guid;
62 gchar *active_report_name;
63
64};
65
66G_DEFINE_TYPE(GncReportCombo, gnc_report_combo, GTK_TYPE_BOX)
67
68enum
69{
70 SIGNAL_0,
71 CHANGED,
72 LAST_SIGNAL
73};
74
75static guint report_combo_signals [LAST_SIGNAL] = {0};
76
77enum
78{
79 PROP_0,
80 PROP_POPUP_SHOWN,
81 N_PROPERTIES
82};
83
84static GParamSpec *report_combo_properties [N_PROPERTIES] = {NULL,};
85
86static void
87gnc_report_combo_get_property (GObject *object,
88 guint property_id,
89 GValue *value,
90 GParamSpec *pspec)
91{
92 GncReportCombo *grc = GNC_REPORT_COMBO(object);
93
94 switch (property_id)
95 {
96 case PROP_POPUP_SHOWN:
97 g_value_set_boolean (value, grc->popup_shown);
98 break;
99
100 default:
101 /* We don't have any other property... */
102 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
103 break;
104 }
105}
106
113static void
114gnc_report_combo_class_init (GncReportComboClass *klass)
115{
116 GObjectClass *object_class = G_OBJECT_CLASS(klass);
117
118 object_class->get_property = gnc_report_combo_get_property;
119 object_class->dispose = gnc_report_combo_dispose;
120 object_class->finalize = gnc_report_combo_finalize;
121
122 report_combo_signals [CHANGED] =
123 g_signal_new ("changed",
124 G_OBJECT_CLASS_TYPE(object_class),
125 G_SIGNAL_RUN_FIRST,
126 0,
127 NULL,
128 NULL,
129 g_cclosure_marshal_VOID__VOID,
130 G_TYPE_NONE,
131 0);
132
133 report_combo_properties [PROP_POPUP_SHOWN] =
134 g_param_spec_boolean ("popup-shown",
135 "State of PopUp",
136 "State of PopUp",
137 FALSE /* default value */,
138 G_PARAM_READABLE);
139
140 g_object_class_install_properties (object_class,
141 N_PROPERTIES,
142 report_combo_properties);
143}
144
151static void
152gnc_report_combo_init (GncReportCombo *grc)
153{
154 g_return_if_fail (grc != NULL);
155 g_return_if_fail (GNC_IS_REPORT_COMBO(grc));
156
157 // Set the name for this widget so it can be easily manipulated with css
158 gtk_widget_set_name (GTK_WIDGET(grc), "gnc-id-report-combo");
159
160 grc->block_signal = FALSE;
161 grc->active_report_guid = NULL;
162 grc->active_report_name = NULL;
163 grc->popup_shown = FALSE;
164}
165
176static void
177gnc_report_combo_dispose (GObject *object)
178{
179 /* Do not free the private data structure itself. It is part of
180 * a larger memory block allocated by the type system. */
181
182 G_OBJECT_CLASS (gnc_report_combo_parent_class)->dispose (object);
183}
184
195static void
196gnc_report_combo_finalize (GObject *object)
197{
198 GncReportCombo *grc;
199
200 g_return_if_fail (object != NULL);
201 g_return_if_fail (GNC_IS_REPORT_COMBO(object));
202
203 grc = GNC_REPORT_COMBO(object);
204
205 g_free (grc->active_report_guid);
206 g_free (grc->active_report_name);
207
208 G_OBJECT_CLASS (gnc_report_combo_parent_class)->finalize (object);
209}
210
221static gboolean
222select_active_and_check_exists (GncReportCombo *grc)
223{
224 GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(grc->combo));
225 GtkTreeIter iter;
226 gboolean valid_iter = gtk_tree_model_get_iter_first (model, &iter);
227 gchar *tmp;
228
229 while (valid_iter)
230 {
231 gchar *guid;
232 gtk_tree_model_get (model, &iter, RC_GUID, &guid, -1);
233
234 if (g_strcmp0 (grc->active_report_guid, guid) == 0)
235 {
236 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(grc->combo), &iter);
237 g_free (guid);
238 return TRUE;
239 }
240 g_free (guid);
241 valid_iter = gtk_tree_model_iter_next (model, &iter);
242 }
243
244 if (grc->active_report_name)
245 tmp = g_strdup (grc->active_report_name);
246 else
247 tmp = g_strdup (_("Selected Report is Missing"));
248
249 gtk_list_store_prepend (GTK_LIST_STORE(model), &iter);
250 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
251 RC_NAME, tmp,
252 RC_GUID, grc->active_report_guid,
253 RC_MISSING, TRUE,
254 -1);
255
256 g_free (tmp);
257 gtk_combo_box_set_active_iter (GTK_COMBO_BOX(grc->combo), &iter);
258 return FALSE;
259}
260
261static void
262update_report_list (GncReportCombo *grc, GSList *report_list)
263{
264 GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(grc->combo));
265
266 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(model),
267 RC_NAME, GTK_SORT_ASCENDING);
268
269 gtk_list_store_clear (GTK_LIST_STORE(model));
270
271 if (report_list)
272 {
273 GtkTreeIter iter;
274
275 for (GSList* node = report_list; node != NULL; node = g_slist_next (node))
276 {
277 ReportListEntry *rle = node->data;
278
279 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
280 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
281 RC_NAME, rle->report_name,
282 RC_GUID, rle->report_guid,
283 RC_MISSING, FALSE,
284 -1);
285 g_free (rle->report_name);
286 g_free (rle->report_guid);
287 g_free (rle);
288 }
289 }
290 g_slist_free (report_list);
291}
292
293static void
294update_warning_tooltip (GncReportCombo *grc)
295{
296 gchar *tool_tip;
297
298 if (grc->active_report_name)
299 /* Translators: %s is the report name. */
300 tool_tip = g_strdup_printf (_("'%s' is missing"),
301 grc->active_report_name);
302 else
303 /* Translators: %s is the internal report guid. */
304 tool_tip = g_strdup_printf (_("Report with GUID '%s' is missing"),
305 grc->active_report_guid);
306
307 gtk_widget_show (grc->warning_image);
308 gtk_widget_set_tooltip_text (grc->warning_image, tool_tip);
309 g_free (tool_tip);
310}
311
312void
313gnc_report_combo_set_active (GncReportCombo *grc,
314 const char* active_report_guid,
315 const char* active_report_name)
316{
317 g_return_if_fail (grc != NULL);
318 g_return_if_fail (GNC_IS_REPORT_COMBO(grc));
319
320 g_free (grc->active_report_guid);
321
322 grc->active_report_guid = g_strdup (active_report_guid);
323
324 g_free (grc->active_report_name);
325
326 grc->active_report_name = g_strdup (active_report_name);
327
328 grc->block_signal = TRUE;
329
330 if (!select_active_and_check_exists (grc))
331 update_warning_tooltip (grc);
332
333 grc->block_signal = FALSE;
334}
335
336gchar *
337gnc_report_combo_get_active_guid (GncReportCombo *grc)
338{
339 gchar *guid = NULL;
340 GtkTreeIter iter;
341
342 g_return_val_if_fail (grc != NULL, NULL);
343 g_return_val_if_fail (GNC_IS_REPORT_COMBO(grc), NULL);
344
345 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(grc->combo), &iter))
346 {
347 GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(grc->combo));
348 gtk_tree_model_get (model, &iter, RC_GUID, &guid, -1);
349 }
350 return guid;
351}
352
353gchar *
354gnc_report_combo_get_active_name (GncReportCombo *grc)
355{
356 gchar *name = NULL;
357 GtkTreeIter iter;
358
359 g_return_val_if_fail (grc != NULL, NULL);
360 g_return_val_if_fail (GNC_IS_REPORT_COMBO(grc), NULL);
361
362 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(grc->combo), &iter))
363 {
364 GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(grc->combo));
365 gtk_tree_model_get (model, &iter, RC_NAME, &name, -1);
366 }
367 return name;
368}
369
370gchar*
371gnc_report_combo_get_active_guid_name (GncReportCombo *grc)
372{
373 gchar *report = NULL;
374 GtkTreeIter iter;
375
376 g_return_val_if_fail (grc != NULL, NULL);
377 g_return_val_if_fail (GNC_IS_REPORT_COMBO(grc), NULL);
378
379 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(grc->combo), &iter))
380 {
381 GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(grc->combo));
382 gchar *report_guid;
383 gchar *report_name;
384 gtk_tree_model_get (model, &iter, RC_NAME, &report_name,
385 RC_GUID, &report_guid,
386 -1);
387
388 report = g_strconcat (report_guid, "/", report_name, NULL);
389 g_free (report_guid);
390 g_free (report_name);
391 }
392 return report;
393}
394
395void
396gnc_report_combo_set_active_guid_name (GncReportCombo *grc,
397 const gchar *guid_name)
398{
399 g_return_if_fail (grc != NULL);
400 g_return_if_fail (GNC_IS_REPORT_COMBO(grc));
401
402 if (guid_name && *guid_name)
403 {
404 gchar *guid = NULL;
405 gchar *name = g_strstr_len (guid_name, -1, "/");
406
407 if (name)
408 {
409 guid = g_strndup (guid_name, (name - guid_name));
410 gnc_report_combo_set_active (grc, guid, name + 1);
411 }
412 g_free (guid);
413 }
414}
415
416gboolean
417gnc_report_combo_is_warning_visible_for_active (GncReportCombo *grc)
418{
419 g_return_val_if_fail (grc != NULL, FALSE);
420 g_return_val_if_fail (GNC_IS_REPORT_COMBO(grc), FALSE);
421
422 return gtk_widget_is_visible (GTK_WIDGET(grc->warning_image));
423}
424
425static void
426combo_changed_cb (GtkComboBox *widget, gpointer user_data)
427{
428 GncReportCombo *grc = GNC_REPORT_COMBO(user_data);
429 GtkTreeIter iter;
430
431 if (gtk_combo_box_get_active_iter (widget, &iter))
432 {
433 GtkTreeModel *model = gtk_combo_box_get_model (widget);
434 gboolean missing;
435 gtk_tree_model_get (model, &iter, RC_MISSING, &missing, -1);
436 // set visibility of the warning image
437 gtk_widget_set_visible (grc->warning_image, missing);
438
439 if (!grc->block_signal)
440 g_signal_emit (grc, report_combo_signals [CHANGED], 0);
441
442 gtk_widget_queue_resize (GTK_WIDGET(widget));
443 }
444}
445
446static void
447combo_popped_cb (GObject *gobject,
448 GParamSpec *pspec,
449 gpointer user_data)
450{
451 GncReportCombo *grc = GNC_REPORT_COMBO(user_data);
452 gboolean popup_shown;
453
454 g_object_get (G_OBJECT(gobject), "popup-shown", &popup_shown, NULL);
455
456 grc->popup_shown = popup_shown;
457 g_object_notify (G_OBJECT(grc), "popup-shown");
458}
459
460void
461gnc_report_combo_refresh (GncReportCombo *grc, GSList *report_list)
462{
463 g_return_if_fail (grc != NULL);
464 g_return_if_fail (GNC_IS_REPORT_COMBO(grc));
465 g_return_if_fail (report_list != NULL);
466
467 grc->block_signal = TRUE;
468
469 update_report_list (grc, report_list);
470
471 if (!select_active_and_check_exists (grc))
472 update_warning_tooltip (grc);
473
474 grc->block_signal = FALSE;
475}
476
477/* Create a new GncReportCombo widget which can be used to select
478 * a report from a GtkComboBox.
479 *
480 * @return A GncReportCombo widget.
481 */
482GtkWidget *
483gnc_report_combo_new (GSList *report_list)
484{
485 GncReportCombo *grc;
486 GtkListStore *store;
487 GtkCellRenderer *renderer;
488
489 store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
490 grc = g_object_new (GNC_TYPE_REPORT_COMBO, NULL);
491
492 grc->combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
493 g_object_unref (store);
494
495 renderer = gtk_cell_renderer_text_new ();
496 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(grc->combo), renderer, TRUE);
497 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(grc->combo), renderer,
498 "text", RC_NAME, NULL);
499
500 gtk_box_pack_start (GTK_BOX(grc), GTK_WIDGET(grc->combo), TRUE, TRUE, 0);
501 grc->warning_image = gtk_image_new_from_icon_name ("dialog-warning",
502 GTK_ICON_SIZE_SMALL_TOOLBAR);
503 gtk_box_pack_start (GTK_BOX(grc), GTK_WIDGET(grc->warning_image), FALSE, FALSE, 6);
504 gtk_widget_set_no_show_all (GTK_WIDGET(grc->warning_image), TRUE);
505 gtk_widget_hide (GTK_WIDGET(grc->warning_image));
506
507 update_report_list (grc, report_list);
508
509 g_signal_connect (G_OBJECT(grc->combo), "changed",
510 G_CALLBACK(combo_changed_cb), grc);
511
512 g_signal_connect (G_OBJECT(grc->combo), "notify::popup-shown",
513 G_CALLBACK(combo_popped_cb), grc);
514
515 gtk_widget_show_all (GTK_WIDGET(grc));
516
517 return GTK_WIDGET(grc);
518}
All type declarations for the whole Gnucash engine.
utility functions for the GnuCash UI