From 07f3f536cc09209308c1b6c011a2ba684e24f1ae Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Wed, 1 Feb 2023 16:26:38 +0000 Subject: [PATCH] Allow to select saved report on print invoice button This change was inspired by mildred's #PR1247 and uses the new GncReportCombo to allow selection of 'Saved Invoice reports' when the invoice print button is used or when printing multiple invoices. This change presents a dialog with the default for the report combo set to the properties setting. This dialog has a timeout which is adjustable under properties and will stop if a key is pressed or combo popped so that a different report template can be selected and used. There is also an 'OK' button that stops the time out and prints and a 'Cancel' button which cancels the print. --- gnucash/gnome/dialog-invoice.c | 185 ++++++++++++++++++++++-- gnucash/gtkbuilder/dialog-invoice.glade | 127 ++++++++++++++++ libgnucash/engine/gnc-optiondb.cpp | 6 +- libgnucash/engine/qofbook.cpp | 15 ++ libgnucash/engine/qofbook.h | 5 + libgnucash/engine/qofbookslots.h | 1 + 6 files changed, 328 insertions(+), 11 deletions(-) diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c index aeca0844ee..786da96556 100644 --- a/gnucash/gnome/dialog-invoice.c +++ b/gnucash/gnome/dialog-invoice.c @@ -79,6 +79,7 @@ #include "dialog-doclink-utils.h" #include "dialog-transfer.h" #include "gnc-uri-utils.h" +#include "gnc-report-combo.h" #define DIALOG_NEW_INVOICE_CM_CLASS "dialog-new-invoice" #define DIALOG_VIEW_INVOICE_CM_CLASS "dialog-view-invoice" @@ -778,15 +779,159 @@ gnc_invoice_window_blankCB (GtkWidget *widget, gpointer data) } } +typedef struct dialog_args +{ + GtkProgressBar *pb; + GtkWidget *dialog; + gdouble timeout; +} dialog_args; + +static gboolean +update_progress_bar (gpointer user_data) +{ + dialog_args *args = user_data; + GtkProgressBar *pb = args->pb; + gdouble frac = gtk_progress_bar_get_fraction (pb); + gdouble step = 0.1 / (args->timeout); + + frac -= step; + + if (frac < step) + { + gtk_dialog_response (GTK_DIALOG(args->dialog), GTK_RESPONSE_OK); + return FALSE; + } + gtk_progress_bar_set_fraction (pb, frac); + return TRUE; +} + +static void +combo_popped_cb (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + gboolean popup_shown; + + g_object_get (G_OBJECT(gobject), "popup-shown", &popup_shown, NULL); + + if (popup_shown) + g_source_remove_by_user_data (user_data); +} + +static gboolean +dialog_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + g_source_remove_by_user_data (user_data); + return FALSE; +} + +static void +combo_changed_cb (GtkComboBox *widget, gpointer user_data) +{ + g_source_remove_by_user_data (user_data); +} + +/* This function will return the selected invoice report guid if + * the countdown times out or a selection is made and OK pressed. + * + * If cancel is pressed then it return a NULL + */ +static char* +use_default_report_template_or_change (GtkWindow *parent) +{ + QofBook *book = gnc_get_current_book (); + GtkWidget *combo; + GtkBuilder *builder; + GtkWidget *dialog; + GtkWidget *ok_button; + GtkWidget *report_combo_hbox; + GtkWidget *progress_bar; + gchar *ret_guid = NULL; + gchar *rep_guid = NULL; + gchar *rep_name = NULL; + gint result; + gdouble timeout; + dialog_args *args; + + timeout = qof_book_get_default_invoice_report_timeout (book); + + if (timeout == 0) + return gnc_get_default_invoice_print_report (); + + combo = gnc_default_invoice_report_combo ("gnc:custom-report-invoice-template-guids"); + + builder = gtk_builder_new (); + gnc_builder_add_from_file (builder, "dialog-invoice.glade", "invoice_print_dialog"); + + dialog = GTK_WIDGET(gtk_builder_get_object (builder, "invoice_print_dialog")); + + gtk_window_set_transient_for (GTK_WINDOW(dialog), parent); + + gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + ok_button = GTK_WIDGET(gtk_builder_get_object (builder, "ok_button")); + report_combo_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "report_combo_hbox")); + progress_bar = GTK_WIDGET(gtk_builder_get_object (builder, "progress_bar")); + + gtk_box_pack_start (GTK_BOX(report_combo_hbox), GTK_WIDGET(combo), TRUE, TRUE, 0); + + gtk_widget_grab_focus (ok_button); + + rep_name = qof_book_get_default_invoice_report_name (book); + rep_guid = gnc_get_default_invoice_print_report (); + + gnc_report_combo_set_active (GNC_REPORT_COMBO(combo), + rep_guid, + rep_name); + g_free (rep_guid); + g_free (rep_name); + + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar), 1); + + args = g_malloc (sizeof(dialog_args)); + args->dialog = dialog; + args->pb = GTK_PROGRESS_BAR(progress_bar); + args->timeout = timeout; + + gtk_widget_show_all (dialog); + + g_object_unref (G_OBJECT(builder)); + + g_signal_connect (G_OBJECT(combo), "changed", + G_CALLBACK(combo_changed_cb), args); + + g_signal_connect (G_OBJECT(dialog), "key_press_event", + G_CALLBACK(dialog_key_press_event_cb), args); + + g_signal_connect (G_OBJECT(combo), "notify::popup-shown", + G_CALLBACK (combo_popped_cb), args); + + g_timeout_add (100, update_progress_bar, args); + + result = gtk_dialog_run (GTK_DIALOG(dialog)); + + g_source_remove_by_user_data (args); + + if (result == GTK_RESPONSE_OK) + ret_guid = gnc_report_combo_get_active_guid (GNC_REPORT_COMBO(combo)); + + gtk_widget_destroy (dialog); + g_free (args); + + return ret_guid; +} + static GncPluginPage * -gnc_invoice_window_print_invoice(GtkWindow *parent, GncInvoice *invoice) +gnc_invoice_window_print_invoice (GtkWindow *parent, GncInvoice *invoice, + const gchar *report_guid) { SCM func, arg, arg2; SCM args = SCM_EOL; SCM is_invoice_guid; SCM scm_guid; int report_id; - char *report_guid = gnc_get_default_invoice_print_report (); + const gchar *use_report_guid = NULL; GncPluginPage *reportPage = NULL; g_return_val_if_fail (invoice, NULL); @@ -795,13 +940,15 @@ gnc_invoice_window_print_invoice(GtkWindow *parent, GncInvoice *invoice) scm_guid = scm_from_utf8_string (report_guid); if (scm_is_false (scm_call_1 (is_invoice_guid, scm_guid))) - report_guid = g_strdup (gnc_get_builtin_default_invoice_print_report ()); // fallback if the option lookup failed + use_report_guid = gnc_get_builtin_default_invoice_print_report (); // fallback if the option lookup failed + else + use_report_guid = report_guid; func = scm_c_eval_string ("gnc:invoice-report-create"); g_return_val_if_fail (scm_is_procedure (func), NULL); arg = SWIG_NewPointerObj(invoice, SWIG_TypeQuery("_p__gncInvoice"), 0); - arg2 = scm_from_utf8_string (report_guid); + arg2 = scm_from_utf8_string (use_report_guid); args = scm_cons2 (arg, arg2, args); /* scm_gc_protect_object(func); */ @@ -816,7 +963,6 @@ gnc_invoice_window_print_invoice(GtkWindow *parent, GncInvoice *invoice) reportPage = gnc_plugin_page_report_new (report_id); gnc_main_window_open_page (GNC_MAIN_WINDOW (parent), reportPage); } - g_free (report_guid); return reportPage; } @@ -841,9 +987,17 @@ gnc_invoice_window_printCB (GtkWindow* parent, gpointer data) iw->reportPage)) gnc_plugin_page_report_reload (GNC_PLUGIN_PAGE_REPORT (iw->reportPage)); else - iw->reportPage = gnc_invoice_window_print_invoice - (parent, iw_get_invoice (iw)); + { + gchar *report_guid = use_default_report_template_or_change (parent); + if (!report_guid) + return; + + iw->reportPage = gnc_invoice_window_print_invoice (parent, + iw_get_invoice (iw), + report_guid); + g_free (report_guid); + } gnc_main_window_open_page (GNC_MAIN_WINDOW (iw->dialog), iw->reportPage); } @@ -3104,8 +3258,9 @@ edit_invoice_cb (GtkWindow *dialog, gpointer inv, gpointer user_data) struct multi_edit_invoice_data { - gpointer user_data; + gpointer user_data; GtkWindow *parent; + gchar *report_guid; }; static void @@ -3272,27 +3427,37 @@ multi_post_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_dat static void print_one_invoice_cb(GtkWindow *dialog, gpointer data, gpointer user_data) { GncInvoice *invoice = data; - gnc_invoice_window_print_invoice (dialog, invoice); + struct multi_edit_invoice_data *meid = user_data; + gnc_invoice_window_print_invoice (dialog, invoice, meid->report_guid); } static void multi_print_invoice_one (gpointer data, gpointer user_data) { struct multi_edit_invoice_data *meid = user_data; - print_one_invoice_cb (gnc_ui_get_main_window (GTK_WIDGET(meid->parent)), data, meid->user_data); + print_one_invoice_cb (gnc_ui_get_main_window (GTK_WIDGET(meid->parent)), data, meid); } static void multi_print_invoice_cb (GtkWindow *dialog, GList *invoice_list, gpointer user_data) { + gchar *report_guid = NULL; struct multi_edit_invoice_data meid; if (!gnc_list_length_cmp (invoice_list, 0)) return; + report_guid = use_default_report_template_or_change (dialog); + + if (!report_guid) + return; + meid.user_data = user_data; meid.parent = dialog; + meid.report_guid = report_guid; + g_list_foreach (invoice_list, multi_print_invoice_one, &meid); + g_free (report_guid); } static gpointer diff --git a/gnucash/gtkbuilder/dialog-invoice.glade b/gnucash/gtkbuilder/dialog-invoice.glade index 9e42c84d65..eba6cd0fbd 100644 --- a/gnucash/gtkbuilder/dialog-invoice.glade +++ b/gnucash/gtkbuilder/dialog-invoice.glade @@ -628,6 +628,133 @@ + + False + Report template + dialog + + + False + vertical + 2 + + + False + end + + + _Cancel + True + True + False + True + + + True + True + 0 + + + + + _OK + True + True + True + True + True + True + True + + + True + True + 1 + + + + + False + False + 0 + + + + + True + False + 6 + 6 + 6 + vertical + 6 + + + True + False + Use template report + + + False + True + 0 + + + + + True + False + 6 + 6 + + + + + + False + True + 1 + + + + + True + False + Choose a different report template before timeout + + + False + True + 2 + + + + + True + False + 24 + 24 + + + False + True + 3 + + + + + False + True + 1 + + + + + + cancel_button + ok_button + + diff --git a/libgnucash/engine/gnc-optiondb.cpp b/libgnucash/engine/gnc-optiondb.cpp index a3bd62990a..cb13ed7b93 100644 --- a/libgnucash/engine/gnc-optiondb.cpp +++ b/libgnucash/engine/gnc-optiondb.cpp @@ -1277,9 +1277,13 @@ gnc_option_db_book_options(GncOptionDB* odb) N_("The ID for your company (eg 'Tax-ID: 00-000000)."), empty_string); gnc_register_invoice_print_report_option(odb, business_section, - OPTION_NAME_DEFAULT_INVOICE_REPORT, "e", + OPTION_NAME_DEFAULT_INVOICE_REPORT, "e1", N_("The invoice report to be used for printing."), empty_string); + gnc_register_number_range_option(odb, business_section, + OPTION_NAME_DEFAULT_INVOICE_REPORT_TIMEOUT, "e2", + N_("Length of time to change the used invoice report. A value of 0 means disabled."), + 0.0, 0.0, 10.0, 1.0); gnc_register_taxtable_option(odb, business_section, N_("Default Customer TaxTable"), "f1", N_("The default tax table to apply to customers."), diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp index d2a9a76ec3..f34c1d5799 100644 --- a/libgnucash/engine/qofbook.cpp +++ b/libgnucash/engine/qofbook.cpp @@ -1098,6 +1098,21 @@ qof_book_get_default_invoice_report_name (const QofBook *book) return report_name; } +gdouble +qof_book_get_default_invoice_report_timeout (const QofBook *book) +{ + double ret = 0; + KvpFrame *root = qof_instance_get_slots (QOF_INSTANCE(book)); + KvpValue *value = root->get_slot ({KVP_OPTION_PATH, + OPTION_SECTION_BUSINESS, + OPTION_NAME_DEFAULT_INVOICE_REPORT_TIMEOUT}); + + if (value) + ret = {value->get()}; + + return ret; +} + /* Note: this will fail if the book slots we're looking for here are flattened at some point ! * When that happens, this function can be removed. */ static Path opt_name_to_path (const char* opt_name) diff --git a/libgnucash/engine/qofbook.h b/libgnucash/engine/qofbook.h index 3ab6c09533..dc52cf4aad 100644 --- a/libgnucash/engine/qofbook.h +++ b/libgnucash/engine/qofbook.h @@ -305,6 +305,11 @@ gchar * qof_book_get_default_invoice_report_guid (const QofBook *book); */ gchar * qof_book_get_default_invoice_report_name (const QofBook *book); +/** Get the length of time available to change the used Invoice Report + * when printing Invoices + */ +gdouble qof_book_get_default_invoice_report_timeout (const QofBook *book); + /** Returns TRUE if this book uses split action field as the 'Num' field, FALSE * if it uses transaction number field */ gboolean qof_book_use_split_action_for_num_field (const QofBook *book); diff --git a/libgnucash/engine/qofbookslots.h b/libgnucash/engine/qofbookslots.h index ea0e32bcd8..5b9eae8bdb 100644 --- a/libgnucash/engine/qofbookslots.h +++ b/libgnucash/engine/qofbookslots.h @@ -72,6 +72,7 @@ #define OPTION_SECTION_BUSINESS N_("Business") #define OPTION_NAME_DEFAULT_INVOICE_REPORT N_("Default Invoice Report") +#define OPTION_NAME_DEFAULT_INVOICE_REPORT_TIMEOUT N_("Default Invoice Report Timeout") /** @} */