From 30f21763e83048c8d3457d15d3ce4aa23d9ac160 Mon Sep 17 00:00:00 2001 From: Robert Fewell <14uBobIT@gmail.com> Date: Mon, 18 May 2020 16:21:29 +0100 Subject: [PATCH] Allow Associations to be added to invoices Use the existing associations functions to do the updating, opening and removing of the association for invoices and all objects that use the invoice interface. The actual association when present is added as a link button which is shown below the notes. --- gnucash/gnome/dialog-invoice.c | 56 +++++++- gnucash/gnome/dialog-invoice.h | 4 + gnucash/gnome/gnc-plugin-page-invoice.c | 168 ++++++++++++++++++++++ gnucash/gtkbuilder/dialog-invoice.glade | 61 ++++++-- gnucash/ui/gnc-plugin-page-invoice-ui.xml | 5 + 5 files changed, 280 insertions(+), 14 deletions(-) diff --git a/gnucash/gnome/dialog-invoice.c b/gnucash/gnome/dialog-invoice.c index 0e3bf45ee7..903310aedc 100644 --- a/gnucash/gnome/dialog-invoice.c +++ b/gnucash/gnome/dialog-invoice.c @@ -73,7 +73,10 @@ #include "gnc-main-window.h" #include "gnc-state.h" +#include "dialog-assoc.h" +#include "dialog-assoc-utils.h" #include "dialog-transfer.h" +#include "gnc-uri-utils.h" /* Disable -Waddress. GCC 4.2 warns (and fails to compile with -Werror) when * passing the address of a guid on the stack to QOF_BOOK_LOOKUP_ENTITY via @@ -166,6 +169,8 @@ struct _invoice_window GtkWidget * active_check; GtkWidget * paid_label; + GtkWidget * assoc_link_button; + GtkWidget * owner_box; GtkWidget * owner_label; GtkWidget * owner_choice; @@ -229,12 +234,12 @@ static GtkWidget * iw_get_window (InvoiceWindow *iw) { if (iw->page) - return gnc_plugin_page_get_window(iw->page); + return gnc_plugin_page_get_window (iw->page); return iw->dialog; } GtkWidget * -gnc_invoice_get_register(InvoiceWindow *iw) +gnc_invoice_get_register (InvoiceWindow *iw) { if (iw) return (GtkWidget *)iw->reg; @@ -242,7 +247,7 @@ gnc_invoice_get_register(InvoiceWindow *iw) } GtkWidget * -gnc_invoice_get_notes(InvoiceWindow *iw) +gnc_invoice_get_notes (InvoiceWindow *iw) { if (iw) return (GtkWidget *)iw->notes_text; @@ -313,6 +318,24 @@ iw_get_invoice (InvoiceWindow *iw) return gncInvoiceLookup (iw->book, &iw->invoice_guid); } +GncInvoice * +gnc_invoice_window_get_invoice (InvoiceWindow *iw) +{ + if (!iw) + return NULL; + + return iw_get_invoice (iw); +} + +GtkWidget * +gnc_invoice_window_get_assoc_link_button (InvoiceWindow *iw) +{ + if (!iw) + return NULL; + + return iw->assoc_link_button; +} + static void set_gncEntry_switch_type (gpointer data, gpointer user_data) { @@ -2371,6 +2394,15 @@ gnc_invoice_save_page (InvoiceWindow *iw, gnc_table_save_state (table, group_name); } +static gboolean +assoc_link_button_cb (GtkLinkButton *button, InvoiceWindow *iw) +{ + GncInvoice *invoice = gncInvoiceLookup (iw->book, &iw->invoice_guid); + gnc_assoc_open_uri (GTK_WINDOW(iw->dialog), gncInvoiceGetAssociation (invoice)); + + return TRUE; +} + GtkWidget * gnc_invoice_create_page (InvoiceWindow *iw, gpointer page) { @@ -2383,6 +2415,7 @@ gnc_invoice_create_page (InvoiceWindow *iw, gpointer page) const gchar *prefs_group = NULL; gboolean is_credit_note = FALSE; const gchar *style_label = NULL; + const gchar *assoc_uri; invoice = gncInvoiceLookup (iw->book, &iw->invoice_guid); is_credit_note = gncInvoiceGetIsCreditNote (invoice); @@ -2413,6 +2446,23 @@ gnc_invoice_create_page (InvoiceWindow *iw, gpointer page) iw->job_box = GTK_WIDGET (gtk_builder_get_object (builder, "page_job_hbox")); iw->paid_label = GTK_WIDGET (gtk_builder_get_object (builder, "paid_label")); + iw->assoc_link_button = GTK_WIDGET(gtk_builder_get_object (builder, "assoc_link_button")); + g_signal_connect (G_OBJECT(iw->assoc_link_button), "activate-link", + G_CALLBACK(assoc_link_button_cb), iw); + + /* invoice association */ + assoc_uri = gncInvoiceGetAssociation (invoice); + if (assoc_uri) + { + gchar *display_uri = gnc_assoc_get_unescaped_just_uri (assoc_uri); + gtk_button_set_label (GTK_BUTTON(iw->assoc_link_button), _("Open Association:")); + gtk_link_button_set_uri (GTK_LINK_BUTTON(iw->assoc_link_button), display_uri); + gtk_widget_show (GTK_WIDGET (iw->assoc_link_button)); + g_free (display_uri); + } + else + gtk_widget_hide (GTK_WIDGET (iw->assoc_link_button)); + // Add a style context for this label so it can be easily manipulated with css gnc_widget_style_context_add_class (GTK_WIDGET(iw->paid_label), "gnc-class-highlight"); diff --git a/gnucash/gnome/dialog-invoice.h b/gnucash/gnome/dialog-invoice.h index 073268d403..392b5abebc 100644 --- a/gnucash/gnome/dialog-invoice.h +++ b/gnucash/gnome/dialog-invoice.h @@ -77,6 +77,10 @@ gchar *gnc_invoice_get_help (InvoiceWindow *iw); gchar *gnc_invoice_get_title (InvoiceWindow *iw); +GncInvoice * gnc_invoice_window_get_invoice (InvoiceWindow *iw); + +GtkWidget * gnc_invoice_window_get_assoc_link_button (InvoiceWindow *iw); + GncInvoiceType gnc_invoice_get_type_from_window(InvoiceWindow *iw); #ifdef __GNC_PLUGIN_PAGE_H diff --git a/gnucash/gnome/gnc-plugin-page-invoice.c b/gnucash/gnome/gnc-plugin-page-invoice.c index fb74f75a2e..bb8c12e0ea 100644 --- a/gnucash/gnome/gnc-plugin-page-invoice.c +++ b/gnucash/gnome/gnc-plugin-page-invoice.c @@ -40,8 +40,11 @@ #include "gnucash-register.h" #include "gnc-prefs.h" #include "gnc-ui-util.h" +#include "gnc-uri-utils.h" #include "gnc-window.h" #include "dialog-utils.h" +#include "dialog-assoc.h" +#include "dialog-assoc-utils.h" #include "gncInvoice.h" /* This static indicates the debugging module that this .o belongs to. */ @@ -85,6 +88,9 @@ static void gnc_plugin_page_invoice_cmd_duplicateEntry (GtkAction *action, GncPl static void gnc_plugin_page_invoice_cmd_pay_invoice (GtkAction *action, GncPluginPageInvoice *plugin_page); static void gnc_plugin_page_invoice_cmd_save_layout (GtkAction *action, GncPluginPageInvoice *plugin_page); static void gnc_plugin_page_invoice_cmd_reset_layout (GtkAction *action, GncPluginPageInvoice *plugin_page); +static void gnc_plugin_page_invoice_cmd_associate (GtkAction *action, GncPluginPageInvoice *plugin_page); +static void gnc_plugin_page_invoice_cmd_associate_remove (GtkAction *action, GncPluginPageInvoice *plugin_page); +static void gnc_plugin_page_invoice_cmd_associate_open (GtkAction *action, GncPluginPageInvoice *plugin_page); static void gnc_plugin_page_invoice_cmd_company_report (GtkAction *action, GncPluginPageInvoice *plugin_page); static void gnc_plugin_page_redraw_help_cb( GnucashRegister *gsr, GncPluginPageInvoice *invoice_page ); @@ -201,6 +207,21 @@ static GtkActionEntry gnc_plugin_page_invoice_actions [] = "Create a new invoice for the same owner as the current one", G_CALLBACK (gnc_plugin_page_invoice_cmd_new_invoice) }, + { + "BusinessAssociationAction", NULL, "_Update Association for Invoice", NULL, + "Update Association for current Invoice", + G_CALLBACK (gnc_plugin_page_invoice_cmd_associate) + }, + { + "BusinessAssociationOpenAction", NULL, "_Open Association for Invoice", NULL, + "Open Association for current Invoice", + G_CALLBACK (gnc_plugin_page_invoice_cmd_associate_open) + }, + { + "BusinessAssociationRemoveAction", NULL, "_Remove Association from Invoice", NULL, + "Remove Association from Invoice", + G_CALLBACK (gnc_plugin_page_invoice_cmd_associate_remove) + }, { "ToolsProcessPaymentAction", GNC_ICON_INVOICE_PAY, "_Pay Invoice", NULL, "Enter a payment for the owner of this invoice", @@ -246,6 +267,8 @@ static const gchar *invoice_book_readwrite_actions[] = "EditDuplicateInvoiceAction", "BusinessNewInvoiceAction", "ToolsProcessPaymentAction", + "BusinessAssociationAction", + "BusinessAssociationRemoveAction", NULL }; @@ -285,6 +308,9 @@ static action_toolbar_labels invoice_action_labels[] = {"EditUnpostInvoiceAction", N_("_Unpost Invoice")}, {"BusinessNewInvoiceAction", N_("New _Invoice")}, {"ToolsProcessPaymentAction", N_("_Pay Invoice")}, + {"BusinessAssociationAction", N_("_Update Association for Invoice")}, + {"BusinessAssociationOpenAction", N_("_Open Association for Invoice")}, + {"BusinessAssociationRemoveAction", N_("_Remove Association from Invoice")}, {NULL, NULL}, }; @@ -304,6 +330,9 @@ static action_toolbar_labels bill_action_labels[] = {"EditUnpostInvoiceAction", N_("_Unpost Bill")}, {"BusinessNewInvoiceAction", N_("New _Bill")}, {"ToolsProcessPaymentAction", N_("_Pay Bill")}, + {"BusinessAssociationAction", N_("_Update Association for Bill")}, + {"BusinessAssociationOpenAction", N_("_Open Association for Bill")}, + {"BusinessAssociationRemoveAction", N_("_Remove Association from Bill")}, {NULL, NULL}, }; @@ -323,6 +352,9 @@ static action_toolbar_labels voucher_action_labels[] = {"EditUnpostInvoiceAction", N_("_Unpost Voucher")}, {"BusinessNewInvoiceAction", N_("New _Voucher")}, {"ToolsProcessPaymentAction", N_("_Pay Voucher")}, + {"BusinessAssociationAction", N_("_Update Association for Voucher")}, + {"BusinessAssociationOpenAction", N_("_Open Association for Voucher")}, + {"BusinessAssociationRemoveAction", N_("_Remove Association from Voucher")}, {NULL, NULL}, }; @@ -342,6 +374,9 @@ static action_toolbar_labels creditnote_action_labels[] = {"EditUnpostInvoiceAction", N_("_Unpost Credit Note")}, {"BusinessNewInvoiceAction", N_("New _Credit Note")}, {"ToolsProcessPaymentAction", N_("_Pay Credit Note")}, + {"BusinessAssociationAction", N_("_Update Association for Credit Note")}, + {"BusinessAssociationOpenAction", N_("_Open Association for Credit Note")}, + {"BusinessAssociationRemoveAction", N_("_Remove Association from Credit Note")}, {NULL, NULL}, }; @@ -356,6 +391,9 @@ static action_toolbar_labels invoice_action_tooltips[] = { {"BlankEntryAction", N_("Move to the blank entry at the bottom of the invoice")}, {"ToolsProcessPaymentAction", N_("Enter a payment for the owner of this invoice") }, {"ReportsCompanyReportAction", N_("Open a company report window for the owner of this invoice") }, + {"BusinessAssociationAction", N_("Update Association for current invoice")}, + {"BusinessAssociationOpenAction", N_("Open Association for current invoice")}, + {"BusinessAssociationRemoveAction", N_("Remove Association from invoice")}, {NULL, NULL}, }; @@ -375,6 +413,9 @@ static action_toolbar_labels bill_action_tooltips[] = { {"BlankEntryAction", N_("Move to the blank entry at the bottom of the bill")}, {"ToolsProcessPaymentAction", N_("Enter a payment for the owner of this bill") }, {"ReportsCompanyReportAction", N_("Open a company report window for the owner of this bill") }, + {"BusinessAssociationAction", N_("Update Association for current bill")}, + {"BusinessAssociationOpenAction", N_("Open Association for current bill")}, + {"BusinessAssociationRemoveAction", N_("Remove Association from bill")}, {NULL, NULL}, }; @@ -394,6 +435,9 @@ static action_toolbar_labels voucher_action_tooltips[] = { {"BlankEntryAction", N_("Move to the blank entry at the bottom of the voucher")}, {"ToolsProcessPaymentAction", N_("Enter a payment for the owner of this voucher") }, {"ReportsCompanyReportAction", N_("Open a company report window for the owner of this voucher") }, + {"BusinessAssociationAction", N_("Update Association for current voucher")}, + {"BusinessAssociationOpenAction", N_("Open Association for current voucher")}, + {"BusinessAssociationRemoveAction", N_("Remove Association from voucher")}, {NULL, NULL}, }; @@ -413,6 +457,9 @@ static action_toolbar_labels creditnote_action_tooltips[] = { {"BlankEntryAction", N_("Move to the blank entry at the bottom of the credit note")}, {"ToolsProcessPaymentAction", N_("Enter a payment for the owner of this credit note") }, {"ReportsCompanyReportAction", N_("Open a company report window for the owner of this credit note") }, + {"BusinessAssociationAction", N_("Update Association for credit note")}, + {"BusinessAssociationOpenAction", N_("Open Association for credit note")}, + {"BusinessAssociationRemoveAction", N_("Remove Association from credit note")}, {NULL, NULL}, }; @@ -550,6 +597,17 @@ gnc_plugin_page_invoice_finalize (GObject *object) LEAVE(" "); } +static void +update_assoc_actions (GncPluginPage *plugin_page, gboolean has_uri) +{ + GtkAction *uri_action; + + uri_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(plugin_page), "BusinessAssociationOpenAction"); + gtk_action_set_sensitive (uri_action, has_uri); + uri_action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(plugin_page), "BusinessAssociationRemoveAction"); + gtk_action_set_sensitive (uri_action, has_uri); +} + static void gnc_plugin_page_invoice_action_update (GtkActionGroup *action_group, action_toolbar_labels *action_list, @@ -590,11 +648,13 @@ gnc_plugin_page_invoice_update_menus (GncPluginPage *page, gboolean is_posted, g GtkActionGroup *action_group; GncPluginPageInvoicePrivate *priv; GncInvoiceType invoice_type; + GncInvoice *invoice; gint i, j; action_toolbar_labels *label_list; action_toolbar_labels *tooltip_list; action_toolbar_labels *label_layout_list; action_toolbar_labels *tooltip_layout_list; + gboolean has_uri = FALSE; gboolean is_readonly = qof_book_is_readonly(gnc_get_current_book()); @@ -678,6 +738,13 @@ gnc_plugin_page_invoice_update_menus (GncPluginPage *page, gboolean is_posted, g gnc_plugin_page_invoice_action_update (action_group, label_layout_list, (void*)gtk_action_set_label); /* update the layout action tooltips */ gnc_plugin_page_invoice_action_update (action_group, tooltip_layout_list, (void*)gtk_action_set_tooltip); + + // update association buttons + invoice = gnc_invoice_window_get_invoice (priv->iw); + if (gncInvoiceGetAssociation (invoice)) + has_uri = TRUE; + + update_assoc_actions (page, has_uri); } @@ -1269,6 +1336,107 @@ gnc_plugin_page_invoice_cmd_reset_layout (GtkAction *action, LEAVE(" "); } +static void +gnc_plugin_page_invoice_cmd_associate (GtkAction *action, + GncPluginPageInvoice *plugin_page) +{ + GncPluginPageInvoicePrivate *priv; + GtkWindow *parent; + GtkAction *uri_action; + GncInvoice *invoice; + const gchar *uri; + gchar *ret_uri; + gboolean has_uri = FALSE; + + g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(plugin_page)); + ENTER("(action %p, plugin_page %p)", action, plugin_page); + priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(plugin_page); + parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page))); + + invoice = gnc_invoice_window_get_invoice (priv->iw); + uri = gncInvoiceGetAssociation (invoice); + + ret_uri = gnc_assoc_get_uri_dialog (parent, _("Change a Business Association"), uri); + + if (ret_uri && g_strcmp0 (uri, ret_uri) != 0) + { + GtkWidget *assoc_link_button = gnc_invoice_window_get_assoc_link_button (priv->iw); + + if (assoc_link_button) + { + if (g_strcmp0 (ret_uri, "") == 0) + gtk_widget_hide (GTK_WIDGET(assoc_link_button)); + else + { + gchar *display_uri = gnc_assoc_get_unescaped_just_uri (ret_uri); + gtk_link_button_set_uri (GTK_LINK_BUTTON(assoc_link_button), display_uri); + gtk_widget_show (GTK_WIDGET(assoc_link_button)); + g_free (display_uri); + } + } + gncInvoiceSetAssociation (invoice, ret_uri); + has_uri = TRUE; + } + + // update the menu actions + update_assoc_actions (GNC_PLUGIN_PAGE(plugin_page), has_uri); + + g_free (ret_uri); + LEAVE(" "); +} + +static void +gnc_plugin_page_invoice_cmd_associate_remove (GtkAction *action, + GncPluginPageInvoice *plugin_page) +{ + GncPluginPageInvoicePrivate *priv; + GtkWindow *parent; + GtkAction *uri_action; + GncInvoice *invoice; + GtkWidget *assoc_link_button; + + g_return_if_fail (GNC_IS_PLUGIN_PAGE_INVOICE(plugin_page)); + ENTER("(action %p, plugin_page %p)", action, plugin_page); + priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(plugin_page); + parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page))); + + invoice = gnc_invoice_window_get_invoice (priv->iw); + gncInvoiceSetAssociation (invoice, ""); + + assoc_link_button = gnc_invoice_window_get_assoc_link_button (priv->iw); + + if (assoc_link_button) + gtk_widget_hide (GTK_WIDGET(assoc_link_button)); + + // update the menu actions + update_assoc_actions (GNC_PLUGIN_PAGE(plugin_page), FALSE); + + LEAVE(" "); +} + +static void +gnc_plugin_page_invoice_cmd_associate_open (GtkAction *action, + GncPluginPageInvoice *plugin_page) +{ + GncPluginPageInvoicePrivate *priv; + GtkWindow *parent; + GncInvoice *invoice; + const gchar *uri = NULL; + + g_return_if_fail(GNC_IS_PLUGIN_PAGE_INVOICE(plugin_page)); + ENTER("(action %p, plugin_page %p)", action, plugin_page); + priv = GNC_PLUGIN_PAGE_INVOICE_GET_PRIVATE(plugin_page); + parent = GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page))); + + invoice = gnc_invoice_window_get_invoice (priv->iw); + uri = gncInvoiceGetAssociation (invoice); + + if (uri) + gnc_assoc_open_uri (parent, uri); + + LEAVE(" "); +} + static void gnc_plugin_page_invoice_cmd_company_report (GtkAction *action, GncPluginPageInvoice *plugin_page) diff --git a/gnucash/gtkbuilder/dialog-invoice.glade b/gnucash/gtkbuilder/dialog-invoice.glade index fd9aa3c6ad..6cb0c11581 100644 --- a/gnucash/gtkbuilder/dialog-invoice.glade +++ b/gnucash/gtkbuilder/dialog-invoice.glade @@ -381,22 +381,61 @@ False 0 - + True False - True - True - 3 - never - in + vertical - + True - True - word - False - + False + True + True + 3 + never + in + + + True + True + word + False + + + + + False + True + 0 + + + + + True + False + + + Open Association + True + True + True + start + none + http://www.gnucash.org + + + False + True + 0 + + + + + False + True + 1 + diff --git a/gnucash/ui/gnc-plugin-page-invoice-ui.xml b/gnucash/ui/gnc-plugin-page-invoice-ui.xml index 8a823271e1..45ce7eea83 100644 --- a/gnucash/ui/gnc-plugin-page-invoice-ui.xml +++ b/gnucash/ui/gnc-plugin-page-invoice-ui.xml @@ -39,6 +39,11 @@ + + + + +