GnuCash  5.6-150-g038405b370+
gnc-plugin-page-account-tree.cpp
1 /*
2  * gnc-plugin-page-account-tree.c --
3  *
4  * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de>
5  * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, contact:
19  *
20  * Free Software Foundation Voice: +1-617-542-5942
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22  * Boston, MA 02110-1301, USA gnu@gnu.org
23  */
24 
35 #include <config.h>
36 
37 #include <algorithm>
38 
39 #include <gtk/gtk.h>
40 #include <glib/gi18n.h>
43 
44 #include "Account.hpp"
45 #include "Scrub.h"
46 #include "Scrub3.h"
47 #include "ScrubBusiness.h"
48 #include "Transaction.h"
49 #include "dialog-account.h"
50 #include "dialog-transfer.h"
51 #include "dialog-utils.h"
52 #include "assistant-hierarchy.h"
53 #include "assistant-stock-transaction.h"
54 #include "gnc-account-sel.h"
55 #include "gnc-component-manager.h"
56 #include "gnc-engine.h"
57 #include "gnc-gnome-utils.h"
58 #include "gnc-gobject-utils.h"
59 #include "gnc-icons.h"
61 #include "gnc-prefs.h"
62 #include "gnc-session.h"
63 #include "gnc-split-reg.h"
64 #include "gnc-state.h"
65 #include "gnc-tree-view-account.h"
67 #include "gnc-ui.h"
68 #include "gnc-ui-util.h"
69 #include "gnc-window.h"
70 #include "dialog-lot-viewer.h"
71 #include "window-reconcile.h"
72 #include "window-autoclear.h"
73 #include "window-main-summarybar.h"
75 #include "dialog-find-account.h"
76 #include <gnc-glib-utils.h>
77 
78 /* This static indicates the debugging module that this .o belongs to. */
79 static QofLogModule log_module = GNC_MOD_GUI;
80 
81 
82 /********************************************************************
83  * delete_account_helper
84  * See if this account has any splits present. Set the user data
85  * and return the same value to stop walking the account tree if
86  * appropriate.
87  ********************************************************************/
88 typedef struct _delete_helper
89 {
90  gboolean has_splits;
91  gboolean has_ro_splits;
93 
94 
95 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-acct-tree"
96 #define STATE_SECTION "Account Hierarchy"
97 
98 #define DELETE_DIALOG_FILTER "filter"
99 #define DELETE_DIALOG_ACCOUNT "account"
100 #define DELETE_DIALOG_TRANS_MAS "trans_mas"
101 #define DELETE_DIALOG_SA_MAS "sa_mas"
102 #define DELETE_DIALOG_SA_TRANS_MAS "sa_trans_mas"
103 #define DELETE_DIALOG_SA_TRANS "sa_trans"
104 #define DELETE_DIALOG_SA_SPLITS "sa_has_split"
105 #define DELETE_DIALOG_OK_BUTTON "deletebutton"
106 
107 enum
108 {
109  ACCOUNT_SELECTED,
110  LAST_SIGNAL
111 };
112 
114 {
115  GtkWidget *widget;
116  GtkTreeView *tree_view;
117  gint component_id;
120 
121 #define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(o) \
122  ((GncPluginPageAccountTreePrivate*)gnc_plugin_page_account_tree_get_instance_private((GncPluginPageAccountTree*)o))
123 
124 /************************************************************
125  * Prototypes *
126  ************************************************************/
127 /* Plugin Actions */
128 static void gnc_plugin_page_account_tree_finalize (GObject *object);
129 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data);
130 
131 static gboolean gnc_plugin_page_account_tree_focus_widget (GncPluginPage *plugin_page);
132 static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page);
133 static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page);
134 static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
135 static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
136 
137 /* Callbacks */
138 static void gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data);
139 static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget, GdkEventButton *event, GncPluginPage *page);
140 static void gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
141  GtkTreePath *path,
142  GtkTreeViewColumn *col,
144 
145 static void gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
147 static void accounting_period_changed_cb(gpointer prefs, gchar *pref, gpointer user_data);
148 
149 extern "C" {
150 void gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb, GtkWidget *dialog);
151 void gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b);
152 }
153 
154 /* Command callbacks */
155 static void gnc_plugin_page_account_tree_cmd_new_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
156 static void gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
157 static void gnc_plugin_page_account_tree_cmd_open_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
158 static void gnc_plugin_page_account_tree_cmd_open_subaccounts (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
159 static void gnc_plugin_page_account_tree_cmd_edit_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
160 static void gnc_plugin_page_account_tree_cmd_find_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
161 static void gnc_plugin_page_account_tree_cmd_find_account_popup (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
162 static void gnc_plugin_page_account_tree_cmd_delete_account (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
163 static void gnc_plugin_page_account_tree_cmd_renumber_accounts (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
164 static void gnc_plugin_page_account_tree_cmd_view_filter_by (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
165 static void gnc_plugin_page_account_tree_cmd_reconcile (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
166 static void gnc_plugin_page_account_tree_cmd_refresh (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
167 static void gnc_plugin_page_account_tree_cmd_autoclear (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
168 static void gnc_plugin_page_account_tree_cmd_transfer (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
169 static void gnc_plugin_page_account_tree_cmd_stock_split (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
170 static void gnc_plugin_page_account_tree_cmd_stock_assistant (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
171 static void gnc_plugin_page_account_tree_cmd_edit_tax_options (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
172 static void gnc_plugin_page_account_tree_cmd_lots (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
173 static void gnc_plugin_page_account_tree_cmd_scrub (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
174 static void gnc_plugin_page_account_tree_cmd_scrub_sub (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
175 static void gnc_plugin_page_account_tree_cmd_scrub_all (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
176 static void gnc_plugin_page_account_tree_cmd_cascade_account_properties (GSimpleAction *simple, GVariant *paramter, gpointer user_data);
177 
178 /* Account Deletion Actions. */
179 static int confirm_delete_account (GSimpleAction *simple,
181  Account* sta, Account* saa,
182  delete_helper_t delete_res);
183 static void do_delete_account (Account* account, Account* saa, Account* sta,
184  Account* ta);
185 
186 
187 
188 static guint plugin_page_signals[LAST_SIGNAL] = { 0 };
189 
190 
191 static GActionEntry gnc_plugin_page_account_tree_actions [] =
192 {
193  { "FileNewAccountAction", gnc_plugin_page_account_tree_cmd_new_account, NULL, NULL, NULL },
194  { "FileAddAccountHierarchyAssistantAction", gnc_plugin_page_account_tree_cmd_file_new_hierarchy, NULL, NULL, NULL },
195  { "EditOpenAccountAction", gnc_plugin_page_account_tree_cmd_open_account, NULL, NULL, NULL },
196  { "EditOpenSubaccountsAction", gnc_plugin_page_account_tree_cmd_open_subaccounts, NULL, NULL, NULL },
197  { "EditEditAccountAction", gnc_plugin_page_account_tree_cmd_edit_account, NULL, NULL, NULL },
198  { "EditDeleteAccountAction", gnc_plugin_page_account_tree_cmd_delete_account, NULL, NULL, NULL },
199  { "EditCascadeAccountAction", gnc_plugin_page_account_tree_cmd_cascade_account_properties, NULL, NULL, NULL },
200  { "EditFindAccountAction", gnc_plugin_page_account_tree_cmd_find_account, NULL, NULL, NULL },
201  { "EditFindAccountPopupAction", gnc_plugin_page_account_tree_cmd_find_account_popup, NULL, NULL, NULL },
202  { "EditRenumberSubaccountsAction", gnc_plugin_page_account_tree_cmd_renumber_accounts, NULL, NULL, NULL },
203  { "EditTaxOptionsAction", gnc_plugin_page_account_tree_cmd_edit_tax_options, NULL, NULL, NULL },
204  { "ViewFilterByAction", gnc_plugin_page_account_tree_cmd_view_filter_by, NULL, NULL, NULL },
205  { "ViewRefreshAction", gnc_plugin_page_account_tree_cmd_refresh, NULL, NULL, NULL },
206  { "ActionsReconcileAction", gnc_plugin_page_account_tree_cmd_reconcile, NULL, NULL, NULL },
207  { "ActionsAutoClearAction", gnc_plugin_page_account_tree_cmd_autoclear, NULL, NULL, NULL },
208  { "ActionsTransferAction", gnc_plugin_page_account_tree_cmd_transfer, NULL, NULL, NULL },
209  { "ActionsStockSplitAction", gnc_plugin_page_account_tree_cmd_stock_split, NULL, NULL, NULL },
210  { "ActionsStockAssistantAction", gnc_plugin_page_account_tree_cmd_stock_assistant, NULL, NULL, NULL },
211  { "ActionsLotsAction", gnc_plugin_page_account_tree_cmd_lots, NULL, NULL, NULL },
212  { "ScrubAction", gnc_plugin_page_account_tree_cmd_scrub, NULL, NULL, NULL },
213  { "ScrubSubAction", gnc_plugin_page_account_tree_cmd_scrub_sub, NULL, NULL, NULL },
214  { "ScrubAllAction", gnc_plugin_page_account_tree_cmd_scrub_all, NULL, NULL, NULL },
215 };
217 static guint gnc_plugin_page_account_tree_n_actions = G_N_ELEMENTS(gnc_plugin_page_account_tree_actions);
218 
220 static const gchar *gnc_plugin_load_ui_items [] =
221 {
222  "FilePlaceholder3",
223  "EditPlaceholder1",
224  "EditPlaceholder2",
225  "EditPlaceholder3",
226  "EditPlaceholder5",
227  "ViewPlaceholder1",
228  "ViewPlaceholder4",
229  "ActionsPlaceholder4",
230  "ActionsPlaceholder5",
231  "ActionsPlaceholder6",
232  NULL,
233 };
234 
235 
236 
237 
240 static const gchar *actions_requiring_account_rw[] =
241 {
242  "EditEditAccountAction",
243  "EditDeleteAccountAction",
244  "ActionsReconcileAction",
245  "ActionsAutoClearAction",
246  NULL
247 };
248 
251 static const gchar *actions_requiring_subaccounts_rw[] =
252 {
253  "EditRenumberSubaccountsAction",
254  "EditCascadeAccountAction",
255  NULL
256 };
257 
260 static const gchar *actions_requiring_account_always[] =
261 {
262  "EditOpenAccountAction",
263  "EditOpenSubaccountsAction",
264  "ActionsLotsAction",
265  NULL
266 };
267 
268 static const gchar* actions_requiring_priced_account[] =
269 {
270  "ActionsStockAssistantAction",
271  NULL
272 };
273 
274 /* This is the list of actions which are switched inactive in a read-only book. */
275 static const gchar* readonly_inactive_actions[] =
276 {
277  "FileNewAccountAction",
278  "FileAddAccountHierarchyAssistantAction",
279  "EditEditAccountAction",
280  "EditDeleteAccountAction",
281  "ActionsTransferAction",
282  "ActionsReconcileAction",
283  "ActionsAutoClearAction",
284  "ActionsStockSplitAction",
285  "ScrubAction",
286  "ScrubSubAction",
287  "ScrubAllAction",
288  NULL
289 };
290 
292 static GncToolBarShortNames toolbar_labels[] =
293 {
294  { "EditOpenAccountAction", N_("Open") },
295  { "EditEditAccountAction", N_("Edit") },
296  { "FileNewAccountAction", N_("New") },
297  { "EditDeleteAccountAction", N_("Delete") },
298  { NULL, NULL },
299 };
300 
303 {
304  ENTER(" ");
305  auto plugin_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE
306  (g_object_new (GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, nullptr));
307 
308  LEAVE("new account tree page %p", plugin_page);
309  return GNC_PLUGIN_PAGE (plugin_page);
310 }
311 
312 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageAccountTree, gnc_plugin_page_account_tree, GNC_TYPE_PLUGIN_PAGE)
313 
314 static gboolean show_abort_verify = TRUE;
315 
316 static void
317 prepare_scrubbing ()
318 {
319  gnc_suspend_gui_refresh ();
320  gnc_set_abort_scrub (FALSE);
321 }
322 
323 static void
324 finish_scrubbing (GncWindow *window, gulong handler_id)
325 {
326  g_signal_handler_disconnect (G_OBJECT(window), handler_id);
327  show_abort_verify = TRUE;
328  gnc_resume_gui_refresh ();
329 }
330 
331 static const char*
332 check_repair_abort_YN = N_("'Check & Repair' is currently running, do you want to abort it?");
333 
334 static gboolean
335 gnc_plugin_page_account_finish_pending (GncPluginPage* page)
336 {
337  if (gnc_get_ongoing_scrub ())
338  {
339  if (show_abort_verify)
340  {
341  gboolean ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window
342  (GNC_PLUGIN_PAGE(page))), FALSE,
343  "%s", _(check_repair_abort_YN));
344 
345  show_abort_verify = FALSE;
346 
347  if (ret)
348  gnc_set_abort_scrub (TRUE);
349 
350  return ret; // verify response
351  }
352  else
353  {
354  if (gnc_get_abort_scrub ())
355  return TRUE; // close
356  else
357  return FALSE; // no close
358  }
359  }
360  else
361  return TRUE; // normal close
362 }
363 
364 static void
365 gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
366 {
367  GObjectClass *object_class = G_OBJECT_CLASS (klass);
368  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
369 
370  object_class->finalize = gnc_plugin_page_account_tree_finalize;
371 
372  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
373  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
374  gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget;
375  gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget;
376  gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
377  gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
378  gnc_plugin_class->focus_page_function = gnc_plugin_page_account_tree_focus_widget;
379  gnc_plugin_class->finish_pending = gnc_plugin_page_account_finish_pending;
380 
381  plugin_page_signals[ACCOUNT_SELECTED] =
382  g_signal_new ("account_selected",
383  G_OBJECT_CLASS_TYPE (object_class),
384  G_SIGNAL_RUN_FIRST,
385  G_STRUCT_OFFSET (GncPluginPageAccountTreeClass, account_selected),
386  NULL, NULL,
387  g_cclosure_marshal_VOID__POINTER,
388  G_TYPE_NONE, 1,
389  G_TYPE_POINTER);
390 }
391 
392 static void
393 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
394 {
395  GSimpleActionGroup *simple_action_group = NULL;
397  GncPluginPage *parent;
398  const GList *page_list;
399 
400  ENTER("page %p", plugin_page);
401  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(plugin_page);
402 
403  /* Init parent declared variables */
404  parent = GNC_PLUGIN_PAGE(plugin_page);
405  g_object_set (G_OBJECT(plugin_page),
406  "page-name", _("Accounts"),
407  "ui-description", "gnc-plugin-page-account-tree.ui",
408  NULL);
409  g_signal_connect (G_OBJECT (plugin_page), "selected",
410  G_CALLBACK (gnc_plugin_page_account_tree_selected), plugin_page);
411 
412  /* change me when the system supports multiple books */
413  gnc_plugin_page_add_book (parent, gnc_get_current_book());
414 
415  /* Is this the first accounts page? */
416  page_list =
417  gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
418  if (!page_list || plugin_page == page_list->data)
419  {
420  g_object_set_data (G_OBJECT(plugin_page), PLUGIN_PAGE_IMMUTABLE,
421  GINT_TO_POINTER(1));
422  }
423 
424  /* Create menu and toolbar information */
425  simple_action_group = gnc_plugin_page_create_action_group (parent, "GncPluginPageAccountTreeActions");
426  g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
427  gnc_plugin_page_account_tree_actions,
428  gnc_plugin_page_account_tree_n_actions,
429  plugin_page);
430 
431  /* Visible types */
432  priv->fd.visible_types = -1; /* Start with all types */
433  priv->fd.show_hidden = FALSE;
434  priv->fd.show_unused = TRUE;
435  priv->fd.show_zero_total = TRUE;
436  priv->fd.filter_override = g_hash_table_new (g_direct_hash, g_direct_equal);
437 
438  LEAVE("page %p, priv %p, action group %p",
439  plugin_page, priv, simple_action_group);
440 }
441 
442 static void
443 gnc_plugin_page_account_tree_finalize (GObject *object)
444 {
447 
448  ENTER("object %p", object);
449  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (object);
450  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
451  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
452  g_return_if_fail (priv != NULL);
453 
454  G_OBJECT_CLASS (gnc_plugin_page_account_tree_parent_class)->finalize (object);
455  LEAVE(" ");
456 }
457 
458 void
459 gnc_plugin_page_account_tree_open (Account *account, GtkWindow *win)
460 {
463  GncPluginPage *plugin_page = NULL;
464  const GList *page_list;
465  GtkWidget *window;
466 
467  /* Find Accounts page */
468  page_list = gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
469 
470  // If we have a window, look for account page in that window
471  if (gnc_list_length_cmp (page_list, 0))
472  {
473  if (win != NULL)
474  {
475  for ( ; page_list; page_list = g_list_next(page_list))
476  {
477  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
478  if (GTK_WINDOW(plugin_page->window) == win)
479  break;
480  }
481  }
482  else // if no window, open first account page in list
483  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
484  }
485  else // we have no account pages, create one
486  plugin_page = gnc_plugin_page_account_tree_new ();
487 
488  g_return_if_fail(plugin_page);
489  window = plugin_page->window;
490 
491  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), plugin_page);
492 
493  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
494  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
495 
496  if (account != NULL)
497  {
498  Account *root_account = gnc_get_current_root_account ();
499  Account *parent_account = NULL;
500  Account *temp_account = account;
501 
502  g_hash_table_insert (priv->fd.filter_override, account, account);
503 
504  // make sure we override all the parent accounts to root
505  while (parent_account != root_account)
506  {
507  parent_account = gnc_account_get_parent (temp_account);
508 
509  g_hash_table_insert (priv->fd.filter_override, parent_account, parent_account);
510  temp_account = parent_account;
511  }
512  gnc_tree_view_account_refilter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
513  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), account);
514  }
515 }
516 
517 Account *
519 {
521  Account *account;
522 
523  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
524  ENTER("page %p (tree view %p)", page, priv->tree_view);
525  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
526  if (account == NULL)
527  {
528  LEAVE("no account");
529  return NULL;
530  }
531 
532  LEAVE("account %p", account);
533  return account;
534 }
535 
540 static gboolean
541 gnc_plugin_page_account_tree_focus_widget (GncPluginPage *account_plugin_page)
542 {
543  if (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(account_plugin_page))
544  {
545  GncPluginPageAccountTreePrivate *priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_plugin_page);
546  GtkTreeView *view = GTK_TREE_VIEW(priv->tree_view);
547 
548  /* Disable the Transaction Menu */
549  GAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(account_plugin_page->window), "TransactionAction");
550  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
551  /* Disable the Schedule menu */
552  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(account_plugin_page->window), "ScheduledAction");
553  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
554 
555  gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(account_plugin_page->window),
556  account_plugin_page,
557  gnc_plugin_load_ui_items);
558 
559  // setup any short toolbar names
560  gnc_main_window_init_short_names (GNC_MAIN_WINDOW(account_plugin_page->window), toolbar_labels);
561 
562  /* Disable the FilePrintAction */
563  action = gnc_main_window_find_action (GNC_MAIN_WINDOW(account_plugin_page->window), "FilePrintAction");
564  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
565 
566  if (!gtk_widget_is_focus (GTK_WIDGET(view)))
567  gtk_widget_grab_focus (GTK_WIDGET(view));
568  }
569  return FALSE;
570 }
571 
572 /* Virtual Functions */
573 
574 static void
575 gnc_plugin_page_account_refresh_cb (GHashTable *changes, gpointer user_data)
576 {
577  /* We're only looking for forced updates here. */
578  if (!changes)
579  gnc_plugin_page_account_tree_cmd_refresh(NULL, NULL, user_data);
580 }
581 
582 static void
583 gnc_plugin_page_account_tree_close_cb (gpointer user_data)
584 {
585  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
586  gnc_main_window_close_page(plugin_page);
587 }
588 
589 static void
590 gnc_plugin_page_account_editing_started_cd (gpointer various, GncPluginPageRegister *page)
591 {
592  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
593  GAction *action = gnc_main_window_find_action_in_group (GNC_MAIN_WINDOW(plugin_page->window),
594  "GncPluginPageAccountTreeActions",
595  "EditDeleteAccountAction");
596  if (action != NULL)
597  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
598 }
599 
600 static void
601 gnc_plugin_page_account_editing_finished_cb (gpointer various, GncPluginPageRegister *page)
602 {
603  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
604  GAction *action = gnc_main_window_find_action_in_group (GNC_MAIN_WINDOW(plugin_page->window),
605  "GncPluginPageAccountTreeActions",
606  "EditDeleteAccountAction");
607  if (action != NULL)
608  g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
609 }
610 
611 static GtkWidget *
612 gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page)
613 {
616  GtkTreeSelection *selection;
617  GtkTreeView *tree_view;
618  GtkWidget *scrolled_window;
619  GtkTreeViewColumn *col;
620 
621  ENTER("page %p", plugin_page);
622  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
623  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
624  if (priv->widget != NULL)
625  {
626  LEAVE("widget = %p", priv->widget);
627  return priv->widget;
628  }
629 
630  priv->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
631  gtk_box_set_homogeneous (GTK_BOX (priv->widget), FALSE);
632  gtk_widget_show (priv->widget);
633 
634  // Set the name for this widget so it can be easily manipulated with css
635  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-account-page");
636 
637  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
638  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
639  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
640  gtk_widget_show (scrolled_window);
641  gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window,
642  TRUE, TRUE, 0);
643 
644  tree_view = gnc_tree_view_account_new(FALSE);
646  GNC_TREE_VIEW(tree_view), "description");
647  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
649  GNC_TREE_VIEW(tree_view), "total");
650  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
651  gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view));
652  g_object_set(G_OBJECT(tree_view),
653  "state-section", STATE_SECTION,
654  "show-column-menu", TRUE,
655  NULL);
656 
657  /* No name handler; then the user can't click on the name of the
658  account to open its register. */
659  gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
660  gnc_tree_view_account_code_edited_cb);
661  gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
662  gnc_tree_view_account_description_edited_cb);
663  gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
664  gnc_tree_view_account_notes_edited_cb);
665 
666  // Setup some callbacks so menu actions can be disabled/enabled
667  gnc_tree_view_account_set_editing_started_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
668  (GFunc)gnc_plugin_page_account_editing_started_cd, page);
669  gnc_tree_view_account_set_editing_finished_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
670  (GFunc)gnc_plugin_page_account_editing_finished_cb, page);
671 
672  priv->tree_view = tree_view;
673  selection = gtk_tree_view_get_selection(tree_view);
674  g_signal_connect (G_OBJECT (selection), "changed",
675  G_CALLBACK (gnc_plugin_page_account_tree_selection_changed_cb), page);
676  g_signal_connect (G_OBJECT (tree_view), "button-press-event",
677  G_CALLBACK (gnc_plugin_page_account_tree_button_press_cb), page);
678  g_signal_connect (G_OBJECT (tree_view), "row-activated",
679  G_CALLBACK (gnc_plugin_page_account_tree_double_click_cb), page);
680 
681  gtk_tree_view_set_headers_visible(tree_view, TRUE);
682  gnc_plugin_page_account_tree_selection_changed_cb (NULL, page);
683  gtk_widget_show (GTK_WIDGET (tree_view));
684  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(tree_view));
685 
686  priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view);
688  GNC_TREE_VIEW_ACCOUNT(tree_view),
690 
691  priv->component_id =
692  gnc_register_gui_component(PLUGIN_PAGE_ACCT_TREE_CM_CLASS,
693  gnc_plugin_page_account_refresh_cb,
694  gnc_plugin_page_account_tree_close_cb,
695  page);
696  gnc_gui_component_set_session (priv->component_id,
697  gnc_get_current_session());
698 
699  plugin_page->summarybar = gnc_main_window_summary_new();
700  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
701  FALSE, FALSE, 0);
702  gtk_widget_show(plugin_page->summarybar);
703  gnc_plugin_page_account_tree_summarybar_position_changed(NULL, NULL, page);
704  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
705  GNC_PREF_SUMMARYBAR_POSITION_TOP,
706  (gpointer)gnc_plugin_page_account_tree_summarybar_position_changed,
707  page);
708  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
709  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
710  (gpointer)gnc_plugin_page_account_tree_summarybar_position_changed,
711  page);
712 
713  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_CHOICE_ABS,
714  (gpointer)accounting_period_changed_cb, page);
715  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_DATE,
716  (gpointer)accounting_period_changed_cb, page);
717  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_PERIOD,
718  (gpointer)accounting_period_changed_cb, page);
719  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_CHOICE_ABS,
720  (gpointer)accounting_period_changed_cb, page);
721  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_DATE,
722  (gpointer)accounting_period_changed_cb, page);
723  gnc_prefs_register_cb(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_PERIOD,
724  (gpointer)accounting_period_changed_cb, page);
725 
726  g_signal_connect (G_OBJECT(plugin_page), "inserted",
727  G_CALLBACK(gnc_plugin_page_inserted_cb),
728  NULL);
729 
730  // Read account filter state information from account section
731  gnc_tree_view_account_restore_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
732  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
733 
734  LEAVE("widget = %p", priv->widget);
735  return priv->widget;
736 }
737 
738 static void
739 gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page)
740 {
743 
744  ENTER("page %p", plugin_page);
745  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
746  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
747 
748  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
749  GNC_PREF_SUMMARYBAR_POSITION_TOP,
750  (gpointer)gnc_plugin_page_account_tree_summarybar_position_changed,
751  page);
752  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
753  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
754  (gpointer)gnc_plugin_page_account_tree_summarybar_position_changed,
755  page);
756 
757  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_CHOICE_ABS,
758  (gpointer)accounting_period_changed_cb, page);
759  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_DATE,
760  (gpointer)accounting_period_changed_cb, page);
761  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_START_PERIOD,
762  (gpointer)accounting_period_changed_cb, page);
763  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_CHOICE_ABS,
764  (gpointer)accounting_period_changed_cb, page);
765  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_DATE,
766  (gpointer)accounting_period_changed_cb, page);
767  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_ACCT_SUMMARY, GNC_PREF_END_PERIOD,
768  (gpointer)accounting_period_changed_cb, page);
769 
770 // Save account filter state information to account section
771  gnc_tree_view_account_save_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
772  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
773 
774  // Destroy the filter override hash table
775  g_hash_table_destroy(priv->fd.filter_override);
776 
777  // Remove the page_changed signal callback
778  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
779 
780  // Remove the page focus idle function if present
781  g_idle_remove_by_data (plugin_page);
782 
783  if (priv->widget)
784  {
785  g_object_unref(G_OBJECT(priv->widget));
786  priv->widget = NULL;
787  }
788 
789  if (priv->component_id)
790  {
791  gnc_unregister_gui_component(priv->component_id);
792  priv->component_id = 0;
793  }
794 
795  LEAVE("widget destroyed");
796 }
797 
798 static void
799 update_inactive_actions (GncPluginPage *plugin_page)
800 {
802  GSimpleActionGroup *simple_action_group = NULL;
803  Account *account = NULL;
804  gboolean allow_write = !qof_book_is_readonly (gnc_get_current_book());
805  gboolean has_account = FALSE;
806  gboolean subaccounts = FALSE;
807 
808  g_return_if_fail (plugin_page && GNC_IS_PLUGIN_PAGE(plugin_page));
809 
810  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE (plugin_page);
811 
812  if (gtk_tree_view_get_selection (priv->tree_view))
813  {
814  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
815  has_account = (account != NULL);
816  subaccounts = (account && gnc_account_n_children (account) != 0);
817  /* Check here for placeholder accounts, etc. */
818  }
819 
820  /* Get the action group */
821  simple_action_group = gnc_plugin_page_get_action_group (plugin_page);
822  g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple_action_group));
823 
824  /* Set the action's sensitivity */
825  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), readonly_inactive_actions,
826  allow_write);
827  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account_rw,
828  allow_write && has_account);
829  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account_always,
830  has_account);
831  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_subaccounts_rw,
832  allow_write && subaccounts);
833  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_priced_account,
834  account && xaccAccountIsPriced (account));
835 
836  g_signal_emit (plugin_page, plugin_page_signals[ACCOUNT_SELECTED], 0, account);
837 }
838 
843 static void
844 gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data)
845 {
846  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object);
847  g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page));
848  update_inactive_actions(plugin_page);
849 }
850 
860 static void
861 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
862  GKeyFile *key_file,
863  const gchar *group_name)
864 {
865  GncPluginPageAccountTree *account_page;
867 
868  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
869  g_return_if_fail (key_file != NULL);
870  g_return_if_fail (group_name != NULL);
871 
872  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
873  group_name);
874 
875  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
876  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
877 
878  gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
879  &priv->fd, key_file, group_name);
880  LEAVE(" ");
881 }
882 
883 
884 
894 static GncPluginPage *
895 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
896  GKeyFile *key_file,
897  const gchar *group_name)
898 {
899  GncPluginPageAccountTree *account_page;
901  GncPluginPage *page;
902 
903  g_return_val_if_fail(key_file, NULL);
904  g_return_val_if_fail(group_name, NULL);
905  ENTER("key_file %p, group_name %s", key_file, group_name);
906 
907  /* Create the new page. */
909  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
910  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
911 
912  /* Install it now so we can then manipulate the created widget */
913  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
914 
915  gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
916  &priv->fd, key_file, group_name);
917  LEAVE(" ");
918  return page;
919 }
920 
921 
922 /* Callbacks */
923 
924 static void
925 gnc_plugin_page_account_tree_summarybar_position_changed (gpointer prefs,
926  gchar* pref,
927  gpointer user_data)
928 {
929  GncPluginPage *plugin_page;
932  GtkPositionType position = GTK_POS_BOTTOM;
933 
934  g_return_if_fail(user_data != NULL);
935 
936  plugin_page = GNC_PLUGIN_PAGE(user_data);
937  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data);
938  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
939 
940  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SUMMARYBAR_POSITION_TOP))
941  position = GTK_POS_TOP;
942 
943  gtk_box_reorder_child(GTK_BOX(priv->widget),
944  plugin_page->summarybar,
945  (position == GTK_POS_TOP ? 0 : -1) );
946 }
947 
955 static gboolean
956 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
957  GdkEventButton *event,
958  GncPluginPage *page)
959 {
960 
961  g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
962 
963  ENTER("widget %p, event %p, page %p", widget, event, page);
964  gnc_main_window_button_press_cb(widget, event, page);
965  LEAVE(" ");
966 
967  /* Always return FALSE. This will let the tree view callback run as
968  * well which will select the item under the cursor. By the time
969  * the user sees the menu both callbacks will have run and the menu
970  * actions will operate on the just-selected account. */
971  return FALSE;
972 }
973 
974 static void
975 gppat_open_account_common (GncPluginPageAccountTree *page,
976  Account *account,
977  gboolean include_subs)
978 {
979  GtkWidget *window;
980  GncPluginPage *new_page;
981 
982  if (account == NULL)
983  return;
984 
985  window = GNC_PLUGIN_PAGE (page)->window;
986  new_page = gnc_plugin_page_register_new (account, include_subs);
987  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
988 }
989 
990 static void
991 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
992  GtkTreePath *path,
993  GtkTreeViewColumn *col,
995 {
996  GtkTreeModel *model;
997  GtkTreeIter iter;
998 
999  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1000  g_return_if_fail (treeview);
1001 
1002  model = gtk_tree_view_get_model(treeview);
1003  if (gtk_tree_model_get_iter(model, &iter, path))
1004  {
1005  Account *account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path);
1006  if (xaccAccountGetPlaceholder (account))
1007  {
1008  /* This is a placeholder account. Only only show/hide
1009  * subaccount list if there is one.
1010  */
1011  if (gtk_tree_model_iter_has_child(model, &iter))
1012  {
1013  /* There are children,
1014  * just expand or collapse the row. */
1015  if (gtk_tree_view_row_expanded(treeview, path))
1016  gtk_tree_view_collapse_row(treeview, path);
1017  else
1018  gtk_tree_view_expand_row(treeview, path, FALSE);
1019  }
1020  }
1021  else
1022  {
1023  /* No placeholder account, so open its register */
1024  gppat_open_account_common (page, account, FALSE);
1025  }
1026  }
1027 }
1028 
1029 static void
1030 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
1032 {
1033  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
1034  update_inactive_actions (plugin_page);
1035 }
1036 
1037 static void
1038 accounting_period_changed_cb (gpointer prefs, gchar *pref, gpointer user_data)
1039 {
1040  gnc_plugin_page_account_tree_cmd_refresh (NULL, NULL, user_data);
1041 }
1042 
1043 /* Command callbacks */
1044 static void
1045 gnc_plugin_page_account_tree_cmd_new_account (GSimpleAction *simple,
1046  GVariant *paramter,
1047  gpointer user_data)
1048 {
1049  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1051  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1052  gnc_ui_new_account_window (parent, gnc_get_current_book(),
1053  account);
1054 }
1055 
1056 static void
1057 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GSimpleAction *simple,
1058  GVariant *paramter,
1059  gpointer user_data)
1060 {
1061  gnc_ui_hierarchy_assistant(FALSE);
1062 }
1063 
1064 static void
1065 gnc_plugin_page_account_tree_cmd_open_account (GSimpleAction *simple,
1066  GVariant *paramter,
1067  gpointer user_data)
1068 {
1069  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1070  Account *account;
1071 
1072  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1074  gppat_open_account_common (page, account, FALSE);
1075 }
1076 
1077 static void
1078 gnc_plugin_page_account_tree_cmd_open_subaccounts (GSimpleAction *simple,
1079  GVariant *paramter,
1080  gpointer user_data)
1081 {
1082  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1083  Account *account;
1084 
1085  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1087  gppat_open_account_common (page, account, TRUE);
1088 }
1089 
1090 static void
1091 gnc_plugin_page_account_tree_cmd_edit_account (GSimpleAction *simple,
1092  GVariant *paramter,
1093  gpointer user_data)
1094 {
1095  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1096  Account *account;
1097  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1098  ENTER("action %p, page %p", simple, page);
1099 
1101  g_return_if_fail (account != NULL);
1102 
1103  gnc_ui_edit_account_window (parent, account);
1104  LEAVE(" ");
1105 }
1106 
1107 static void
1108 gnc_plugin_page_account_tree_cmd_find_account (GSimpleAction *simple,
1109  GVariant *paramter,
1110  gpointer user_data)
1111 {
1112  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1113  GtkWidget *window;
1114 
1115  ENTER("action %p, page %p", simple, page);
1116 
1117  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1118 
1119  gnc_find_account_dialog (window, NULL);
1120  LEAVE(" ");
1121 }
1122 
1123 static void
1124 gnc_plugin_page_account_tree_cmd_find_account_popup (GSimpleAction *simple,
1125  GVariant *paramter,
1126  gpointer user_data)
1127 {
1128  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1129  Account *account = NULL;
1130  GtkWidget *window;
1131 
1132  ENTER("action %p, page %p", simple, page);
1133 
1135 
1136  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1137 
1138  gnc_find_account_dialog (window, account);
1139  LEAVE(" ");
1140 }
1141 
1142 static void
1143 gnc_plugin_page_account_tree_cmd_cascade_account_properties (GSimpleAction *simple,
1144  GVariant *paramter,
1145  gpointer user_data)
1146 {
1147  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1148  Account *account = NULL;
1149  GtkWidget *window;
1150 
1151  ENTER("action %p, page %p", simple, page);
1152 
1154 
1155  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page));
1156 
1157  if (account != NULL)
1158  gnc_account_cascade_properties_dialog (window, account);
1159 
1160  LEAVE(" ");
1161 }
1162 
1163 static gpointer
1164 delete_account_helper (Account * account, gpointer data)
1165 {
1166  auto helper_res = static_cast<delete_helper_t*>(data);
1167  auto& splits{xaccAccountGetSplits (account)};
1168  auto split_ro = [](auto s) -> bool { return xaccTransGetReadOnly (xaccSplitGetParent (s)); };
1169 
1170  helper_res->has_splits = !splits.empty();
1171  helper_res->has_ro_splits = std::any_of (splits.begin(), splits.end(), split_ro);
1172 
1173  return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits);
1174 }
1175 
1176 /***
1177  *** The OK button of a Delete Account dialog is insensitive if
1178  *** and only if a sensitive account selector contains no accounts.
1179  ***/
1180 static void
1181 set_ok_sensitivity(GtkWidget *dialog)
1182 {
1183  gboolean sensitive;
1184 
1185  auto sa_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS));
1186  auto trans_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS));
1187 
1188  sensitive = ((!sa_mas ||
1189  !gtk_widget_is_sensitive (sa_mas) ||
1190  gnc_account_sel_get_visible_account_num (GNC_ACCOUNT_SEL (sa_mas))) &&
1191  (!trans_mas ||
1192  !gtk_widget_is_sensitive (trans_mas) ||
1193  gnc_account_sel_get_visible_account_num (GNC_ACCOUNT_SEL (trans_mas))));
1194 
1195  auto button = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON));
1196  gtk_widget_set_sensitive(button, sensitive);
1197 }
1198 
1199 static GList *
1200 gppat_get_exclude_list (Account *acc, gboolean exclude_subaccounts)
1201 {
1202  GList *acct_list = NULL;
1203 
1204  if (exclude_subaccounts)
1205  acct_list = gnc_account_get_descendants (acc);
1206 
1207  acct_list = g_list_prepend (acct_list, acc);
1208 
1209  return acct_list;
1210 }
1211 
1212 static void
1213 gppat_populate_gas_list(GtkWidget *dialog,
1214  GNCAccountSel *gas,
1215  gboolean exclude_subaccounts)
1216 {
1217  Account *account;
1218  GList *filter;
1219  GList *exclude;
1220 
1221  g_return_if_fail(GTK_IS_DIALOG(dialog));
1222  if (gas == NULL)
1223  return;
1224  account = GNC_ACCOUNT(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT));
1225  filter = static_cast<GList*>(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER));
1226 
1227  /* Setting the account type filter triggers GNCAccountSel population. */
1228  gnc_account_sel_set_acct_filters (gas, filter, NULL);
1229 
1230  /* Accounts to be deleted must be excluded from GAS. */
1231  exclude = gppat_get_exclude_list (account, exclude_subaccounts);
1232  gnc_account_sel_set_acct_exclude_filter (gas, exclude);
1233  g_list_free (exclude);
1234 
1235  gnc_account_sel_set_account (gas, NULL, TRUE);
1236 
1237  /* The sensitivity of the OK button needs to be reevaluated. */
1238  set_ok_sensitivity(dialog);
1239 }
1240 
1241 void
1242 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb,
1243  GtkWidget *dialog)
1244 {
1245  g_return_if_fail(GTK_IS_DIALOG(dialog));
1246 
1247  /* Cannot move transactions to subaccounts if they are to be deleted. */
1248  auto trans_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS));
1249  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb));
1250 }
1251 
1252 /* Note that the emitting object (the toggle button) and the signal data
1253  * are swapped in below callback function. This is a gtkbuilder feature:
1254  * it swaps if you explicitly set an object for a signal handler in the
1255  * gtkbuilder xml file.
1256  */
1257 void
1258 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b)
1259 {
1260  GtkWidget *dialog = gtk_widget_get_toplevel(widget);
1261  auto subaccount_trans = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS));
1262  auto sa_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS));
1263  auto have_splits = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS) != nullptr;
1264 
1265  gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b));
1266 
1267  // If we have subaccount splits & delete subaccounts, enable subaccount_trans
1268  if ((have_splits) && !gtk_widget_is_sensitive(sa_mas))
1269  gtk_widget_set_sensitive(subaccount_trans, TRUE);
1270  else
1271  gtk_widget_set_sensitive(subaccount_trans, FALSE);
1272 
1273  set_ok_sensitivity(dialog);
1274 }
1275 
1276 static GtkWidget *
1277 gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
1278  const gchar *hbox, const gchar *sel_name)
1279 {
1280  GtkWidget *selector = gnc_account_sel_new();
1281  GtkWidget *box = GTK_WIDGET(gtk_builder_get_object (builder, hbox));
1282 
1283  gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
1284 
1285  // placeholder accounts are OK for this GAS
1286  if (g_strcmp0 (sel_name, DELETE_DIALOG_SA_MAS) == 0)
1287  g_object_set (selector, "hide-placeholder", FALSE, NULL);
1288 
1289  g_object_set_data(G_OBJECT(dialog), sel_name, selector);
1290 
1291  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(selector), TRUE);
1292  gtk_widget_show_all(box);
1293 
1294  return selector;
1295 }
1296 
1297 static int
1298 commodity_mismatch_dialog (const Account* account, GtkWindow* parent)
1299 {
1300  int response;
1301  char *account_name = gnc_account_get_full_name (account);
1302  char* message = g_strdup_printf (
1303  _("Account %s does not have the same currency as the one you're "
1304  "moving transactions from.\nAre you sure you want to do this?"),
1305  account_name);
1306  GtkWidget* error_dialog =
1307  gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
1308  GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
1309  "%s", message);
1310  gtk_dialog_add_buttons (GTK_DIALOG(error_dialog),
1311  _("_Pick another account"), GTK_RESPONSE_CANCEL,
1312  _("_Do it anyway"), GTK_RESPONSE_ACCEPT,
1313  (gchar *)NULL);
1314  response = gtk_dialog_run (GTK_DIALOG (error_dialog));
1315  gtk_widget_destroy (error_dialog);
1316  g_free (message);
1317  g_free (account_name);
1318  return response;
1319 }
1320 
1321 typedef struct
1322 {
1323  Account *new_account;
1324  Account *old_account;
1325  GNCAccountSel *selector;
1326  gboolean match;
1327  gboolean for_account;
1328 } Adopter;
1329 
1330 static void
1331 adopter_set_account_and_match (Adopter* adopter)
1332 {
1333  if (!(adopter->selector &&
1334  gtk_widget_is_sensitive (GTK_WIDGET (adopter->selector))))
1335  return;
1336  adopter->new_account = gnc_account_sel_get_account(adopter->selector);
1337 /* We care about the commodity only if we're moving transactions. */
1338  if (!adopter->for_account && adopter->old_account && adopter->new_account)
1339  adopter->match =
1340  xaccAccountGetCommodity (adopter->new_account) ==
1341  xaccAccountGetCommodity (adopter->old_account);
1342 }
1343 
1344 static void
1345 adopter_init (Adopter* adopter, GtkWidget *selector, Account* account,
1346  gboolean for_account)
1347 {
1348  adopter->selector = GNC_ACCOUNT_SEL (selector);
1349  adopter->new_account = NULL;
1350  adopter->old_account = account;
1351  adopter->match = TRUE;
1352  adopter->for_account = for_account;
1353 }
1354 
1355 static gboolean
1356 adopter_match (Adopter* adopter, GtkWindow *parent)
1357 {
1358  int result;
1359  if (adopter->match || adopter->for_account)
1360  return TRUE;
1361  result = commodity_mismatch_dialog (adopter->new_account, parent);
1362  return (result == GTK_RESPONSE_ACCEPT);
1363 }
1364 
1365 typedef struct
1366 {
1367  Adopter trans;
1368  Adopter subacct;
1369  Adopter subtrans;
1370  delete_helper_t delete_res;
1371 } Adopters;
1372 
1373 static Account*
1374 account_subaccount (Account* account)
1375 {
1376  Account* subaccount = NULL;
1377  GList *subs = gnc_account_get_children (account);
1378  if (!gnc_list_length_cmp (subs, 1))
1379  subaccount = GNC_ACCOUNT(subs->data);
1380  g_list_free (subs);
1381  return subaccount;
1382 }
1383 
1384 static GtkWidget*
1385 account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
1386 {
1387  GtkWidget *dialog = NULL;
1388  GtkWidget *widget = NULL;
1389  gchar *title = NULL;
1390  GtkBuilder *builder = gtk_builder_new();
1391  gchar *acct_name = gnc_account_get_full_name(account);
1392  GList* filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
1393 
1394  if (!acct_name)
1395  acct_name = g_strdup (_("(no name)"));
1396 
1397  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_delete_dialog");
1398 
1399  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_delete_dialog"));
1400  gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
1401 
1402  /* FIXME: Same account type used for subaccount. */
1403  g_object_set_data_full (G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter,
1404  (GDestroyNotify) g_list_free);
1405  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account);
1406  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header"));
1407  title = g_strdup_printf(_("Deleting account %s"), acct_name);
1408  gtk_label_set_text(GTK_LABEL(widget), title);
1409  g_free(title);
1410  g_free(acct_name);
1411 
1412  widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON));
1413  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget);
1414 
1415  // Add the account selectors and enable sections as appropriate
1416  // setup transactions selector
1417  adopter_init (&adopt->trans,
1418  gppat_setup_account_selector (builder, dialog,
1419  "trans_mas_hbox",
1420  DELETE_DIALOG_TRANS_MAS),
1421  account, FALSE);
1422 
1423  // Does the selected account have splits
1424  if (!xaccAccountGetSplits(account).empty())
1425  {
1426  delete_helper_t delete_res2 = { FALSE, FALSE };
1427 
1428  delete_account_helper(account, &delete_res2);
1429  if (delete_res2.has_ro_splits)
1430  {
1431  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw")));
1432  widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb"));
1433  gtk_widget_set_sensitive(widget, FALSE);
1434  }
1435  else
1436  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1437  }
1438  else
1439  {
1440  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "transactions")), FALSE);
1441  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1442  }
1443 
1444  // setup subaccount account selector
1445  adopter_init (&adopt->subacct,
1446  gppat_setup_account_selector (builder, dialog,
1447  "sa_mas_hbox",
1448  DELETE_DIALOG_SA_MAS),
1449  account, TRUE);
1450 
1451  // setup subaccount transaction selector
1452  adopter_init (&adopt->subtrans,
1453  gppat_setup_account_selector (builder, dialog,
1454  "sa_trans_mas_hbox",
1455  DELETE_DIALOG_SA_TRANS_MAS),
1456  account_subaccount (account), FALSE);
1457  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS,
1458  GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1459 
1460  if (gnc_account_n_children(account) > 0)
1461  {
1462  // Check for RO txns in descendants
1463  gnc_account_foreach_descendant_until(account, delete_account_helper,
1464  &adopt->delete_res);
1465  if (adopt->delete_res.has_splits)
1466  {
1467  if (adopt->delete_res.has_ro_splits)
1468  {
1469  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw")));
1470  widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb"));
1471  gtk_widget_set_sensitive(widget, FALSE);
1472  }
1473  else
1474  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1475 
1476  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(1));
1477  }
1478  else
1479  {
1480  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(0));
1481  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1482  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1483  }
1484  }
1485  else
1486  {
1487  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts")), FALSE);
1488  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1489  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1490  }
1491 
1492  /* default to cancel */
1493  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1494 
1495  gtk_builder_connect_signals(builder, dialog);
1496  g_object_unref(G_OBJECT(builder));
1497 
1498  return dialog;
1499 }
1500 
1501 static void
1502 gnc_plugin_page_account_tree_cmd_delete_account (GSimpleAction *simple,
1503  GVariant *paramter,
1504  gpointer user_data)
1505 {
1506  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1508  gchar *acct_name;
1509  GtkWidget *window;
1510  Adopters adopt;
1511  GList* list;
1512  gint response;
1513  GtkWidget *dialog = NULL;
1514 
1515  if (account == NULL)
1516  return;
1517 
1519  return;
1520 
1521  memset (&adopt, 0, sizeof (adopt));
1522  /* If the account has objects referring to it, show the list - the account can't be deleted until these
1523  references are dealt with. */
1524  list = qof_instance_get_referring_object_list(QOF_INSTANCE(account));
1525  if (list != NULL)
1526  {
1527 #define EXPLANATION _("The list below shows objects which make use of the account which you want to delete.\nBefore you can delete it, you must either delete those objects or else modify them so they make use\nof another account")
1528 
1529  gnc_ui_object_references_show(EXPLANATION, list);
1530  g_list_free(list);
1531  return;
1532  }
1533  g_list_free (list);
1534 
1535  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1536  acct_name = gnc_account_get_full_name(account);
1537  if (!acct_name)
1538  acct_name = g_strdup (_("(no name)"));
1539 
1540  if (gnc_account_n_children(account) > 1) {
1541  gchar* message = g_strdup_printf(_("The account \"%s\" has more than one subaccount.\n\nMove the subaccounts or delete them before attempting to delete this account."), acct_name);
1542  gnc_error_dialog(GTK_WINDOW(window),"%s", message);
1543  g_free (message);
1544  g_free(acct_name);
1545  return;
1546  }
1547  g_free (acct_name);
1548 
1549  // If no transaction or children just delete it.
1550  if (xaccAccountGetSplits (account).empty() && gnc_account_n_children (account) == 0)
1551  {
1552  do_delete_account (account, NULL, NULL, NULL);
1553  return;
1554  }
1555 
1556  dialog = account_delete_dialog (account, GTK_WINDOW (window), &adopt);
1557 
1558  while (TRUE)
1559  {
1560  response = gtk_dialog_run(GTK_DIALOG(dialog));
1561 
1562  if (response != GTK_RESPONSE_ACCEPT)
1563  {
1564  gtk_widget_destroy(dialog);
1565  return;
1566  }
1567  adopter_set_account_and_match (&adopt.trans);
1568  adopter_set_account_and_match (&adopt.subacct);
1569  adopter_set_account_and_match (&adopt.subtrans);
1570 
1571  if (adopter_match (&adopt.trans, GTK_WINDOW (window)) &&
1572  adopter_match (&adopt.subacct, GTK_WINDOW (window)) &&
1573  adopter_match (&adopt.subtrans, GTK_WINDOW (window)))
1574  break;
1575  }
1576  gtk_widget_destroy(dialog);
1577  if (confirm_delete_account (simple, page, adopt.trans.new_account,
1578  adopt.subtrans.new_account,
1579  adopt.subacct.new_account,
1580  adopt.delete_res) == GTK_RESPONSE_ACCEPT)
1581  {
1582  do_delete_account (account, adopt.subacct.new_account,
1583  adopt.subtrans.new_account, adopt.trans.new_account);
1584  }
1585 }
1586 
1587 static int
1588 confirm_delete_account (GSimpleAction *simple, GncPluginPageAccountTree *page,
1589  Account* ta, Account* sta, Account* saa,
1590  delete_helper_t delete_res)
1591 {
1593  GtkWidget* window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1594  gint response;
1595 
1596  char *lines[6] = {0};
1597  char *message;
1598  int i = 0;
1599  GtkWidget *dialog;
1600  gchar* acct_name = gnc_account_get_full_name(account);
1601 
1602  lines[i] = g_strdup_printf (_("The account %s will be deleted."),
1603  acct_name);
1604  g_free(acct_name);
1605 
1606  if (!xaccAccountGetSplits (account).empty())
1607  {
1608  if (ta)
1609  {
1610  char *name = gnc_account_get_full_name(ta);
1611  lines[++i] = g_strdup_printf (_("All transactions in this account "
1612  "will be moved to the account %s."),
1613  name);
1614  g_free (name);
1615  }
1616  else
1617  {
1618  lines[++i] = g_strdup (_("All transactions in this account "
1619  "will be deleted."));
1620  }
1621  }
1622  if (gnc_account_n_children(account))
1623  {
1624  if (saa)
1625  {
1626  char *name = gnc_account_get_full_name(saa);
1627  lines[++i] = g_strdup_printf (_("Its sub-account will be "
1628  "moved to the account %s."), name);
1629  g_free (name);
1630  }
1631  else
1632  {
1633  lines[++i] = g_strdup (_("Its subaccount will be deleted."));
1634  if (sta)
1635  {
1636  char *name = gnc_account_get_full_name(sta);
1637  lines[++i] = g_strdup_printf (_("All sub-account transactions "
1638  "will be moved to the "
1639  "account %s."), name);
1640  g_free (name);
1641  }
1642  else if (delete_res.has_splits)
1643  {
1644  lines[++i] = g_strdup(_("All sub-account transactions "
1645  "will be deleted."));
1646  }
1647  }
1648  }
1649 
1650  lines[++i] = _("Are you sure you want to do this?");
1651 
1652  message = g_strjoinv(" ", lines);
1653  for (int j = 0; j < i; ++j) // Don't try to free the last one, it's const.
1654  g_free (lines[j]);
1655 
1656  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
1657  GTK_DIALOG_DESTROY_WITH_PARENT,
1658  GTK_MESSAGE_QUESTION,
1659  GTK_BUTTONS_NONE,
1660  "%s", message);
1661  g_free(message);
1662  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
1663  _("_Cancel"), GTK_RESPONSE_CANCEL,
1664  _("_Delete"), GTK_RESPONSE_ACCEPT,
1665  (gchar *)NULL);
1666  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1667  response = gtk_dialog_run(GTK_DIALOG(dialog));
1668  gtk_widget_destroy(dialog);
1669  return response;
1670 }
1671 
1672 void
1673 do_delete_account (Account* account, Account* saa, Account* sta, Account* ta)
1674 {
1675  GList *acct_list, *ptr;
1676  const GncGUID *guid;
1677  gchar guidstr[GUID_ENCODING_LENGTH+1];
1678 
1679  gnc_set_busy_cursor(NULL, TRUE);
1680  gnc_suspend_gui_refresh ();
1681 
1682  /* Move subaccounts and transactions if this was requested */
1683  xaccAccountBeginEdit (account);
1684  if (saa)
1685  {
1686  xaccAccountBeginEdit (saa);
1687  acct_list = gnc_account_get_children(account);
1688  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1689  gnc_account_append_child (saa, GNC_ACCOUNT(ptr->data));
1690  g_list_free(acct_list);
1691  xaccAccountCommitEdit (saa);
1692  }
1693  else if (sta)
1694  {
1695  /* Move the splits of its subaccounts, if any. */
1696  gnc_account_foreach_descendant(account,
1697  (AccountCb)xaccAccountMoveAllSplits,
1698  sta);
1699  }
1700  else
1701  {
1702  gnc_account_foreach_descendant (account,
1703  [](auto acc, [[maybe_unused]] auto data)
1705  nullptr);
1706  }
1707  if (ta)
1708  {
1709  /* Move the splits of the account to be deleted. */
1710  xaccAccountMoveAllSplits (account, ta);
1711  }
1712  else
1713  {
1715  }
1716  xaccAccountCommitEdit (account);
1717 
1718  /* Drop all references from the state file for
1719  * any subaccount the account still has
1720  */
1721  acct_list = gnc_account_get_children(account);
1722  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1723  {
1724  guid = xaccAccountGetGUID (ptr->data);
1725  guid_to_string_buff (guid, guidstr);
1726  gnc_state_drop_sections_for (guidstr);
1727  }
1728  g_list_free(acct_list);
1729 
1730  /* Drop all references from the state file for this account
1731  */
1732  guid = xaccAccountGetGUID (account);
1733  guid_to_string_buff (guid, guidstr);
1734  gnc_state_drop_sections_for (guidstr);
1735 
1736  /*
1737  * Finally, delete the account, any subaccounts it may still
1738  * have, and any splits it or its subaccounts may still have.
1739  */
1740  xaccAccountBeginEdit (account);
1741  xaccAccountDestroy (account);
1742  gnc_resume_gui_refresh ();
1743  gnc_unset_busy_cursor(NULL);
1744 }
1745 
1746 static void
1747 gnc_plugin_page_account_tree_cmd_renumber_accounts (GSimpleAction *simple,
1748  GVariant *paramter,
1749  gpointer user_data)
1750 {
1751  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1752  Account *account;
1753  GtkWidget *window;
1754 
1755  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1757  if (!window || !account)
1758  return;
1759 
1760  gnc_account_renumber_create_dialog(window, account);
1761 }
1762 
1763 static void
1764 gnc_plugin_page_account_tree_cmd_refresh (GSimpleAction *simple,
1765  GVariant *paramter,
1766  gpointer user_data)
1767 {
1768  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1770 
1771  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1772 
1773  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1774 
1775  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
1776  gtk_widget_queue_draw (priv->widget);
1777 }
1778 
1779 /*********************/
1780 
1781 static void
1782 gnc_plugin_page_account_tree_cmd_view_filter_by (GSimpleAction *simple,
1783  GVariant *paramter,
1784  gpointer user_data)
1785 {
1786  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1788 
1789  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1790  ENTER("(action %p, page %p)", simple, page);
1791 
1792  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1793  account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page));
1794  LEAVE(" ");
1795 }
1796 
1797 static void
1798 gnc_plugin_page_account_tree_cmd_reconcile (GSimpleAction *simple,
1799  GVariant *paramter,
1800  gpointer user_data)
1801 {
1802  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1803  GtkWidget *window;
1804  Account *account;
1805  RecnWindow *recnData;
1806 
1808  g_return_if_fail (account != NULL);
1809 
1810  /* To prevent mistakes involving saving an edited transaction after
1811  * finishing a reconciliation (reverting the reconcile state), we could look
1812  * at all open registers and determine if any of them have a transaction
1813  * being edited that involves the account to be reconciled.
1814  *
1815  * However, the reconcile window isn't modal so it's still possible to start
1816  * editing a transaction after opening it. Assume the user knows what
1817  * they're doing if they start a reconciliation from the account tree and
1818  * don't attempt to stop them.
1819  */
1820 
1821  window = GNC_PLUGIN_PAGE (page)->window;
1822  recnData = recnWindow (window, account);
1823  gnc_ui_reconcile_window_raise (recnData);
1824 }
1825 
1826 static void
1827 gnc_plugin_page_account_tree_cmd_autoclear (GSimpleAction *simple,
1828  GVariant *paramter,
1829  gpointer user_data)
1830 {
1831  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1832  GtkWidget *window;
1833  Account *account;
1834  AutoClearWindow *autoClearData;
1835 
1837  g_return_if_fail (account != NULL);
1838 
1839  window = GNC_PLUGIN_PAGE (page)->window;
1840  autoClearData = autoClearWindow (window, account);
1841  gnc_ui_autoclear_window_raise (autoClearData);
1842 }
1843 
1844 static void
1845 gnc_plugin_page_account_tree_cmd_transfer (GSimpleAction *simple,
1846  GVariant *paramter,
1847  gpointer user_data)
1848 {
1849  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1850  GtkWidget *window;
1851  Account *account;
1852 
1854  window = GNC_PLUGIN_PAGE (page)->window;
1855  gnc_xfer_dialog (window, account);
1856 }
1857 
1858 static void
1859 gnc_plugin_page_account_tree_cmd_stock_split (GSimpleAction *simple,
1860  GVariant *paramter,
1861  gpointer user_data)
1862 {
1863  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1864  GtkWidget *window;
1865  Account *account;
1866 
1868  window = GNC_PLUGIN_PAGE (page)->window;
1869  gnc_stock_split_dialog (window, account);
1870 }
1871 
1872 static void
1873 gnc_plugin_page_account_tree_cmd_stock_assistant (GSimpleAction *simple,
1874  GVariant *paramter,
1875  gpointer user_data)
1876 {
1877  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1878  Account *account;
1879  GtkWidget *window;
1880 
1881  ENTER ("(action %p, page %p)", simple, page);
1882 
1884  window = GNC_PLUGIN_PAGE(page)->window;
1885  gnc_stock_transaction_assistant (window, account);
1886 
1887  LEAVE (" ");
1888 }
1889 
1890 static void
1891 gnc_plugin_page_account_tree_cmd_edit_tax_options (GSimpleAction *simple,
1892  GVariant *paramter,
1893  gpointer user_data)
1894 {
1895  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1896  GtkWidget *window;
1897  Account *account;
1898 
1900  window = GNC_PLUGIN_PAGE (page)->window;
1901  gnc_tax_info_dialog (window, account);
1902 }
1903 
1904 static void
1905 gnc_plugin_page_account_tree_cmd_lots (GSimpleAction *simple,
1906  GVariant *paramter,
1907  gpointer user_data)
1908 {
1909  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1911  GtkWidget *window = GNC_PLUGIN_PAGE (page)->window;
1912  gnc_lot_viewer_dialog (GTK_WINDOW(window), account);
1913 }
1914 
1915 static gboolean
1916 scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
1917 {
1918  if (event->length == 0) return FALSE;
1919 
1920  switch (event->keyval)
1921  {
1922  case GDK_KEY_Escape:
1923  {
1924  gboolean abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), FALSE,
1925  "%s", _(check_repair_abort_YN));
1926 
1927  if (abort_scrub)
1928  gnc_set_abort_scrub (TRUE);
1929 
1930  return TRUE;
1931  }
1932  default:
1933  break;
1934  }
1935  return FALSE;
1936 }
1937 
1938 static void
1939 gnc_plugin_page_account_tree_cmd_scrub (GSimpleAction *simple,
1940  GVariant *paramter,
1941  gpointer user_data)
1942 {
1943  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1945  GncWindow *window;
1946  gulong scrub_kp_handler_ID;
1947 
1948  g_return_if_fail (account != NULL);
1949 
1950  prepare_scrubbing ();
1951 
1952  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
1953  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
1954  G_CALLBACK(scrub_kp_handler), NULL);
1955  gnc_window_set_progressbar_window (window);
1956 
1957  xaccAccountScrubOrphans (account, gnc_window_show_progress);
1958  xaccAccountScrubImbalance (account, gnc_window_show_progress);
1959 
1960  // XXX: Lots/capital gains scrubbing is disabled
1961  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1962  xaccAccountScrubLots(account);
1963 
1964  gncScrubBusinessAccount(account, gnc_window_show_progress);
1965 
1966  finish_scrubbing (window, scrub_kp_handler_ID);
1967 }
1968 
1969 static void
1970 gnc_plugin_page_account_tree_cmd_scrub_sub (GSimpleAction *simple,
1971  GVariant *paramter,
1972  gpointer user_data)
1973 {
1974  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1976  GncWindow *window;
1977  gulong scrub_kp_handler_ID;
1978 
1979  g_return_if_fail (account != NULL);
1980 
1981  prepare_scrubbing ();
1982 
1983  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
1984  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
1985  G_CALLBACK(scrub_kp_handler), NULL);
1986  gnc_window_set_progressbar_window (window);
1987 
1988  xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
1989  xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
1990 
1991  // XXX: Lots/capital gains scrubbing is disabled
1992  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1993  xaccAccountTreeScrubLots(account);
1994 
1995  gncScrubBusinessAccountTree(account, gnc_window_show_progress);
1996 
1997  finish_scrubbing (window, scrub_kp_handler_ID);
1998 }
1999 
2000 static void
2001 gnc_plugin_page_account_tree_cmd_scrub_all (GSimpleAction *simple,
2002  GVariant *paramter,
2003  gpointer user_data)
2004 {
2005  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
2006  Account *root = gnc_get_current_root_account ();
2007  GncWindow *window;
2008  gulong scrub_kp_handler_ID;
2009 
2010  prepare_scrubbing ();
2011 
2012  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2013  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2014  G_CALLBACK(scrub_kp_handler), NULL);
2015  gnc_window_set_progressbar_window (window);
2016 
2017  xaccAccountTreeScrubOrphans (root, gnc_window_show_progress);
2018  xaccAccountTreeScrubImbalance (root, gnc_window_show_progress);
2019  // XXX: Lots/capital gains scrubbing is disabled
2020  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2021  xaccAccountTreeScrubLots(root);
2022 
2023  gncScrubBusinessAccountTree(root, gnc_window_show_progress);
2024 
2025  finish_scrubbing (window, scrub_kp_handler_ID);
2026 }
2027 
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2906
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
Account * gnc_plugin_page_account_tree_get_current_account(GncPluginPageAccountTree *page)
Given a pointer to an account tree plugin page, return the selected account (if any).
Functions to load, save and get gui state.
High-Level API for imposing Lot constraints.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
void gnc_main_window_update_menu_and_toolbar(GncMainWindow *window, GncPluginPage *page, const gchar **ui_updates)
Update the main window menu with the placeholders listed in ui_updates and load the page specific too...
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship, and will then add the account as a child of the new parent.
Definition: Account.cpp:2807
The instance data structure for a content plugin.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
gboolean gnc_main_window_button_press_cb(GtkWidget *whatever, GdkEventButton *event, GncPluginPage *page)
Callback function invoked when the user clicks in the content of any Gnucash window.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
void gnc_plugin_page_account_tree_open(Account *account, GtkWindow *win)
Given a pointer to an account, the account tree will open and the account will be selected (if any)...
This file contains the functions to present a gui to the user for creating a new account or editing a...
GncPluginPage * gnc_plugin_page_account_tree_new(void)
Create a new "account tree" plugin page.
void gnc_tree_view_account_set_editing_finished_cb(GncTreeViewAccount *view, GFunc editing_finished_cb, gpointer editing_cb_data)
Setup the callback for when the user finishes editing the account tree so actions can be enabled like...
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4506
gboolean gnc_get_ongoing_scrub(void)
The gnc_get_ongoing_scrub () method returns TRUE if a scrub operation is ongoing. ...
Definition: Scrub.cpp:87
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3237
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash...
STRUCTS.
gint gnc_state_drop_sections_for(const gchar *partial_name)
Drop all sections from the state file whose name contains partial_name.
Definition: gnc-state.c:260
void gnc_main_window_init_short_names(GncMainWindow *window, GncToolBarShortNames *toolbar_labels)
Update the labels of the toolbar items with short names.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Functions that are supported by all types of windows.
GSimpleActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GSimpleActionGroup object associated with this page.
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3214
GtkWidget * window
The window that contains the display widget for this plugin.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition: guid.cpp:173
void xaccAccountScrubLots(Account *acc)
The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot...
Definition: Scrub3.cpp:159
void xaccAccountMoveAllSplits(Account *accfrom, Account *accto)
The xaccAccountMoveAllSplits() routine reassigns each of the splits in accfrom to accto...
Definition: Account.cpp:2202
void gnc_tree_view_account_set_editing_started_cb(GncTreeViewAccount *view, GFunc editing_started_cb, gpointer editing_cb_data)
Setup the callback for when the user starts editing the account tree so actions can be disabled like ...
GtkTreeViewColumn * gnc_tree_view_find_column_by_name(GncTreeView *view, const gchar *wanted)
Find a tree column given the "pref name" used with saved state.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Cleanup functions for business objects.
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition: gnc-state.c:248
This file contains the functions to present a dialog box with a list of object references and an expl...
void gnc_ui_edit_account_window(GtkWindow *parent, Account *account)
Display a window for editing the attributes of an existing account.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1592
#define xaccAccountGetGUID(X)
Definition: Account.h:252
void gnc_set_abort_scrub(gboolean abort)
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.
Definition: Scrub.cpp:75
convert single-entry accounts to clean double-entry
GAction * gnc_main_window_find_action_in_group(GncMainWindow *window, const gchar *group_name, const gchar *action_name)
Find the GAction in a specific action group for window.
void gnc_tree_view_account_set_filter(GncTreeViewAccount *view, gnc_tree_view_account_filter_func func, gpointer data, GSourceFunc destroy)
This function attaches a filter function to the given account tree.
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3275
Functions providing a register page for the GnuCash UI.
The class data structure for a content plugin.
void gnc_tree_view_account_refilter(GncTreeViewAccount *view)
This function forces the account tree filter to be evaluated.
Gobject helper routines.
GtkTreeView implementation for gnucash account tree.
Account public routines (C++ api)
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
void xaccAccountTreeScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its childr...
Definition: Scrub.cpp:173
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition: guid.h:84
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
void gnc_tree_view_configure_columns(GncTreeView *view)
Make all the correct columns visible, respecting their default visibility setting, their "always" visibility setting, and the last saved state if available.
gboolean gnc_plugin_page_account_tree_filter_accounts(Account *account, gpointer user_data)
This function tells the account tree view whether or not to filter out a particular account...
const gchar * plugin_name
The textual name of this plugin.
void gncScrubBusinessAccount(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccount() function will call all scrub functions relevant for a given account on ...
void gnc_tree_view_account_clear_model_cache(GncTreeViewAccount *view)
This function clears the tree model account cache so the values will be updated/refreshed.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
Account * gnc_tree_view_account_get_account_from_path(GncTreeViewAccount *view, GtkTreePath *s_path)
This function returns the account associated with the specified path.
void xaccAccountScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
The xaccAccountScrubOrphans() method performs this scrub only for the indicated account, and not for any of its children.
Definition: Scrub.cpp:167
void gnc_plugin_set_actions_enabled(GActionMap *action_map, const gchar **action_names, gboolean enable)
This function sets the sensitivity of a GAction in a specific group.
Definition: gnc-plugin.c:250
Gnome specific utility functions.
gint gnc_account_n_children(const Account *account)
Return the number of children of the specified account.
Definition: Account.cpp:2947
gboolean(* finish_pending)(GncPluginPage *plugin_page)
This function vector is called to finish any outstanding activities.
All type declarations for the whole Gnucash engine.
void gnc_ui_new_account_window(GtkWindow *parent, QofBook *book, Account *parent_acct)
Display a window for creating a new account.
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
GtkTreeModel implementation to display account types in a GtkTreeView.
GList * qof_instance_get_referring_object_list(const QofInstance *inst)
Returns a list of objects which refer to a specific object.
const gchar * gnc_tree_view_get_state_section(GncTreeView *view)
Get the name of the state section this tree view is associated with.
GLib helper routines.
Generic api to store and retrieve preferences.
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3014
Functions providing a chart of account page.
void gnc_tree_view_account_set_selected_account(GncTreeViewAccount *view, Account *account)
This function selects an account in the account tree view.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
A structure for defining alternate action names for use in the toolbar.
void xaccAccountDestroyAllTransactions(Account *acc)
Destroy all of the transactions that parent splits in an account.
Definition: Account.cpp:1602
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2931
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1477
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4074
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
Provide the menus to create a chart of account page.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
This function returns the account associated with the selected item in the account tree view...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
void gncScrubBusinessAccountTree(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccountTreeLots() function will call gncScrubBusinessAccount() on the given accou...
gboolean gnc_main_window_all_finish_pending(void)
Tell all pages in all windows to finish any outstanding activities.
gint gnc_list_length_cmp(const GList *list, size_t len)
Scans the GList elements the minimum number of iterations required to test it against a specified siz...
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1518
GtkWidget * summarybar
The summary bar widget (if any) that is associated with this plugin.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143