mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Bug 797900 - Crash caused by Quitting while Check and Repair All is running
The account tree page didn't have a "finish" function normally used to verify a page can close. I added one, along with two flags that indicate whether a scrubbing operation is currently ongoing and whether we should quit when the scrubbing is done. The result is: If a user attempts to quit while scrubbing isn't done, an alert pops up asking whether the user wants to abort the scrub. If so, the scrub is aborted (safely) and GC quits. If not the app does not quit. I have to say, I'm not sure this is the right way to do this. In my view, the right way would be: - Disable the "quit" menu when scrubbing is happening (for some reason gnc_suspend_gui_refresh() does not cause the quit menu to be grayed) so there's no chance of quitting while scrubbing is ongoing - If needed, add an abort scrubbing button to the main window. Not sure whether that's desirable or not. Let me know what you think: is what I have what we need, or would the above be better.
This commit is contained in:
parent
a50c188dca
commit
bbdd4f34b6
@ -1146,6 +1146,11 @@ gnc_main_window_all_finish_pending (void)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (gnc_gui_refresh_suspended ())
|
||||||
|
{
|
||||||
|
gnc_warning_dialog (NULL, "%s", "An operation is still pending, wait for it to complete before quitting ");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,6 +413,30 @@ gnc_plugin_page_account_tree_new (void)
|
|||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageAccountTree, gnc_plugin_page_account_tree, GNC_TYPE_PLUGIN_PAGE)
|
G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageAccountTree, gnc_plugin_page_account_tree, GNC_TYPE_PLUGIN_PAGE)
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepare_scrubbing ()
|
||||||
|
{
|
||||||
|
gnc_suspend_gui_refresh ();
|
||||||
|
gnc_set_abort_scrub (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
finish (GncPluginPage* page)
|
||||||
|
{
|
||||||
|
if (gnc_get_ongoing_scrub ())
|
||||||
|
{
|
||||||
|
gboolean ret = gnc_verify_dialog (NULL, FALSE, "%s", "A scrubbing operation is currently pending, do you want to abort it?");
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
gnc_set_abort_scrub (TRUE);
|
||||||
|
gnc_resume_gui_refresh (); // This is so quit does not complain about an ongoing operation.
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
|
gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
|
||||||
{
|
{
|
||||||
@ -430,6 +454,8 @@ gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
|
|||||||
gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
|
gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
|
||||||
gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
|
gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
|
||||||
gnc_plugin_class->focus_page_function = gnc_plugin_page_account_tree_focus_widget;
|
gnc_plugin_class->focus_page_function = gnc_plugin_page_account_tree_focus_widget;
|
||||||
|
gnc_plugin_class->finish_pending = finish;
|
||||||
|
|
||||||
|
|
||||||
plugin_page_signals[ACCOUNT_SELECTED] =
|
plugin_page_signals[ACCOUNT_SELECTED] =
|
||||||
g_signal_new ("account_selected",
|
g_signal_new ("account_selected",
|
||||||
@ -1913,7 +1939,7 @@ gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountT
|
|||||||
|
|
||||||
g_return_if_fail (account != NULL);
|
g_return_if_fail (account != NULL);
|
||||||
|
|
||||||
gnc_suspend_gui_refresh ();
|
prepare_scrubbing ();
|
||||||
|
|
||||||
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
||||||
gnc_window_set_progressbar_window (window);
|
gnc_window_set_progressbar_window (window);
|
||||||
@ -1939,7 +1965,7 @@ gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAcco
|
|||||||
|
|
||||||
g_return_if_fail (account != NULL);
|
g_return_if_fail (account != NULL);
|
||||||
|
|
||||||
gnc_suspend_gui_refresh ();
|
prepare_scrubbing ();
|
||||||
|
|
||||||
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
||||||
gnc_window_set_progressbar_window (window);
|
gnc_window_set_progressbar_window (window);
|
||||||
@ -1962,7 +1988,7 @@ gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAcco
|
|||||||
Account *root = gnc_get_current_root_account ();
|
Account *root = gnc_get_current_root_account ();
|
||||||
GncWindow *window;
|
GncWindow *window;
|
||||||
|
|
||||||
gnc_suspend_gui_refresh ();
|
prepare_scrubbing ();
|
||||||
|
|
||||||
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
|
||||||
gnc_window_set_progressbar_window (window);
|
gnc_window_set_progressbar_window (window);
|
||||||
|
@ -1905,6 +1905,25 @@ gnc_plugin_page_register_update_edit_menu (GncPluginPage* page, gboolean hide)
|
|||||||
gtk_action_set_visible (action, !hide || can_paste);
|
gtk_action_set_visible (action, !hide || can_paste);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean abort_scrub = FALSE;
|
||||||
|
static gboolean is_scrubbing = FALSE;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
finish_scrub (GncPluginPage* page)
|
||||||
|
{
|
||||||
|
if (is_scrubbing)
|
||||||
|
{
|
||||||
|
gboolean ret = gnc_verify_dialog (NULL, FALSE, "%s", "A scrubbing operation is currently pending, do you want to abort it?");
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
abort_scrub = TRUE;
|
||||||
|
gnc_resume_gui_refresh (); // This is so quit does not complain about an ongoing operation.
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gnc_plugin_page_register_finish_pending (GncPluginPage* page)
|
gnc_plugin_page_register_finish_pending (GncPluginPage* page)
|
||||||
@ -1916,6 +1935,9 @@ gnc_plugin_page_register_finish_pending (GncPluginPage* page)
|
|||||||
const gchar* name;
|
const gchar* name;
|
||||||
gint response;
|
gint response;
|
||||||
|
|
||||||
|
if (!finish_scrub (page))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
|
reg_page = GNC_PLUGIN_PAGE_REGISTER (page);
|
||||||
priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
|
priv = GNC_PLUGIN_PAGE_REGISTER_GET_PRIVATE (reg_page);
|
||||||
reg = gnc_ledger_display_get_split_register (priv->ledger);
|
reg = gnc_ledger_display_get_split_register (priv->ledger);
|
||||||
@ -4933,6 +4955,7 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction* action,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gnc_suspend_gui_refresh();
|
gnc_suspend_gui_refresh();
|
||||||
|
is_scrubbing = TRUE;
|
||||||
window = GNC_WINDOW (GNC_PLUGIN_PAGE (plugin_page)->window);
|
window = GNC_WINDOW (GNC_PLUGIN_PAGE (plugin_page)->window);
|
||||||
gnc_window_set_progressbar_window (window);
|
gnc_window_set_progressbar_window (window);
|
||||||
|
|
||||||
@ -4956,6 +4979,8 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction* action,
|
|||||||
char* progress_msg = g_strdup_printf (message, curr_split_no, split_count);
|
char* progress_msg = g_strdup_printf (message, curr_split_no, split_count);
|
||||||
gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
|
gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
|
||||||
g_free (progress_msg);
|
g_free (progress_msg);
|
||||||
|
if (abort_scrub)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
xaccTransScrubOrphans (trans);
|
xaccTransScrubOrphans (trans);
|
||||||
@ -4976,6 +5001,7 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction* action,
|
|||||||
|
|
||||||
gnc_window_show_progress (NULL, -1.0);
|
gnc_window_show_progress (NULL, -1.0);
|
||||||
gnc_resume_gui_refresh();
|
gnc_resume_gui_refresh();
|
||||||
|
is_scrubbing = FALSE;
|
||||||
LEAVE (" ");
|
LEAVE (" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,20 @@
|
|||||||
#define G_LOG_DOMAIN "gnc.engine.scrub"
|
#define G_LOG_DOMAIN "gnc.engine.scrub"
|
||||||
|
|
||||||
static QofLogModule log_module = G_LOG_DOMAIN;
|
static QofLogModule log_module = G_LOG_DOMAIN;
|
||||||
|
static gboolean abort_now = FALSE;
|
||||||
|
static gint scrub_depth = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
gnc_set_abort_scrub (gboolean abort)
|
||||||
|
{
|
||||||
|
abort_now = abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gnc_get_ongoing_scrub (void)
|
||||||
|
{
|
||||||
|
return scrub_depth > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
|
|
||||||
@ -64,10 +78,11 @@ void
|
|||||||
xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
|
xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
|
||||||
{
|
{
|
||||||
if (!acc) return;
|
if (!acc) return;
|
||||||
|
scrub_depth ++;
|
||||||
xaccAccountScrubOrphans (acc, percentagefunc);
|
xaccAccountScrubOrphans (acc, percentagefunc);
|
||||||
gnc_account_foreach_descendant(acc,
|
gnc_account_foreach_descendant(acc,
|
||||||
(AccountCb)xaccAccountScrubOrphans, percentagefunc);
|
(AccountCb)xaccAccountScrubOrphans, percentagefunc);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -83,6 +98,7 @@ TransScrubOrphansFast (Transaction *trans, Account *root)
|
|||||||
{
|
{
|
||||||
Split *split = node->data;
|
Split *split = node->data;
|
||||||
Account *orph;
|
Account *orph;
|
||||||
|
if (abort_now) break;
|
||||||
|
|
||||||
if (split->acc) continue;
|
if (split->acc) continue;
|
||||||
|
|
||||||
@ -110,6 +126,7 @@ xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
guint current_split = 0;
|
guint current_split = 0;
|
||||||
|
|
||||||
if (!acc) return;
|
if (!acc) return;
|
||||||
|
scrub_depth++;
|
||||||
|
|
||||||
str = xaccAccountGetName (acc);
|
str = xaccAccountGetName (acc);
|
||||||
str = str ? str : "(null)";
|
str = str ? str : "(null)";
|
||||||
@ -120,12 +137,12 @@ xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
for (node = splits; node; node = node->next)
|
for (node = splits; node; node = node->next)
|
||||||
{
|
{
|
||||||
Split *split = node->data;
|
Split *split = node->data;
|
||||||
|
|
||||||
if (current_split % 100 == 0)
|
if (current_split % 100 == 0)
|
||||||
{
|
{
|
||||||
char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
|
char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
|
||||||
(percentagefunc)(progress_msg, (100 * current_split) / total_splits);
|
(percentagefunc)(progress_msg, (100 * current_split) / total_splits);
|
||||||
g_free (progress_msg);
|
g_free (progress_msg);
|
||||||
|
if (abort_now) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransScrubOrphansFast (xaccSplitGetParent (split),
|
TransScrubOrphansFast (xaccSplitGetParent (split),
|
||||||
@ -133,6 +150,7 @@ xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
current_split++;
|
current_split++;
|
||||||
}
|
}
|
||||||
(percentagefunc)(NULL, -1.0);
|
(percentagefunc)(NULL, -1.0);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -148,6 +166,7 @@ xaccTransScrubOrphans (Transaction *trans)
|
|||||||
for (node = trans->splits; node; node = node->next)
|
for (node = trans->splits; node; node = node->next)
|
||||||
{
|
{
|
||||||
Split *split = node->data;
|
Split *split = node->data;
|
||||||
|
if (abort_now) break;
|
||||||
|
|
||||||
if (split->acc)
|
if (split->acc)
|
||||||
{
|
{
|
||||||
@ -183,9 +202,13 @@ void
|
|||||||
xaccAccountScrubSplits (Account *account)
|
xaccAccountScrubSplits (Account *account)
|
||||||
{
|
{
|
||||||
GList *node;
|
GList *node;
|
||||||
|
scrub_depth++;
|
||||||
for (node = xaccAccountGetSplitList (account); node; node = node->next)
|
for (node = xaccAccountGetSplitList (account); node; node = node->next)
|
||||||
|
{
|
||||||
|
if (abort_now) break;
|
||||||
xaccSplitScrub (node->data);
|
xaccSplitScrub (node->data);
|
||||||
|
}
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -291,9 +314,11 @@ xaccSplitScrub (Split *split)
|
|||||||
void
|
void
|
||||||
xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
|
xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
|
||||||
{
|
{
|
||||||
|
scrub_depth++;
|
||||||
xaccAccountScrubImbalance (acc, percentagefunc);
|
xaccAccountScrubImbalance (acc, percentagefunc);
|
||||||
gnc_account_foreach_descendant(acc,
|
gnc_account_foreach_descendant(acc,
|
||||||
(AccountCb)xaccAccountScrubImbalance, percentagefunc);
|
(AccountCb)xaccAccountScrubImbalance, percentagefunc);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -305,6 +330,7 @@ xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
gint split_count = 0, curr_split_no = 0;
|
gint split_count = 0, curr_split_no = 0;
|
||||||
|
|
||||||
if (!acc) return;
|
if (!acc) return;
|
||||||
|
scrub_depth++;
|
||||||
|
|
||||||
str = xaccAccountGetName(acc);
|
str = xaccAccountGetName(acc);
|
||||||
str = str ? str : "(null)";
|
str = str ? str : "(null)";
|
||||||
@ -316,6 +342,7 @@ xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
{
|
{
|
||||||
Split *split = node->data;
|
Split *split = node->data;
|
||||||
Transaction *trans = xaccSplitGetParent(split);
|
Transaction *trans = xaccSplitGetParent(split);
|
||||||
|
if (abort_now) break;
|
||||||
|
|
||||||
PINFO("Start processing split %d of %d",
|
PINFO("Start processing split %d of %d",
|
||||||
curr_split_no + 1, split_count);
|
curr_split_no + 1, split_count);
|
||||||
@ -340,6 +367,7 @@ xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
|
|||||||
curr_split_no++;
|
curr_split_no++;
|
||||||
}
|
}
|
||||||
(percentagefunc)(NULL, -1.0);
|
(percentagefunc)(NULL, -1.0);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Split *
|
static Split *
|
||||||
@ -1243,19 +1271,22 @@ scrub_trans_currency_helper (Transaction *t, gpointer data)
|
|||||||
static void
|
static void
|
||||||
scrub_account_commodity_helper (Account *account, gpointer data)
|
scrub_account_commodity_helper (Account *account, gpointer data)
|
||||||
{
|
{
|
||||||
|
scrub_depth++;
|
||||||
xaccAccountScrubCommodity (account);
|
xaccAccountScrubCommodity (account);
|
||||||
xaccAccountDeleteOldData (account);
|
xaccAccountDeleteOldData (account);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xaccAccountTreeScrubCommodities (Account *acc)
|
xaccAccountTreeScrubCommodities (Account *acc)
|
||||||
{
|
{
|
||||||
if (!acc) return;
|
if (!acc) return;
|
||||||
|
scrub_depth++;
|
||||||
xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
|
xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
|
||||||
|
|
||||||
scrub_account_commodity_helper (acc, NULL);
|
scrub_account_commodity_helper (acc, NULL);
|
||||||
gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
|
gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
@ -1315,13 +1346,14 @@ xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
|
|||||||
LEAVE("Oops");
|
LEAVE("Oops");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
scrub_depth++;
|
||||||
gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
|
gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
|
||||||
|
|
||||||
move_quote_source(root, GINT_TO_POINTER(new_style));
|
move_quote_source(root, GINT_TO_POINTER(new_style));
|
||||||
gnc_account_foreach_descendant (root, move_quote_source,
|
gnc_account_foreach_descendant (root, move_quote_source,
|
||||||
GINT_TO_POINTER(new_style));
|
GINT_TO_POINTER(new_style));
|
||||||
LEAVE("Migration done");
|
LEAVE("Migration done");
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
@ -1333,6 +1365,7 @@ xaccAccountScrubKvp (Account *account)
|
|||||||
gchar *str2;
|
gchar *str2;
|
||||||
|
|
||||||
if (!account) return;
|
if (!account) return;
|
||||||
|
scrub_depth++;
|
||||||
|
|
||||||
qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
|
qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
|
||||||
if (G_VALUE_HOLDS_STRING (&v))
|
if (G_VALUE_HOLDS_STRING (&v))
|
||||||
@ -1350,6 +1383,7 @@ xaccAccountScrubKvp (Account *account)
|
|||||||
qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
|
qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
|
||||||
|
|
||||||
qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
|
qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
|
||||||
|
scrub_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================================ */
|
/* ================================================================ */
|
||||||
|
@ -69,6 +69,16 @@
|
|||||||
for orphaned inodes.
|
for orphaned inodes.
|
||||||
@{ */
|
@{ */
|
||||||
|
|
||||||
|
/** The gnc_set_abort_scrub () method causes a currently running scrub operation
|
||||||
|
* to stop, if abort is TRUE; gnc_set_abort_scrub(FALSE) must be called before
|
||||||
|
* any scrubbing operation.
|
||||||
|
*/
|
||||||
|
void gnc_set_abort_scrub (gboolean abort);
|
||||||
|
|
||||||
|
/** The gnc_get_ongoing_scrub () method returns TRUE if a scrub operation is ongoing.
|
||||||
|
*/
|
||||||
|
gboolean gnc_get_ongoing_scrub (void);
|
||||||
|
|
||||||
/** The xaccTransScrubOrphans() method scrubs only the splits in the
|
/** The xaccTransScrubOrphans() method scrubs only the splits in the
|
||||||
* given transaction.
|
* given transaction.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user