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  priv->tree_view = NULL;
796  LEAVE("widget destroyed");
797 }
798 
799 static void
800 update_inactive_actions (GncPluginPage *plugin_page)
801 {
803  GSimpleActionGroup *simple_action_group = NULL;
804  Account *account = NULL;
805  gboolean allow_write = !qof_book_is_readonly (gnc_get_current_book());
806  gboolean has_account = FALSE;
807  gboolean subaccounts = FALSE;
808 
809  g_return_if_fail (plugin_page && GNC_IS_PLUGIN_PAGE(plugin_page));
810 
811  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE (plugin_page);
812 
813  if (gtk_tree_view_get_selection (priv->tree_view))
814  {
815  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
816  has_account = (account != NULL);
817  subaccounts = (account && gnc_account_n_children (account) != 0);
818  /* Check here for placeholder accounts, etc. */
819  }
820 
821  /* Get the action group */
822  simple_action_group = gnc_plugin_page_get_action_group (plugin_page);
823  g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple_action_group));
824 
825  /* Set the action's sensitivity */
826  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), readonly_inactive_actions,
827  allow_write);
828  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account_rw,
829  allow_write && has_account);
830  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account_always,
831  has_account);
832  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_subaccounts_rw,
833  allow_write && subaccounts);
834  gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_priced_account,
835  account && xaccAccountIsPriced (account));
836 
837  g_signal_emit (plugin_page, plugin_page_signals[ACCOUNT_SELECTED], 0, account);
838 }
839 
844 static void
845 gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data)
846 {
847  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object);
848  g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page));
849  update_inactive_actions(plugin_page);
850 }
851 
861 static void
862 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
863  GKeyFile *key_file,
864  const gchar *group_name)
865 {
866  GncPluginPageAccountTree *account_page;
868 
869  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
870  g_return_if_fail (key_file != NULL);
871  g_return_if_fail (group_name != NULL);
872 
873  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
874  group_name);
875 
876  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
877  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
878 
879  gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
880  &priv->fd, key_file, group_name);
881  LEAVE(" ");
882 }
883 
884 
885 
895 static GncPluginPage *
896 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
897  GKeyFile *key_file,
898  const gchar *group_name)
899 {
900  GncPluginPageAccountTree *account_page;
902  GncPluginPage *page;
903 
904  g_return_val_if_fail(key_file, NULL);
905  g_return_val_if_fail(group_name, NULL);
906  ENTER("key_file %p, group_name %s", key_file, group_name);
907 
908  /* Create the new page. */
910  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
911  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
912 
913  /* Install it now so we can then manipulate the created widget */
914  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
915 
916  gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
917  &priv->fd, key_file, group_name);
918  LEAVE(" ");
919  return page;
920 }
921 
922 
923 /* Callbacks */
924 
925 static void
926 gnc_plugin_page_account_tree_summarybar_position_changed (gpointer prefs,
927  gchar* pref,
928  gpointer user_data)
929 {
930  GncPluginPage *plugin_page;
933  GtkPositionType position = GTK_POS_BOTTOM;
934 
935  g_return_if_fail(user_data != NULL);
936 
937  plugin_page = GNC_PLUGIN_PAGE(user_data);
938  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data);
939  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
940 
941  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SUMMARYBAR_POSITION_TOP))
942  position = GTK_POS_TOP;
943 
944  gtk_box_reorder_child(GTK_BOX(priv->widget),
945  plugin_page->summarybar,
946  (position == GTK_POS_TOP ? 0 : -1) );
947 }
948 
956 static gboolean
957 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
958  GdkEventButton *event,
959  GncPluginPage *page)
960 {
961 
962  g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
963 
964  ENTER("widget %p, event %p, page %p", widget, event, page);
965  gnc_main_window_button_press_cb(widget, event, page);
966  LEAVE(" ");
967 
968  /* Always return FALSE. This will let the tree view callback run as
969  * well which will select the item under the cursor. By the time
970  * the user sees the menu both callbacks will have run and the menu
971  * actions will operate on the just-selected account. */
972  return FALSE;
973 }
974 
975 static void
976 gppat_open_account_common (GncPluginPageAccountTree *page,
977  Account *account,
978  gboolean include_subs)
979 {
980  GtkWidget *window;
981  GncPluginPage *new_page;
982 
983  if (account == NULL)
984  return;
985 
986  window = GNC_PLUGIN_PAGE (page)->window;
987  new_page = gnc_plugin_page_register_new (account, include_subs);
988  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
989 }
990 
991 static void
992 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
993  GtkTreePath *path,
994  GtkTreeViewColumn *col,
996 {
997  GtkTreeModel *model;
998  GtkTreeIter iter;
999 
1000  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1001  g_return_if_fail (treeview);
1002 
1003  model = gtk_tree_view_get_model(treeview);
1004  if (gtk_tree_model_get_iter(model, &iter, path))
1005  {
1006  Account *account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path);
1007  if (xaccAccountGetPlaceholder (account))
1008  {
1009  /* This is a placeholder account. Only only show/hide
1010  * subaccount list if there is one.
1011  */
1012  if (gtk_tree_model_iter_has_child(model, &iter))
1013  {
1014  /* There are children,
1015  * just expand or collapse the row. */
1016  if (gtk_tree_view_row_expanded(treeview, path))
1017  gtk_tree_view_collapse_row(treeview, path);
1018  else
1019  gtk_tree_view_expand_row(treeview, path, FALSE);
1020  }
1021  }
1022  else
1023  {
1024  /* No placeholder account, so open its register */
1025  gppat_open_account_common (page, account, FALSE);
1026  }
1027  }
1028 }
1029 
1030 static void
1031 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
1033 {
1034  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
1035  update_inactive_actions (plugin_page);
1036 }
1037 
1038 static void
1039 accounting_period_changed_cb (gpointer prefs, gchar *pref, gpointer user_data)
1040 {
1041  gnc_plugin_page_account_tree_cmd_refresh (NULL, NULL, user_data);
1042 }
1043 
1044 /* Command callbacks */
1045 static void
1046 gnc_plugin_page_account_tree_cmd_new_account (GSimpleAction *simple,
1047  GVariant *paramter,
1048  gpointer user_data)
1049 {
1050  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1052  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1053  gnc_ui_new_account_window (parent, gnc_get_current_book(),
1054  account);
1055 }
1056 
1057 static void
1058 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GSimpleAction *simple,
1059  GVariant *paramter,
1060  gpointer user_data)
1061 {
1062  gnc_ui_hierarchy_assistant(FALSE);
1063 }
1064 
1065 static void
1066 gnc_plugin_page_account_tree_cmd_open_account (GSimpleAction *simple,
1067  GVariant *paramter,
1068  gpointer user_data)
1069 {
1070  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1071  Account *account;
1072 
1073  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1075  gppat_open_account_common (page, account, FALSE);
1076 }
1077 
1078 static void
1079 gnc_plugin_page_account_tree_cmd_open_subaccounts (GSimpleAction *simple,
1080  GVariant *paramter,
1081  gpointer user_data)
1082 {
1083  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1084  Account *account;
1085 
1086  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1088  gppat_open_account_common (page, account, TRUE);
1089 }
1090 
1091 static void
1092 gnc_plugin_page_account_tree_cmd_edit_account (GSimpleAction *simple,
1093  GVariant *paramter,
1094  gpointer user_data)
1095 {
1096  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1097  Account *account;
1098  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1099  ENTER("action %p, page %p", simple, page);
1100 
1102  g_return_if_fail (account != NULL);
1103 
1104  gnc_ui_edit_account_window (parent, account);
1105  LEAVE(" ");
1106 }
1107 
1108 static void
1109 gnc_plugin_page_account_tree_cmd_find_account (GSimpleAction *simple,
1110  GVariant *paramter,
1111  gpointer user_data)
1112 {
1113  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1114  GtkWidget *window;
1115 
1116  ENTER("action %p, page %p", simple, page);
1117 
1118  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1119 
1120  gnc_find_account_dialog (window, NULL);
1121  LEAVE(" ");
1122 }
1123 
1124 static void
1125 gnc_plugin_page_account_tree_cmd_find_account_popup (GSimpleAction *simple,
1126  GVariant *paramter,
1127  gpointer user_data)
1128 {
1129  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1130  Account *account = NULL;
1131  GtkWidget *window;
1132 
1133  ENTER("action %p, page %p", simple, page);
1134 
1136 
1137  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1138 
1139  gnc_find_account_dialog (window, account);
1140  LEAVE(" ");
1141 }
1142 
1143 static void
1144 gnc_plugin_page_account_tree_cmd_cascade_account_properties (GSimpleAction *simple,
1145  GVariant *paramter,
1146  gpointer user_data)
1147 {
1148  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1149  Account *account = NULL;
1150  GtkWidget *window;
1151 
1152  ENTER("action %p, page %p", simple, page);
1153 
1155 
1156  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page));
1157 
1158  if (account != NULL)
1159  gnc_account_cascade_properties_dialog (window, account);
1160 
1161  LEAVE(" ");
1162 }
1163 
1164 static gpointer
1165 delete_account_helper (Account * account, gpointer data)
1166 {
1167  auto helper_res = static_cast<delete_helper_t*>(data);
1168  auto& splits{xaccAccountGetSplits (account)};
1169  auto split_ro = [](auto s) -> bool { return xaccTransGetReadOnly (xaccSplitGetParent (s)); };
1170 
1171  helper_res->has_splits = !splits.empty();
1172  helper_res->has_ro_splits = std::any_of (splits.begin(), splits.end(), split_ro);
1173 
1174  return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits);
1175 }
1176 
1177 /***
1178  *** The OK button of a Delete Account dialog is insensitive if
1179  *** and only if a sensitive account selector contains no accounts.
1180  ***/
1181 static void
1182 set_ok_sensitivity(GtkWidget *dialog)
1183 {
1184  gboolean sensitive;
1185 
1186  auto sa_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS));
1187  auto trans_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS));
1188 
1189  sensitive = ((!sa_mas ||
1190  !gtk_widget_is_sensitive (sa_mas) ||
1191  gnc_account_sel_get_visible_account_num (GNC_ACCOUNT_SEL (sa_mas))) &&
1192  (!trans_mas ||
1193  !gtk_widget_is_sensitive (trans_mas) ||
1194  gnc_account_sel_get_visible_account_num (GNC_ACCOUNT_SEL (trans_mas))));
1195 
1196  auto button = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON));
1197  gtk_widget_set_sensitive(button, sensitive);
1198 }
1199 
1200 static GList *
1201 gppat_get_exclude_list (Account *acc, gboolean exclude_subaccounts)
1202 {
1203  GList *acct_list = NULL;
1204 
1205  if (exclude_subaccounts)
1206  acct_list = gnc_account_get_descendants (acc);
1207 
1208  acct_list = g_list_prepend (acct_list, acc);
1209 
1210  return acct_list;
1211 }
1212 
1213 static void
1214 gppat_populate_gas_list(GtkWidget *dialog,
1215  GNCAccountSel *gas,
1216  gboolean exclude_subaccounts)
1217 {
1218  Account *account;
1219  GList *filter;
1220  GList *exclude;
1221 
1222  g_return_if_fail(GTK_IS_DIALOG(dialog));
1223  if (gas == NULL)
1224  return;
1225  account = GNC_ACCOUNT(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT));
1226  filter = static_cast<GList*>(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER));
1227 
1228  /* Setting the account type filter triggers GNCAccountSel population. */
1229  gnc_account_sel_set_acct_filters (gas, filter, NULL);
1230 
1231  /* Accounts to be deleted must be excluded from GAS. */
1232  exclude = gppat_get_exclude_list (account, exclude_subaccounts);
1233  gnc_account_sel_set_acct_exclude_filter (gas, exclude);
1234  g_list_free (exclude);
1235 
1236  gnc_account_sel_set_account (gas, NULL, TRUE);
1237 
1238  /* The sensitivity of the OK button needs to be reevaluated. */
1239  set_ok_sensitivity(dialog);
1240 }
1241 
1242 void
1243 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb,
1244  GtkWidget *dialog)
1245 {
1246  g_return_if_fail(GTK_IS_DIALOG(dialog));
1247 
1248  /* Cannot move transactions to subaccounts if they are to be deleted. */
1249  auto trans_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS));
1250  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb));
1251 }
1252 
1253 /* Note that the emitting object (the toggle button) and the signal data
1254  * are swapped in below callback function. This is a gtkbuilder feature:
1255  * it swaps if you explicitly set an object for a signal handler in the
1256  * gtkbuilder xml file.
1257  */
1258 void
1259 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b)
1260 {
1261  GtkWidget *dialog = gtk_widget_get_toplevel(widget);
1262  auto subaccount_trans = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS));
1263  auto sa_mas = GTK_WIDGET(g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS));
1264  auto have_splits = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS) != nullptr;
1265 
1266  gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b));
1267 
1268  // If we have subaccount splits & delete subaccounts, enable subaccount_trans
1269  if ((have_splits) && !gtk_widget_is_sensitive(sa_mas))
1270  gtk_widget_set_sensitive(subaccount_trans, TRUE);
1271  else
1272  gtk_widget_set_sensitive(subaccount_trans, FALSE);
1273 
1274  set_ok_sensitivity(dialog);
1275 }
1276 
1277 static GtkWidget *
1278 gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
1279  const gchar *hbox, const gchar *sel_name)
1280 {
1281  GtkWidget *selector = gnc_account_sel_new();
1282  GtkWidget *box = GTK_WIDGET(gtk_builder_get_object (builder, hbox));
1283 
1284  gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
1285 
1286  // placeholder accounts are OK for this GAS
1287  if (g_strcmp0 (sel_name, DELETE_DIALOG_SA_MAS) == 0)
1288  g_object_set (selector, "hide-placeholder", FALSE, NULL);
1289 
1290  g_object_set_data(G_OBJECT(dialog), sel_name, selector);
1291 
1292  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(selector), TRUE);
1293  gtk_widget_show_all(box);
1294 
1295  return selector;
1296 }
1297 
1298 static int
1299 commodity_mismatch_dialog (const Account* account, GtkWindow* parent)
1300 {
1301  int response;
1302  char *account_name = gnc_account_get_full_name (account);
1303  char* message = g_strdup_printf (
1304  _("Account %s does not have the same currency as the one you're "
1305  "moving transactions from.\nAre you sure you want to do this?"),
1306  account_name);
1307  GtkWidget* error_dialog =
1308  gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
1309  GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
1310  "%s", message);
1311  gtk_dialog_add_buttons (GTK_DIALOG(error_dialog),
1312  _("_Pick another account"), GTK_RESPONSE_CANCEL,
1313  _("_Do it anyway"), GTK_RESPONSE_ACCEPT,
1314  (gchar *)NULL);
1315  response = gtk_dialog_run (GTK_DIALOG (error_dialog));
1316  gtk_widget_destroy (error_dialog);
1317  g_free (message);
1318  g_free (account_name);
1319  return response;
1320 }
1321 
1322 typedef struct
1323 {
1324  Account *new_account;
1325  Account *old_account;
1326  GNCAccountSel *selector;
1327  gboolean match;
1328  gboolean for_account;
1329 } Adopter;
1330 
1331 static void
1332 adopter_set_account_and_match (Adopter* adopter)
1333 {
1334  if (!(adopter->selector &&
1335  gtk_widget_is_sensitive (GTK_WIDGET (adopter->selector))))
1336  return;
1337  adopter->new_account = gnc_account_sel_get_account(adopter->selector);
1338 /* We care about the commodity only if we're moving transactions. */
1339  if (!adopter->for_account && adopter->old_account && adopter->new_account)
1340  adopter->match =
1341  xaccAccountGetCommodity (adopter->new_account) ==
1342  xaccAccountGetCommodity (adopter->old_account);
1343 }
1344 
1345 static void
1346 adopter_init (Adopter* adopter, GtkWidget *selector, Account* account,
1347  gboolean for_account)
1348 {
1349  adopter->selector = GNC_ACCOUNT_SEL (selector);
1350  adopter->new_account = NULL;
1351  adopter->old_account = account;
1352  adopter->match = TRUE;
1353  adopter->for_account = for_account;
1354 }
1355 
1356 static gboolean
1357 adopter_match (Adopter* adopter, GtkWindow *parent)
1358 {
1359  int result;
1360  if (adopter->match || adopter->for_account)
1361  return TRUE;
1362  result = commodity_mismatch_dialog (adopter->new_account, parent);
1363  return (result == GTK_RESPONSE_ACCEPT);
1364 }
1365 
1366 typedef struct
1367 {
1368  Adopter trans;
1369  Adopter subacct;
1370  Adopter subtrans;
1371  delete_helper_t delete_res;
1372 } Adopters;
1373 
1374 static Account*
1375 account_subaccount (Account* account)
1376 {
1377  Account* subaccount = NULL;
1378  GList *subs = gnc_account_get_children (account);
1379  if (!gnc_list_length_cmp (subs, 1))
1380  subaccount = GNC_ACCOUNT(subs->data);
1381  g_list_free (subs);
1382  return subaccount;
1383 }
1384 
1385 static GtkWidget*
1386 account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
1387 {
1388  GtkWidget *dialog = NULL;
1389  GtkWidget *widget = NULL;
1390  gchar *title = NULL;
1391  GtkBuilder *builder = gtk_builder_new();
1392  gchar *acct_name = gnc_account_get_full_name(account);
1393  GList* filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
1394 
1395  if (!acct_name)
1396  acct_name = g_strdup (_("(no name)"));
1397 
1398  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_delete_dialog");
1399 
1400  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_delete_dialog"));
1401  gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
1402 
1403  /* FIXME: Same account type used for subaccount. */
1404  g_object_set_data_full (G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter,
1405  (GDestroyNotify) g_list_free);
1406  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account);
1407  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header"));
1408  title = g_strdup_printf(_("Deleting account %s"), acct_name);
1409  gtk_label_set_text(GTK_LABEL(widget), title);
1410  g_free(title);
1411  g_free(acct_name);
1412 
1413  widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON));
1414  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget);
1415 
1416  // Add the account selectors and enable sections as appropriate
1417  // setup transactions selector
1418  adopter_init (&adopt->trans,
1419  gppat_setup_account_selector (builder, dialog,
1420  "trans_mas_hbox",
1421  DELETE_DIALOG_TRANS_MAS),
1422  account, FALSE);
1423 
1424  // Does the selected account have splits
1425  if (!xaccAccountGetSplits(account).empty())
1426  {
1427  delete_helper_t delete_res2 = { FALSE, FALSE };
1428 
1429  delete_account_helper(account, &delete_res2);
1430  if (delete_res2.has_ro_splits)
1431  {
1432  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw")));
1433  widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb"));
1434  gtk_widget_set_sensitive(widget, FALSE);
1435  }
1436  else
1437  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1438  }
1439  else
1440  {
1441  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "transactions")), FALSE);
1442  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1443  }
1444 
1445  // setup subaccount account selector
1446  adopter_init (&adopt->subacct,
1447  gppat_setup_account_selector (builder, dialog,
1448  "sa_mas_hbox",
1449  DELETE_DIALOG_SA_MAS),
1450  account, TRUE);
1451 
1452  // setup subaccount transaction selector
1453  adopter_init (&adopt->subtrans,
1454  gppat_setup_account_selector (builder, dialog,
1455  "sa_trans_mas_hbox",
1456  DELETE_DIALOG_SA_TRANS_MAS),
1457  account_subaccount (account), FALSE);
1458  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS,
1459  GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1460 
1461  if (gnc_account_n_children(account) > 0)
1462  {
1463  // Check for RO txns in descendants
1464  gnc_account_foreach_descendant_until(account, delete_account_helper,
1465  &adopt->delete_res);
1466  if (adopt->delete_res.has_splits)
1467  {
1468  if (adopt->delete_res.has_ro_splits)
1469  {
1470  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw")));
1471  widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb"));
1472  gtk_widget_set_sensitive(widget, FALSE);
1473  }
1474  else
1475  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1476 
1477  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(1));
1478  }
1479  else
1480  {
1481  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(0));
1482  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1483  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1484  }
1485  }
1486  else
1487  {
1488  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts")), FALSE);
1489  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1490  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1491  }
1492 
1493  /* default to cancel */
1494  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1495 
1496  gtk_builder_connect_signals(builder, dialog);
1497  g_object_unref(G_OBJECT(builder));
1498 
1499  return dialog;
1500 }
1501 
1502 static void
1503 gnc_plugin_page_account_tree_cmd_delete_account (GSimpleAction *simple,
1504  GVariant *paramter,
1505  gpointer user_data)
1506 {
1507  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1509  gchar *acct_name;
1510  GtkWidget *window;
1511  Adopters adopt;
1512  GList* list;
1513  gint response;
1514  GtkWidget *dialog = NULL;
1515 
1516  if (account == NULL)
1517  return;
1518 
1520  return;
1521 
1522  memset (&adopt, 0, sizeof (adopt));
1523  /* If the account has objects referring to it, show the list - the account can't be deleted until these
1524  references are dealt with. */
1525  list = qof_instance_get_referring_object_list(QOF_INSTANCE(account));
1526  if (list != NULL)
1527  {
1528 #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")
1529 
1530  gnc_ui_object_references_show(EXPLANATION, list);
1531  g_list_free(list);
1532  return;
1533  }
1534  g_list_free (list);
1535 
1536  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1537  acct_name = gnc_account_get_full_name(account);
1538  if (!acct_name)
1539  acct_name = g_strdup (_("(no name)"));
1540 
1541  if (gnc_account_n_children(account) > 1) {
1542  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);
1543  gnc_error_dialog(GTK_WINDOW(window),"%s", message);
1544  g_free (message);
1545  g_free(acct_name);
1546  return;
1547  }
1548  g_free (acct_name);
1549 
1550  // If no transaction or children just delete it.
1551  if (xaccAccountGetSplits (account).empty() && gnc_account_n_children (account) == 0)
1552  {
1553  do_delete_account (account, NULL, NULL, NULL);
1554  return;
1555  }
1556 
1557  dialog = account_delete_dialog (account, GTK_WINDOW (window), &adopt);
1558 
1559  while (TRUE)
1560  {
1561  response = gtk_dialog_run(GTK_DIALOG(dialog));
1562 
1563  if (response != GTK_RESPONSE_ACCEPT)
1564  {
1565  gtk_widget_destroy(dialog);
1566  return;
1567  }
1568  adopter_set_account_and_match (&adopt.trans);
1569  adopter_set_account_and_match (&adopt.subacct);
1570  adopter_set_account_and_match (&adopt.subtrans);
1571 
1572  if (adopter_match (&adopt.trans, GTK_WINDOW (window)) &&
1573  adopter_match (&adopt.subacct, GTK_WINDOW (window)) &&
1574  adopter_match (&adopt.subtrans, GTK_WINDOW (window)))
1575  break;
1576  }
1577  gtk_widget_destroy(dialog);
1578  if (confirm_delete_account (simple, page, adopt.trans.new_account,
1579  adopt.subtrans.new_account,
1580  adopt.subacct.new_account,
1581  adopt.delete_res) == GTK_RESPONSE_ACCEPT)
1582  {
1583  do_delete_account (account, adopt.subacct.new_account,
1584  adopt.subtrans.new_account, adopt.trans.new_account);
1585  }
1586 }
1587 
1588 static int
1589 confirm_delete_account (GSimpleAction *simple, GncPluginPageAccountTree *page,
1590  Account* ta, Account* sta, Account* saa,
1591  delete_helper_t delete_res)
1592 {
1594  GtkWidget* window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1595  gint response;
1596 
1597  char *lines[6] = {0};
1598  char *message;
1599  int i = 0;
1600  GtkWidget *dialog;
1601  gchar* acct_name = gnc_account_get_full_name(account);
1602 
1603  lines[i] = g_strdup_printf (_("The account %s will be deleted."),
1604  acct_name);
1605  g_free(acct_name);
1606 
1607  if (!xaccAccountGetSplits (account).empty())
1608  {
1609  if (ta)
1610  {
1611  char *name = gnc_account_get_full_name(ta);
1612  lines[++i] = g_strdup_printf (_("All transactions in this account "
1613  "will be moved to the account %s."),
1614  name);
1615  g_free (name);
1616  }
1617  else
1618  {
1619  lines[++i] = g_strdup (_("All transactions in this account "
1620  "will be deleted."));
1621  }
1622  }
1623  if (gnc_account_n_children(account))
1624  {
1625  if (saa)
1626  {
1627  char *name = gnc_account_get_full_name(saa);
1628  lines[++i] = g_strdup_printf (_("Its sub-account will be "
1629  "moved to the account %s."), name);
1630  g_free (name);
1631  }
1632  else
1633  {
1634  lines[++i] = g_strdup (_("Its subaccount will be deleted."));
1635  if (sta)
1636  {
1637  char *name = gnc_account_get_full_name(sta);
1638  lines[++i] = g_strdup_printf (_("All sub-account transactions "
1639  "will be moved to the "
1640  "account %s."), name);
1641  g_free (name);
1642  }
1643  else if (delete_res.has_splits)
1644  {
1645  lines[++i] = g_strdup(_("All sub-account transactions "
1646  "will be deleted."));
1647  }
1648  }
1649  }
1650 
1651  lines[++i] = _("Are you sure you want to do this?");
1652 
1653  message = g_strjoinv(" ", lines);
1654  for (int j = 0; j < i; ++j) // Don't try to free the last one, it's const.
1655  g_free (lines[j]);
1656 
1657  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
1658  GTK_DIALOG_DESTROY_WITH_PARENT,
1659  GTK_MESSAGE_QUESTION,
1660  GTK_BUTTONS_NONE,
1661  "%s", message);
1662  g_free(message);
1663  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
1664  _("_Cancel"), GTK_RESPONSE_CANCEL,
1665  _("_Delete"), GTK_RESPONSE_ACCEPT,
1666  (gchar *)NULL);
1667  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1668  response = gtk_dialog_run(GTK_DIALOG(dialog));
1669  gtk_widget_destroy(dialog);
1670  return response;
1671 }
1672 
1673 void
1674 do_delete_account (Account* account, Account* saa, Account* sta, Account* ta)
1675 {
1676  GList *acct_list, *ptr;
1677  const GncGUID *guid;
1678  gchar guidstr[GUID_ENCODING_LENGTH+1];
1679 
1680  gnc_set_busy_cursor(NULL, TRUE);
1681  gnc_suspend_gui_refresh ();
1682 
1683  /* Move subaccounts and transactions if this was requested */
1684  xaccAccountBeginEdit (account);
1685  if (saa)
1686  {
1687  xaccAccountBeginEdit (saa);
1688  acct_list = gnc_account_get_children(account);
1689  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1690  gnc_account_append_child (saa, GNC_ACCOUNT(ptr->data));
1691  g_list_free(acct_list);
1692  xaccAccountCommitEdit (saa);
1693  }
1694  else if (sta)
1695  {
1696  /* Move the splits of its subaccounts, if any. */
1697  gnc_account_foreach_descendant(account,
1698  (AccountCb)xaccAccountMoveAllSplits,
1699  sta);
1700  }
1701  else
1702  {
1703  gnc_account_foreach_descendant (account,
1704  [](auto acc, [[maybe_unused]] auto data)
1706  nullptr);
1707  }
1708  if (ta)
1709  {
1710  /* Move the splits of the account to be deleted. */
1711  xaccAccountMoveAllSplits (account, ta);
1712  }
1713  else
1714  {
1716  }
1717  xaccAccountCommitEdit (account);
1718 
1719  /* Drop all references from the state file for
1720  * any subaccount the account still has
1721  */
1722  acct_list = gnc_account_get_children(account);
1723  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1724  {
1725  guid = xaccAccountGetGUID (ptr->data);
1726  guid_to_string_buff (guid, guidstr);
1727  gnc_state_drop_sections_for (guidstr);
1728  }
1729  g_list_free(acct_list);
1730 
1731  /* Drop all references from the state file for this account
1732  */
1733  guid = xaccAccountGetGUID (account);
1734  guid_to_string_buff (guid, guidstr);
1735  gnc_state_drop_sections_for (guidstr);
1736 
1737  /*
1738  * Finally, delete the account, any subaccounts it may still
1739  * have, and any splits it or its subaccounts may still have.
1740  */
1741  xaccAccountBeginEdit (account);
1742  xaccAccountDestroy (account);
1743  gnc_resume_gui_refresh ();
1744  gnc_unset_busy_cursor(NULL);
1745 }
1746 
1747 static void
1748 gnc_plugin_page_account_tree_cmd_renumber_accounts (GSimpleAction *simple,
1749  GVariant *paramter,
1750  gpointer user_data)
1751 {
1752  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1753  Account *account;
1754  GtkWidget *window;
1755 
1756  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1758  if (!window || !account)
1759  return;
1760 
1761  gnc_account_renumber_create_dialog(window, account);
1762 }
1763 
1764 static void
1765 gnc_plugin_page_account_tree_cmd_refresh (GSimpleAction *simple,
1766  GVariant *paramter,
1767  gpointer user_data)
1768 {
1769  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1771 
1772  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1773 
1774  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1775 
1776  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
1777  gtk_widget_queue_draw (priv->widget);
1778 }
1779 
1780 /*********************/
1781 
1782 static void
1783 gnc_plugin_page_account_tree_cmd_view_filter_by (GSimpleAction *simple,
1784  GVariant *paramter,
1785  gpointer user_data)
1786 {
1787  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1789 
1790  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1791  ENTER("(action %p, page %p)", simple, page);
1792 
1793  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1794  account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page));
1795  LEAVE(" ");
1796 }
1797 
1798 static void
1799 gnc_plugin_page_account_tree_cmd_reconcile (GSimpleAction *simple,
1800  GVariant *paramter,
1801  gpointer user_data)
1802 {
1803  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1804  GtkWidget *window;
1805  Account *account;
1806  RecnWindow *recnData;
1807 
1809  g_return_if_fail (account != NULL);
1810 
1811  /* To prevent mistakes involving saving an edited transaction after
1812  * finishing a reconciliation (reverting the reconcile state), we could look
1813  * at all open registers and determine if any of them have a transaction
1814  * being edited that involves the account to be reconciled.
1815  *
1816  * However, the reconcile window isn't modal so it's still possible to start
1817  * editing a transaction after opening it. Assume the user knows what
1818  * they're doing if they start a reconciliation from the account tree and
1819  * don't attempt to stop them.
1820  */
1821 
1822  window = GNC_PLUGIN_PAGE (page)->window;
1823  recnData = recnWindow (window, account);
1824  gnc_ui_reconcile_window_raise (recnData);
1825 }
1826 
1827 static void
1828 gnc_plugin_page_account_tree_cmd_autoclear (GSimpleAction *simple,
1829  GVariant *paramter,
1830  gpointer user_data)
1831 {
1832  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1833  GtkWidget *window;
1834  Account *account;
1835  AutoClearWindow *autoClearData;
1836 
1838  g_return_if_fail (account != NULL);
1839 
1840  window = GNC_PLUGIN_PAGE (page)->window;
1841  autoClearData = autoClearWindow (window, account);
1842  gnc_ui_autoclear_window_raise (autoClearData);
1843 }
1844 
1845 static void
1846 gnc_plugin_page_account_tree_cmd_transfer (GSimpleAction *simple,
1847  GVariant *paramter,
1848  gpointer user_data)
1849 {
1850  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1851  GtkWidget *window;
1852  Account *account;
1853 
1855  window = GNC_PLUGIN_PAGE (page)->window;
1856  gnc_xfer_dialog (window, account);
1857 }
1858 
1859 static void
1860 gnc_plugin_page_account_tree_cmd_stock_split (GSimpleAction *simple,
1861  GVariant *paramter,
1862  gpointer user_data)
1863 {
1864  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1865  GtkWidget *window;
1866  Account *account;
1867 
1869  window = GNC_PLUGIN_PAGE (page)->window;
1870  gnc_stock_split_dialog (window, account);
1871 }
1872 
1873 static void
1874 gnc_plugin_page_account_tree_cmd_stock_assistant (GSimpleAction *simple,
1875  GVariant *paramter,
1876  gpointer user_data)
1877 {
1878  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1879  Account *account;
1880  GtkWidget *window;
1881 
1882  ENTER ("(action %p, page %p)", simple, page);
1883 
1885  window = GNC_PLUGIN_PAGE(page)->window;
1886  gnc_stock_transaction_assistant (window, account);
1887 
1888  LEAVE (" ");
1889 }
1890 
1891 static void
1892 gnc_plugin_page_account_tree_cmd_edit_tax_options (GSimpleAction *simple,
1893  GVariant *paramter,
1894  gpointer user_data)
1895 {
1896  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1897  GtkWidget *window;
1898  Account *account;
1899 
1901  window = GNC_PLUGIN_PAGE (page)->window;
1902  gnc_tax_info_dialog (window, account);
1903 }
1904 
1905 static void
1906 gnc_plugin_page_account_tree_cmd_lots (GSimpleAction *simple,
1907  GVariant *paramter,
1908  gpointer user_data)
1909 {
1910  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1912  GtkWidget *window = GNC_PLUGIN_PAGE (page)->window;
1913  gnc_lot_viewer_dialog (GTK_WINDOW(window), account);
1914 }
1915 
1916 static gboolean
1917 scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
1918 {
1919  if (event->length == 0) return FALSE;
1920 
1921  switch (event->keyval)
1922  {
1923  case GDK_KEY_Escape:
1924  {
1925  gboolean abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), FALSE,
1926  "%s", _(check_repair_abort_YN));
1927 
1928  if (abort_scrub)
1929  gnc_set_abort_scrub (TRUE);
1930 
1931  return TRUE;
1932  }
1933  default:
1934  break;
1935  }
1936  return FALSE;
1937 }
1938 
1939 static void
1940 gnc_plugin_page_account_tree_cmd_scrub (GSimpleAction *simple,
1941  GVariant *paramter,
1942  gpointer user_data)
1943 {
1944  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1946  GncWindow *window;
1947  gulong scrub_kp_handler_ID;
1948 
1949  g_return_if_fail (account != NULL);
1950 
1951  prepare_scrubbing ();
1952 
1953  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
1954  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
1955  G_CALLBACK(scrub_kp_handler), NULL);
1956  gnc_window_set_progressbar_window (window);
1957 
1958  xaccAccountScrubOrphans (account, gnc_window_show_progress);
1959  xaccAccountScrubImbalance (account, gnc_window_show_progress);
1960 
1961  // XXX: Lots/capital gains scrubbing is disabled
1962  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1963  xaccAccountScrubLots(account);
1964 
1965  gncScrubBusinessAccount(account, gnc_window_show_progress);
1966 
1967  finish_scrubbing (window, scrub_kp_handler_ID);
1968 }
1969 
1970 static void
1971 gnc_plugin_page_account_tree_cmd_scrub_sub (GSimpleAction *simple,
1972  GVariant *paramter,
1973  gpointer user_data)
1974 {
1975  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
1977  GncWindow *window;
1978  gulong scrub_kp_handler_ID;
1979 
1980  g_return_if_fail (account != NULL);
1981 
1982  prepare_scrubbing ();
1983 
1984  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
1985  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
1986  G_CALLBACK(scrub_kp_handler), NULL);
1987  gnc_window_set_progressbar_window (window);
1988 
1989  xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
1990  xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
1991 
1992  // XXX: Lots/capital gains scrubbing is disabled
1993  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1994  xaccAccountTreeScrubLots(account);
1995 
1996  gncScrubBusinessAccountTree(account, gnc_window_show_progress);
1997 
1998  finish_scrubbing (window, scrub_kp_handler_ID);
1999 }
2000 
2001 static void
2002 gnc_plugin_page_account_tree_cmd_scrub_all (GSimpleAction *simple,
2003  GVariant *paramter,
2004  gpointer user_data)
2005 {
2006  auto page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(user_data);
2007  Account *root = gnc_get_current_root_account ();
2008  GncWindow *window;
2009  gulong scrub_kp_handler_ID;
2010 
2011  prepare_scrubbing ();
2012 
2013  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2014  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2015  G_CALLBACK(scrub_kp_handler), NULL);
2016  gnc_window_set_progressbar_window (window);
2017 
2018  xaccAccountTreeScrubOrphans (root, gnc_window_show_progress);
2019  xaccAccountTreeScrubImbalance (root, gnc_window_show_progress);
2020  // XXX: Lots/capital gains scrubbing is disabled
2021  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2022  xaccAccountTreeScrubLots(root);
2023 
2024  gncScrubBusinessAccountTree(root, gnc_window_show_progress);
2025 
2026  finish_scrubbing (window, scrub_kp_handler_ID);
2027 }
2028 
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2902
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:2803
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.cpp:127
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:4502
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:3233
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:3210
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:2198
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:1588
#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:3271
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:2943
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:3010
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:1598
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2927
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1473
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3367
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4070
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:1514
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.cpp:142