From 95c0933a84f82cb2e1ba32a60e03dc651b419768 Mon Sep 17 00:00:00 2001 From: Geert Janssens Date: Sun, 24 Nov 2013 16:28:36 +0000 Subject: [PATCH] When an account or budget is deleted, drop any associated saved state git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@23432 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/app-utils/gnc-state.c | 42 ++++++++++++++++++++++++ src/app-utils/gnc-state.h | 17 ++++++++++ src/core-utils/gnc-gkeyfile-utils.c | 4 +++ src/gnome/gnc-budget-view.c | 4 ++- src/gnome/gnc-plugin-page-account-tree.c | 29 +++++++++++++++- src/gnome/gnc-plugin-page-budget.c | 6 ++++ src/gnome/gnc-plugin-page-register2.c | 5 +++ 7 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/app-utils/gnc-state.c b/src/app-utils/gnc-state.c index cd05981d04..2896717acb 100644 --- a/src/app-utils/gnc-state.c +++ b/src/app-utils/gnc-state.c @@ -260,3 +260,45 @@ GKeyFile *gnc_state_get_current (void) } +gint gnc_state_drop_sections_for (const gchar *partial_name) +{ + gchar **groups; + gint found_count = 0, dropped_count = 0; + gsize i, num_groups; + GError *error = NULL; + + if (!state_file) + { + PWARN ("No pre-existing state found, ignoring drop request"); + return 0; + } + + ENTER(""); + + groups = g_key_file_get_groups (state_file, &num_groups); + for (i = 0; i < num_groups; i++) + { + if (g_strstr_len (groups[i], -1, partial_name)) + { + DEBUG ("Section \"%s\" matches \"%s\", removing", groups[i], partial_name); + found_count++; + if (!g_key_file_remove_group (state_file, groups[i], &error)) + { + PWARN ("Warning: unable to remove section %s.\n %s", + groups[i], + error->message); + g_error_free (error); + } + else + dropped_count++; + + } + } + g_strfreev (groups); + + LEAVE("Found %i sections matching \"%s\", successfully removed %i", + found_count, partial_name, dropped_count); + return dropped_count; + +} + diff --git a/src/app-utils/gnc-state.h b/src/app-utils/gnc-state.h index 8c1592f90b..2cf0d7b944 100644 --- a/src/app-utils/gnc-state.h +++ b/src/app-utils/gnc-state.h @@ -85,6 +85,23 @@ void gnc_state_save (const QofSession *session); */ GKeyFile *gnc_state_get_current (void); +/** Drop all sections from the state file whose name contains + * partial_name. + * + * This function is meant to be called when an object is deleted + * for which state is kept. For example, when an account is + * deleted from GnuCash, all state sections that refer to it + * should get removed. In that case you can call this function + * with the account's guid as parameter. + * + * @param partial_name a string to match in the section names + * for most objects in GnuCash that maintain + * state, this will be the object's guid + * + * @return The number of successfully dropped sections. + */ +gint gnc_state_drop_sections_for (const gchar *partial_name); + #endif /* GNC_STATE_H */ /** @} */ /** @} */ diff --git a/src/core-utils/gnc-gkeyfile-utils.c b/src/core-utils/gnc-gkeyfile-utils.c index bb4464b931..7491df8e2e 100644 --- a/src/core-utils/gnc-gkeyfile-utils.c +++ b/src/core-utils/gnc-gkeyfile-utils.c @@ -56,7 +56,10 @@ #endif #include "gnc-gkeyfile-utils.h" +#include "qof.h" +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; GKeyFile * gnc_key_file_load_from_file (const gchar *filename, @@ -111,6 +114,7 @@ gnc_key_file_save_to_file (const gchar *filename, g_return_val_if_fail(*error == NULL, FALSE); contents = g_key_file_to_data(key_file, NULL, NULL); + DEBUG("Keyfile data:\n%s", contents); length = strlen(contents); fd = g_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd == -1) diff --git a/src/gnome/gnc-budget-view.c b/src/gnome/gnc-budget-view.c index 0bb908fc49..90c2010104 100644 --- a/src/gnome/gnc-budget-view.c +++ b/src/gnome/gnc-budget-view.c @@ -56,6 +56,7 @@ #include "option-util.h" #include "gnc-main-window.h" #include "gnc-component-manager.h" +#include "gnc-state.h" #include "qof.h" @@ -491,7 +492,8 @@ gnc_budget_view_delete_budget(GncBudgetView *view) ENTER("view %p", view); priv = GNC_BUDGET_VIEW_GET_PRIVATE (view); - gnc_tree_view_remove_state_information (GNC_TREE_VIEW (priv->tree_view)); + gnc_state_drop_sections_for (guid_to_string (&priv->key)); + g_object_set (G_OBJECT (priv->tree_view), "state-section", NULL, NULL); LEAVE(" "); } diff --git a/src/gnome/gnc-plugin-page-account-tree.c b/src/gnome/gnc-plugin-page-account-tree.c index 48552861c1..39f39c21f5 100644 --- a/src/gnome/gnc-plugin-page-account-tree.c +++ b/src/gnome/gnc-plugin-page-account-tree.c @@ -57,6 +57,7 @@ #include "gnc-prefs.h" #include "gnc-session.h" #include "gnc-split-reg.h" +#include "gnc-state.h" #include "gnc-tree-view-account.h" #include "gnc-tree-model-account-types.h" #include "gnc-ui.h" @@ -1388,12 +1389,17 @@ gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPag if (GTK_RESPONSE_ACCEPT == response) { + GList *acct_list, *ptr; + const GncGUID *guid; + const gchar *guid_str; + gnc_set_busy_cursor(NULL, TRUE); gnc_suspend_gui_refresh (); + + /* Move subaccounts and transactions if this was requested */ xaccAccountBeginEdit (account); if (NULL != saa) { - GList *acct_list, *ptr; xaccAccountBeginEdit (saa); acct_list = gnc_account_get_children(account); @@ -1414,10 +1420,31 @@ gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPag /* Move the splits of the account to be deleted. */ xaccAccountMoveAllSplits (account, ta); } + xaccAccountCommitEdit (account); + + /* Drop all references from the state file for + * any subaccount the account still has + */ + acct_list = gnc_account_get_children(account); + for (ptr = acct_list; ptr; ptr = g_list_next(ptr)) + { + guid = xaccAccountGetGUID (ptr->data); + guid_str = guid_to_string (guid); + gnc_state_drop_sections_for (guid_str); + } + g_list_free(acct_list); + + /* Drop all references from the state file for this account + */ + guid = xaccAccountGetGUID (account); + guid_str = guid_to_string (guid); + gnc_state_drop_sections_for (guid_str); + /* * Finally, delete the account, any subaccounts it may still * have, and any splits it or its subaccounts may still have. */ + xaccAccountBeginEdit (account); xaccAccountDestroy (account); gnc_resume_gui_refresh (); gnc_unset_busy_cursor(NULL); diff --git a/src/gnome/gnc-plugin-page-budget.c b/src/gnome/gnc-plugin-page-budget.c index c48dc27543..f76f881cd2 100644 --- a/src/gnome/gnc-plugin-page-budget.c +++ b/src/gnome/gnc-plugin-page-budget.c @@ -382,6 +382,12 @@ gnc_plugin_page_budget_refresh_cb(GHashTable *changes, gpointer user_data) { if (ei->event_mask & QOF_EVENT_DESTROY) { + /* Budget has been deleted, close plugin page + * but prevent that action from writing state information + * for this budget account + */ + priv->delete_budget = TRUE; + gnc_budget_view_delete_budget (priv->budget_view); gnc_plugin_page_budget_close_cb(user_data); return; } diff --git a/src/gnome/gnc-plugin-page-register2.c b/src/gnome/gnc-plugin-page-register2.c index bfbbdc71e8..3eef99208b 100644 --- a/src/gnome/gnc-plugin-page-register2.c +++ b/src/gnome/gnc-plugin-page-register2.c @@ -3899,6 +3899,11 @@ gnc_plugin_page_register2_refresh_cb (GHashTable *changes, gpointer user_data) / { if (ei->event_mask & QOF_EVENT_DESTROY) { + /* Account has been deleted, close plugin page + * but prevent that action from writing state information + * for this deleted account + */ + g_object_set (G_OBJECT (view), "state-section", NULL, NULL); gnc_main_window_close_page (GNC_PLUGIN_PAGE (page)); return; }