GnuCash  4.12-68-g5dc52459a1+
gnc-plugin-page-account-tree.c
Go to the documentation of this file.
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 <gtk/gtk.h>
38 #include <glib/gi18n.h>
42 
43 #include "Scrub.h"
44 #include "Scrub3.h"
45 #include "ScrubBusiness.h"
46 #include "Transaction.h"
47 #include "dialog-account.h"
48 #include "dialog-transfer.h"
49 #include "dialog-utils.h"
50 #include "assistant-hierarchy.h"
51 #include "gnc-account-sel.h"
52 #include "gnc-component-manager.h"
53 #include "gnc-engine.h"
54 #include "gnc-gnome-utils.h"
55 #include "gnc-gobject-utils.h"
56 #include "gnc-icons.h"
58 #include "gnc-prefs.h"
59 #include "gnc-session.h"
60 #include "gnc-split-reg.h"
61 #include "gnc-state.h"
62 #include "gnc-tree-view-account.h"
64 #include "gnc-ui.h"
65 #include "gnc-ui-util.h"
66 #include "gnc-window.h"
67 #include "dialog-lot-viewer.h"
68 #include "window-reconcile.h"
69 #include "window-autoclear.h"
70 #include "window-main-summarybar.h"
72 #include "dialog-find-account.h"
73 #include <gnc-glib-utils.h>
74 
75 /* This static indicates the debugging module that this .o belongs to. */
76 static QofLogModule log_module = GNC_MOD_GUI;
77 
78 
79 /********************************************************************
80  * delete_account_helper
81  * See if this account has any splits present. Set the user data
82  * and return the same value to stop walking the account tree if
83  * appropriate.
84  ********************************************************************/
85 typedef struct _delete_helper
86 {
87  gboolean has_splits;
88  gboolean has_ro_splits;
90 
91 
92 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-acct-tree"
93 #define STATE_SECTION "Account Hierarchy"
94 
95 #define DELETE_DIALOG_FILTER "filter"
96 #define DELETE_DIALOG_ACCOUNT "account"
97 #define DELETE_DIALOG_TRANS_MAS "trans_mas"
98 #define DELETE_DIALOG_SA_MAS "sa_mas"
99 #define DELETE_DIALOG_SA_TRANS_MAS "sa_trans_mas"
100 #define DELETE_DIALOG_SA_TRANS "sa_trans"
101 #define DELETE_DIALOG_SA_SPLITS "sa_has_split"
102 #define DELETE_DIALOG_OK_BUTTON "deletebutton"
103 
104 enum
105 {
106  ACCOUNT_SELECTED,
107  LAST_SIGNAL
108 };
109 
111 {
112  GtkWidget *widget;
113  GtkTreeView *tree_view;
114  gint component_id;
117 
118 #define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(o) \
119  ((GncPluginPageAccountTreePrivate*)gnc_plugin_page_account_tree_get_instance_private((GncPluginPageAccountTree*)o))
120 
121 static GObjectClass *parent_class = NULL;
122 
123 /************************************************************
124  * Prototypes *
125  ************************************************************/
126 /* Plugin Actions */
127 static void gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass);
128 static void gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page);
129 static void gnc_plugin_page_account_tree_finalize (GObject *object);
130 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data);
131 
132 static gboolean gnc_plugin_page_account_tree_focus_widget (GncPluginPage *plugin_page);
133 static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page);
134 static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page);
135 static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
136 static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
137 
138 /* Callbacks */
139 static void gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data);
140 static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
141  GdkEventButton *event,
142  GncPluginPage *page);
143 static void gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
144  GtkTreePath *path,
145  GtkTreeViewColumn *col,
147 
148 static void gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
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 /* Command callbacks */
154 static void gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *plugin_page);
155 static void gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *plugin_page);
156 static void gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action, GncPluginPageAccountTree *page);
157 static void gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action, GncPluginPageAccountTree *page);
158 static void gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page);
159 static void gnc_plugin_page_account_tree_cmd_find_account (GtkAction *action, GncPluginPageAccountTree *page);
160 static void gnc_plugin_page_account_tree_cmd_find_account_popup (GtkAction *action, GncPluginPageAccountTree *page);
161 static void gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page);
162 static void gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action, GncPluginPageAccountTree *page);
163 static void gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action, GncPluginPageAccountTree *plugin_page);
164 static void gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action, GncPluginPageAccountTree *page);
165 static void gnc_plugin_page_account_tree_cmd_refresh (GtkAction *action, GncPluginPageAccountTree *page);
166 static void gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action, GncPluginPageAccountTree *page);
167 static void gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action, GncPluginPageAccountTree *page);
168 static void gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action, GncPluginPageAccountTree *page);
169 static void gnc_plugin_page_account_tree_cmd_edit_tax_options (GtkAction *action, GncPluginPageAccountTree *page);
170 static void gnc_plugin_page_account_tree_cmd_lots (GtkAction *action, GncPluginPageAccountTree *page);
171 static void gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page);
172 static void gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page);
173 static void gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page);
174 static void gnc_plugin_page_account_tree_cmd_cascade_account_properties (GtkAction *action, GncPluginPageAccountTree *page);
175 
176 /* Command callback for new Register Test */
177 static void gnc_plugin_page_account_tree_cmd_open2_account (GtkAction *action, GncPluginPageAccountTree *page);
178 static void gnc_plugin_page_account_tree_cmd_open2_subaccounts (GtkAction *action, GncPluginPageAccountTree *page);
179 /* Account Deletion Actions. */
180 static int confirm_delete_account (GtkAction *action,
182  Account* sta, Account* saa,
183  delete_helper_t delete_res);
184 static void do_delete_account (Account* account, Account* saa, Account* sta,
185  Account* ta);
186 
187 
188 
189 static guint plugin_page_signals[LAST_SIGNAL] = { 0 };
190 
191 
192 static GtkActionEntry gnc_plugin_page_account_tree_actions [] =
193 {
194  /* Toplevel */
195  { "FakeToplevel", NULL, "", NULL, NULL, NULL },
196 
197  /* File menu */
198  {
199  "FileNewAccountAction", GNC_ICON_NEW_ACCOUNT, N_("New _Account..."), NULL,
200  N_("Create a new Account"),
201  G_CALLBACK (gnc_plugin_page_account_tree_cmd_new_account)
202  },
203  {
204  "FileAddAccountHierarchyAssistantAction", GNC_ICON_NEW_ACCOUNT, N_("New Account _Hierarchy..."), NULL,
205  N_("Extend the current book by merging with new account type categories"),
206  G_CALLBACK (gnc_plugin_page_account_tree_cmd_file_new_hierarchy)
207  },
208 #ifdef REGISTER2_ENABLED
209  {
210  "FileOpenAccount2Action", GNC_ICON_OPEN_ACCOUNT, N_("Open _Account"), NULL,
211  N_("Open the selected account"),
212  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_account)
213  },
214  {
215  "FileOpenAccountAction", GNC_ICON_OPEN_ACCOUNT, N_("Open _Old Style Register Account"), NULL,
216  N_("Open the old style register selected account"),
217  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account)
218  },
219 #else
220  {
221  "FileOpenAccountAction", GNC_ICON_OPEN_ACCOUNT, N_("Open _Account"), NULL,
222  N_("Open the selected account"),
223  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account)
224  },
225 #endif
226 
227 #ifdef REGISTER2_ENABLED
228  {
229  "FileOpenSubaccounts2Action", GNC_ICON_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
230  N_("Open the selected account and all its subaccounts"),
231  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_subaccounts)
232  },
233  {
234  "FileOpenSubaccountsAction", GNC_ICON_OPEN_ACCOUNT, N_("Open Old St_yle Subaccounts"), NULL,
235  N_("Open the old style register selected account and all its subaccounts"),
236  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_subaccounts)
237  },
238 #else
239  {
240  "FileOpenSubaccountsAction", GNC_ICON_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
241  N_("Open the selected account and all its subaccounts"),
242  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_subaccounts)
243  },
244 #endif
245 
246  /* Edit menu */
247  {
248  "EditEditAccountAction", GNC_ICON_EDIT_ACCOUNT, N_("Edit _Account"), "<primary>e",
249  N_("Edit the selected account"),
250  G_CALLBACK (gnc_plugin_page_account_tree_cmd_edit_account)
251  },
252  {
253  "EditDeleteAccountAction", GNC_ICON_DELETE_ACCOUNT, N_("_Delete Account..."), "Delete",
254  N_("Delete selected account"),
255  G_CALLBACK (gnc_plugin_page_account_tree_cmd_delete_account)
256  },
257  {
258  "EditCascadeAccountAction", NULL, N_("_Cascade Account Properties..."), NULL,
259  N_("Cascade selected properties for account"),
260  G_CALLBACK (gnc_plugin_page_account_tree_cmd_cascade_account_properties)
261  },
262  {
263  "EditFindAccountAction", "edit-find", N_("F_ind Account"), "<primary>i",
264  N_("Find an account"),
265  G_CALLBACK (gnc_plugin_page_account_tree_cmd_find_account)
266  },
267  {
268  "EditFindAccountPopupAction", "edit-find", N_("F_ind Account"), "<primary>i",
269  N_("Find an account"),
270  G_CALLBACK (gnc_plugin_page_account_tree_cmd_find_account_popup)
271  },
272  {
273  "EditRenumberSubaccountsAction", NULL, N_("_Renumber Subaccounts..."), NULL,
274  N_("Renumber the children of the selected account"),
275  G_CALLBACK (gnc_plugin_page_account_tree_cmd_renumber_accounts)
276  },
277  {
278  "EditTaxOptionsAction", NULL,
279  /* Translators: remember to reuse this
280  translation in dialog-account.glade */
281  N_("Ta_x Report Options"), NULL,
282  /* Translators: currently implemented are
283  US: income tax and
284  DE: VAT
285  So adjust this string */
286  N_("Setup relevant accounts for tax reports, e.g. US income tax"),
287  G_CALLBACK (gnc_plugin_page_account_tree_cmd_edit_tax_options)
288  },
289  /* View menu */
290  {
291  "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, NULL,
292  G_CALLBACK (gnc_plugin_page_account_tree_cmd_view_filter_by)
293  },
294  {
295  "ViewRefreshAction", "view-refresh", N_("_Refresh"), "<primary>r",
296  N_("Refresh this window"),
297  G_CALLBACK (gnc_plugin_page_account_tree_cmd_refresh)
298  },
299 
300  /* Actions menu */
301  {
302  "ActionsReconcileAction", NULL, N_("_Reconcile..."), NULL,
303  N_("Reconcile the selected account"),
304  G_CALLBACK (gnc_plugin_page_account_tree_cmd_reconcile)
305  },
306  {
307  "ActionsAutoClearAction", NULL, N_("_Auto-clear..."), NULL,
308  N_("Automatically clear individual transactions, given a cleared amount"),
309  G_CALLBACK (gnc_plugin_page_account_tree_cmd_autoclear)
310  },
311  {
312  "ActionsTransferAction", NULL, N_("_Transfer..."), "<primary>t",
313  N_("Transfer funds from one account to another"),
314  G_CALLBACK (gnc_plugin_page_account_tree_cmd_transfer)
315  },
316  {
317  "ActionsStockSplitAction", NULL, N_("Stoc_k Split..."), NULL,
318  N_("Record a stock split or a stock merger"),
319  G_CALLBACK (gnc_plugin_page_account_tree_cmd_stock_split)
320  },
321  {
322  "ActionsLotsAction", NULL, N_("View _Lots..."), NULL,
323  N_("Bring up the lot viewer/editor window"),
324  G_CALLBACK (gnc_plugin_page_account_tree_cmd_lots)
325  },
326  {
327  "ScrubAction", NULL, N_("Check & Repair A_ccount"), NULL,
328  N_("Check for and repair unbalanced transactions and orphan splits " "in this account"),
329  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub)
330  },
331  {
332  "ScrubSubAction", NULL, N_("Check & Repair Su_baccounts"), NULL,
333  N_("Check for and repair unbalanced transactions and orphan splits "
334  "in this account and its subaccounts"),
335  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_sub)
336  },
337  {
338  "ScrubAllAction", NULL, N_("Check & Repair A_ll"), NULL,
339  N_("Check for and repair unbalanced transactions and orphan splits " "in all accounts"),
340  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_all)
341  },
342  /* Extensions Menu */
343  { "Register2TestAction", NULL, N_("_Register2"), NULL, NULL, NULL },
344  {
345  "Register2TestAccountAction", GNC_ICON_OPEN_ACCOUNT, N_("Open _Account"), NULL,
346  N_("Open the selected account"),
347  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_account)
348  },
349  {
350  "Register2TestSubAccountAction", GNC_ICON_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
351  N_("Open the selected account and all its subaccounts"),
352  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_subaccounts)
353  },
354 };
356 static guint gnc_plugin_page_account_tree_n_actions = G_N_ELEMENTS (gnc_plugin_page_account_tree_actions);
357 
358 
361 static const gchar *actions_requiring_account_rw[] =
362 {
363  "EditEditAccountAction",
364  "EditDeleteAccountAction",
365  "ActionsReconcileAction",
366  "ActionsAutoClearAction",
367  NULL
368 };
369 
372 static const gchar *actions_requiring_subaccounts_rw[] =
373 {
374  "EditRenumberSubaccountsAction",
375  "EditCascadeAccountAction",
376  NULL
377 };
378 
381 static const gchar *actions_requiring_account_always[] =
382 {
383  "FileOpenAccountAction",
384 #ifdef REGISTER2_ENABLED
385  "FileOpenAccount2Action",
386 #endif
387  "FileOpenSubaccountsAction",
388  "ActionsLotsAction",
389  NULL
390 };
391 
392 /* This is the list of actions which are switched inactive in a read-only book. */
393 static const gchar* readonly_inactive_actions[] =
394 {
395  "FileNewAccountAction",
396  "FileAddAccountHierarchyAssistantAction",
397  "EditEditAccountAction",
398  "EditDeleteAccountAction",
399  "ActionsTransferAction",
400  "ActionsReconcileAction",
401  "ActionsAutoClearAction",
402  "ActionsStockSplitAction",
403  "ScrubAction",
404  "ScrubSubAction",
405  "ScrubAllAction",
406  NULL
407 };
408 
410 static action_toolbar_labels toolbar_labels[] =
411 {
412  { "FileOpenAccountAction", N_("Open") },
413 #ifdef REGISTER2_ENABLED
414  { "FileOpenAccount2Action", N_("Open2") },
415 #endif
416  { "EditEditAccountAction", N_("Edit") },
417  { "FileNewAccountAction", N_("New") },
418  { "EditDeleteAccountAction", N_("Delete") },
419  { NULL, NULL },
420 };
421 
424 {
425  GncPluginPageAccountTree *plugin_page;
426 
427  ENTER(" ");
428  plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE,
429  NULL);
430 
431  LEAVE("new account tree page %p", plugin_page);
432  return GNC_PLUGIN_PAGE (plugin_page);
433 }
434 
435 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageAccountTree, gnc_plugin_page_account_tree, GNC_TYPE_PLUGIN_PAGE)
436 
437 static gboolean show_abort_verify = TRUE;
438 
439 static void
440 prepare_scrubbing ()
441 {
442  gnc_suspend_gui_refresh ();
443  gnc_set_abort_scrub (FALSE);
444 }
445 
446 static void
447 finish_scrubbing (GncWindow *window, gulong handler_id)
448 {
449  g_signal_handler_disconnect (G_OBJECT(window), handler_id);
450  show_abort_verify = TRUE;
451  gnc_resume_gui_refresh ();
452 }
453 
454 static gboolean
455 gnc_plugin_page_account_finish_pending (GncPluginPage* page)
456 {
457  if (gnc_get_ongoing_scrub ())
458  {
459  if (show_abort_verify)
460  {
461  gboolean ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window
462  (GNC_PLUGIN_PAGE(page))), FALSE,
463  _("'Check & Repair' is currently running, do you want to abort it?"));
464 
465  show_abort_verify = FALSE;
466 
467  if (ret)
468  gnc_set_abort_scrub (TRUE);
469 
470  return ret; // verify response
471  }
472  else
473  {
474  if (gnc_get_abort_scrub ())
475  return TRUE; // close
476  else
477  return FALSE; // no close
478  }
479  }
480  else
481  return TRUE; // normal close
482 }
483 
484 static void
485 gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
486 {
487  GObjectClass *object_class = G_OBJECT_CLASS (klass);
488  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
489 
490  parent_class = g_type_class_peek_parent (klass);
491 
492  object_class->finalize = gnc_plugin_page_account_tree_finalize;
493 
494  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
495  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
496  gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget;
497  gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget;
498  gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
499  gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
500  gnc_plugin_class->focus_page_function = gnc_plugin_page_account_tree_focus_widget;
501  gnc_plugin_class->finish_pending = gnc_plugin_page_account_finish_pending;
502 
503  plugin_page_signals[ACCOUNT_SELECTED] =
504  g_signal_new ("account_selected",
505  G_OBJECT_CLASS_TYPE (object_class),
506  G_SIGNAL_RUN_FIRST,
507  G_STRUCT_OFFSET (GncPluginPageAccountTreeClass, account_selected),
508  NULL, NULL,
509  g_cclosure_marshal_VOID__POINTER,
510  G_TYPE_NONE, 1,
511  G_TYPE_POINTER);
512 }
513 
514 static void
515 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
516 {
517  GtkActionGroup *action_group;
519  GncPluginPage *parent;
520  const GList *page_list;
521 
522  ENTER("page %p", plugin_page);
523  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(plugin_page);
524 
525  /* Init parent declared variables */
526  parent = GNC_PLUGIN_PAGE(plugin_page);
527 #ifdef REGISTER2_ENABLED
528  g_object_set(G_OBJECT(plugin_page),
529  "page-name", _("Accounts"),
530  "page-uri", "default:",
531  "ui-description", "gnc-plugin-page-account-tree2-ui.xml",
532  NULL);
533 #else
534  g_object_set(G_OBJECT(plugin_page),
535  "page-name", _("Accounts"),
536  "page-uri", "default:",
537  "ui-description", "gnc-plugin-page-account-tree-ui.xml",
538  NULL);
539 #endif
540  g_signal_connect (G_OBJECT (plugin_page), "selected",
541  G_CALLBACK (gnc_plugin_page_account_tree_selected), plugin_page);
542 
543  /* change me when the system supports multiple books */
544  gnc_plugin_page_add_book(parent, gnc_get_current_book());
545 
546  /* Is this the first accounts page? */
547  page_list =
548  gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
549  if (!page_list || plugin_page == page_list->data)
550  {
551  g_object_set_data(G_OBJECT(plugin_page), PLUGIN_PAGE_IMMUTABLE,
552  GINT_TO_POINTER(1));
553  }
554 
555  /* Create menu and toolbar information */
556  action_group =
558  "GncPluginPageAccountTreeActions");
559  gtk_action_group_add_actions(action_group,
560  gnc_plugin_page_account_tree_actions,
561  gnc_plugin_page_account_tree_n_actions,
562  plugin_page);
563  gnc_plugin_init_short_names (action_group, toolbar_labels);
564 
565  /* Visible types */
566  priv->fd.visible_types = -1; /* Start with all types */
567  priv->fd.show_hidden = FALSE;
568  priv->fd.show_unused = TRUE;
569  priv->fd.show_zero_total = TRUE;
570  priv->fd.filter_override = g_hash_table_new (g_direct_hash, g_direct_equal);
571 
572  LEAVE("page %p, priv %p, action group %p",
573  plugin_page, priv, action_group);
574 }
575 
576 static void
577 gnc_plugin_page_account_tree_finalize (GObject *object)
578 {
581 
582  ENTER("object %p", object);
583  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (object);
584  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
585  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
586  g_return_if_fail (priv != NULL);
587 
588  G_OBJECT_CLASS (parent_class)->finalize (object);
589  LEAVE(" ");
590 }
591 
592 void
593 gnc_plugin_page_account_tree_open (Account *account, GtkWindow *win)
594 {
597  GncPluginPage *plugin_page = NULL;
598  const GList *page_list;
599  GtkWidget *window;
600 
601  /* Find Accounts page */
602  page_list = gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
603 
604  // If we have a window, look for account page in that window
605  if (gnc_list_length_cmp (page_list, 0))
606  {
607  if (win != NULL)
608  {
609  for ( ; page_list; page_list = g_list_next(page_list))
610  {
611  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
612  if (GTK_WINDOW(plugin_page->window) == win)
613  break;
614  }
615  }
616  else // if no window, open first account page in list
617  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
618  }
619  else // we have no account pages, create one
620  plugin_page = gnc_plugin_page_account_tree_new ();
621 
622  g_return_if_fail(plugin_page);
623  window = plugin_page->window;
624 
625  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), plugin_page);
626 
627  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
628  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
629 
630  if (account != NULL)
631  {
632  Account *root_account = gnc_get_current_root_account ();
633  Account *parent_account = NULL;
634  Account *temp_account = account;
635 
636  g_hash_table_insert (priv->fd.filter_override, account, account);
637 
638  // make sure we override all the parent accounts to root
639  while (parent_account != root_account)
640  {
641  parent_account = gnc_account_get_parent (temp_account);
642 
643  g_hash_table_insert (priv->fd.filter_override, parent_account, parent_account);
644  temp_account = parent_account;
645  }
646  gnc_tree_view_account_refilter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
647  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), account);
648  }
649 }
650 
651 Account *
653 {
655  Account *account;
656 
657  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
658  ENTER("page %p (tree view %p)", page, priv->tree_view);
659  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
660  if (account == NULL)
661  {
662  LEAVE("no account");
663  return NULL;
664  }
665 
666  LEAVE("account %p", account);
667  return account;
668 }
669 
674 static gboolean
675 gnc_plugin_page_account_tree_focus_widget (GncPluginPage *account_plugin_page)
676 {
677  if (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(account_plugin_page))
678  {
679  GncPluginPageAccountTreePrivate *priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_plugin_page);
680  GtkTreeView *view = GTK_TREE_VIEW(priv->tree_view);
681 
682  if (!gtk_widget_is_focus (GTK_WIDGET(view)))
683  gtk_widget_grab_focus (GTK_WIDGET(view));
684  }
685  return FALSE;
686 }
687 
688 /* Virtual Functions */
689 
690 static void
691 gnc_plugin_page_account_refresh_cb (GHashTable *changes, gpointer user_data)
692 {
693  GncPluginPageAccountTree *page = user_data;
695 
696  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
697 
698  /* We're only looking for forced updates here. */
699  if (changes)
700  return;
701 
702  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
703 
704  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
705  gtk_widget_queue_draw(priv->widget);
706 }
707 
708 static void
709 gnc_plugin_page_account_tree_close_cb (gpointer user_data)
710 {
711  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
712  gnc_main_window_close_page(plugin_page);
713 }
714 
715 static void
716 gnc_plugin_page_account_editing_started_cd (gpointer various, GncPluginPageRegister *page)
717 {
718  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
719  GtkAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window),
720  "EditDeleteAccountAction");
721 
722  if (action != NULL)
723  gtk_action_set_sensitive (action, FALSE);
724 }
725 
726 static void
727 gnc_plugin_page_account_editing_finished_cb (gpointer various, GncPluginPageRegister *page)
728 {
729  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
730  GtkAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window),
731  "EditDeleteAccountAction");
732 
733  if (action != NULL)
734  gtk_action_set_sensitive (action, TRUE);
735 }
736 
737 static GtkWidget *
738 gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page)
739 {
742  GtkTreeSelection *selection;
743  GtkTreeView *tree_view;
744  GtkWidget *scrolled_window;
745  GtkTreeViewColumn *col;
746 
747  ENTER("page %p", plugin_page);
748  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
749  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
750  if (priv->widget != NULL)
751  {
752  LEAVE("widget = %p", priv->widget);
753  return priv->widget;
754  }
755 
756  priv->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
757  gtk_box_set_homogeneous (GTK_BOX (priv->widget), FALSE);
758  gtk_widget_show (priv->widget);
759 
760  // Set the name for this widget so it can be easily manipulated with css
761  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-account-page");
762 
763  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
764  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
765  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
766  gtk_widget_show (scrolled_window);
767  gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window,
768  TRUE, TRUE, 0);
769 
770  tree_view = gnc_tree_view_account_new(FALSE);
772  GNC_TREE_VIEW(tree_view), "description");
773  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
775  GNC_TREE_VIEW(tree_view), "total");
776  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
777  gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view));
778  g_object_set(G_OBJECT(tree_view),
779  "state-section", STATE_SECTION,
780  "show-column-menu", TRUE,
781  NULL);
782 
783  /* No name handler; then the user can't click on the name of the
784  account to open its register. */
785  gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
786  gnc_tree_view_account_code_edited_cb);
787  gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
788  gnc_tree_view_account_description_edited_cb);
789  gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
790  gnc_tree_view_account_notes_edited_cb);
791 
792  // Setup some callbacks so menu actions can be disabled/enabled
793  gnc_tree_view_account_set_editing_started_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
794  (GFunc)gnc_plugin_page_account_editing_started_cd, page);
795  gnc_tree_view_account_set_editing_finished_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
796  (GFunc)gnc_plugin_page_account_editing_finished_cb, page);
797 
798  priv->tree_view = tree_view;
799  selection = gtk_tree_view_get_selection(tree_view);
800  g_signal_connect (G_OBJECT (selection), "changed",
801  G_CALLBACK (gnc_plugin_page_account_tree_selection_changed_cb), page);
802  g_signal_connect (G_OBJECT (tree_view), "button-press-event",
803  G_CALLBACK (gnc_plugin_page_account_tree_button_press_cb), page);
804  g_signal_connect (G_OBJECT (tree_view), "row-activated",
805  G_CALLBACK (gnc_plugin_page_account_tree_double_click_cb), page);
806 
807  gtk_tree_view_set_headers_visible(tree_view, TRUE);
808  gnc_plugin_page_account_tree_selection_changed_cb (NULL, page);
809  gtk_widget_show (GTK_WIDGET (tree_view));
810  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(tree_view));
811 
812  priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view);
814  GNC_TREE_VIEW_ACCOUNT(tree_view),
816 
817  priv->component_id =
818  gnc_register_gui_component(PLUGIN_PAGE_ACCT_TREE_CM_CLASS,
819  gnc_plugin_page_account_refresh_cb,
820  gnc_plugin_page_account_tree_close_cb,
821  page);
822  gnc_gui_component_set_session (priv->component_id,
823  gnc_get_current_session());
824 
825  plugin_page->summarybar = gnc_main_window_summary_new();
826  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
827  FALSE, FALSE, 0);
828  gtk_widget_show(plugin_page->summarybar);
829  gnc_plugin_page_account_tree_summarybar_position_changed(NULL, NULL, page);
830  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
831  GNC_PREF_SUMMARYBAR_POSITION_TOP,
832  gnc_plugin_page_account_tree_summarybar_position_changed,
833  page);
834  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
835  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
836  gnc_plugin_page_account_tree_summarybar_position_changed,
837  page);
838 
839  g_signal_connect (G_OBJECT(plugin_page), "inserted",
840  G_CALLBACK(gnc_plugin_page_inserted_cb),
841  NULL);
842 
843  // Read account filter state information from account section
844  gnc_tree_view_account_restore_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
845  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
846 
847  LEAVE("widget = %p", priv->widget);
848  return priv->widget;
849 }
850 
851 static void
852 gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page)
853 {
856 
857  ENTER("page %p", plugin_page);
858  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
859  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
860 
861  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
862  GNC_PREF_SUMMARYBAR_POSITION_TOP,
863  gnc_plugin_page_account_tree_summarybar_position_changed,
864  page);
865  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
866  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
867  gnc_plugin_page_account_tree_summarybar_position_changed,
868  page);
869 
870  // Save account filter state information to account section
871  gnc_tree_view_account_save_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
872  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
873 
874  // Destroy the filter override hash table
875  g_hash_table_destroy(priv->fd.filter_override);
876 
877  // Remove the page_changed signal callback
878  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
879 
880  // Remove the page focus idle function if present
881  g_idle_remove_by_data (plugin_page);
882 
883  if (priv->widget)
884  {
885  g_object_unref(G_OBJECT(priv->widget));
886  priv->widget = NULL;
887  }
888 
889  if (priv->component_id)
890  {
891  gnc_unregister_gui_component(priv->component_id);
892  priv->component_id = 0;
893  }
894 
895  LEAVE("widget destroyed");
896 }
897 
898 static void update_inactive_actions(GncPluginPage *plugin_page)
899 {
901  GtkActionGroup *action_group;
902  Account *account = NULL;
903  gboolean allow_write = !qof_book_is_readonly(gnc_get_current_book());
904  gboolean has_account = FALSE;
905  gboolean subaccounts = FALSE;
906 
907  g_return_if_fail (plugin_page && GNC_IS_PLUGIN_PAGE(plugin_page));
908 
909  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE (plugin_page);
910 
911  if (gtk_tree_view_get_selection (priv->tree_view))
912  {
913  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
914  has_account = (account != NULL);
915  subaccounts = (account && gnc_account_n_children (account) != 0);
916  /* Check here for placeholder accounts, etc. */
917  }
918 
919  /* Get the action group */
920  action_group = gnc_plugin_page_get_action_group(plugin_page);
921  g_return_if_fail(GTK_IS_ACTION_GROUP (action_group));
922 
923  /* Set the action's sensitivity */
924  gnc_plugin_update_actions (action_group, readonly_inactive_actions,
925  "sensitive", allow_write);
926  gnc_plugin_update_actions (action_group, actions_requiring_account_rw,
927  "sensitive", allow_write && has_account);
928  gnc_plugin_update_actions (action_group, actions_requiring_account_always,
929  "sensitive", has_account);
930  gnc_plugin_update_actions (action_group, actions_requiring_subaccounts_rw,
931  "sensitive", allow_write && subaccounts);
932  g_signal_emit (plugin_page, plugin_page_signals[ACCOUNT_SELECTED], 0, account);
933 }
934 
939 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data)
940 {
941  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object);
942  g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page));
943  update_inactive_actions(plugin_page);
944 }
945 
955 static void
956 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
957  GKeyFile *key_file,
958  const gchar *group_name)
959 {
960  GncPluginPageAccountTree *account_page;
962 
963  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
964  g_return_if_fail (key_file != NULL);
965  g_return_if_fail (group_name != NULL);
966 
967  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
968  group_name);
969 
970  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
971  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
972 
973  gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
974  &priv->fd, key_file, group_name);
975  LEAVE(" ");
976 }
977 
978 
979 
989 static GncPluginPage *
990 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
991  GKeyFile *key_file,
992  const gchar *group_name)
993 {
994  GncPluginPageAccountTree *account_page;
996  GncPluginPage *page;
997 
998  g_return_val_if_fail(key_file, NULL);
999  g_return_val_if_fail(group_name, NULL);
1000  ENTER("key_file %p, group_name %s", key_file, group_name);
1001 
1002  /* Create the new page. */
1004  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
1005  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
1006 
1007  /* Install it now so we can then manipulate the created widget */
1008  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
1009 
1010  gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
1011  &priv->fd, key_file, group_name);
1012  LEAVE(" ");
1013  return page;
1014 }
1015 
1016 
1017 /* Callbacks */
1018 
1019 static void
1020 gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data)
1021 {
1022  GncPluginPage *plugin_page;
1025  GtkPositionType position = GTK_POS_BOTTOM;
1026 
1027  g_return_if_fail(user_data != NULL);
1028 
1029  plugin_page = GNC_PLUGIN_PAGE(user_data);
1030  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data);
1031  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1032 
1033  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SUMMARYBAR_POSITION_TOP))
1034  position = GTK_POS_TOP;
1035 
1036  gtk_box_reorder_child(GTK_BOX(priv->widget),
1037  plugin_page->summarybar,
1038  (position == GTK_POS_TOP ? 0 : -1) );
1039 }
1040 
1048 static gboolean
1049 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
1050  GdkEventButton *event,
1051  GncPluginPage *page)
1052 {
1053 
1054  g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
1055 
1056  ENTER("widget %p, event %p, page %p", widget, event, page);
1057  gnc_main_window_button_press_cb(widget, event, page);
1058  LEAVE(" ");
1059 
1060  /* Always return FALSE. This will let the tree view callback run as
1061  * well which will select the item under the cursor. By the time
1062  * the user sees the menu both callbacks will have run and the menu
1063  * actions will operate on the just-selected account. */
1064  return FALSE;
1065 }
1066 
1067 static void
1068 gppat_open_account_common (GncPluginPageAccountTree *page,
1069  Account *account,
1070  gboolean include_subs)
1071 {
1072  GtkWidget *window;
1073  GncPluginPage *new_page;
1074 
1075  if (account == NULL)
1076  return;
1077 
1078  window = GNC_PLUGIN_PAGE (page)->window;
1079  new_page = gnc_plugin_page_register_new (account, include_subs);
1080  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
1081 }
1082 
1083 /*################## Added for Reg2 #################*/
1084 /* New Register Common */
1085 static void
1086 gppat_open2_account_common (GncPluginPageAccountTree *page,
1087  Account *account,
1088  gboolean include_subs)
1089 {
1090  GtkWidget *window;
1091  GncPluginPage *new_page;
1092 
1093  if (account == NULL)
1094  return;
1095 
1096  window = GNC_PLUGIN_PAGE (page)->window;
1097  new_page = gnc_plugin_page_register2_new (account, include_subs);
1098  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
1099 }
1100 /*################## Added for Reg2 #################*/
1101 
1102 static void
1103 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
1104  GtkTreePath *path,
1105  GtkTreeViewColumn *col,
1107 {
1108  GtkTreeModel *model;
1109  GtkTreeIter iter;
1110 
1111  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1112  g_return_if_fail (treeview);
1113 
1114  model = gtk_tree_view_get_model(treeview);
1115  if (gtk_tree_model_get_iter(model, &iter, path))
1116  {
1117  Account *account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path);
1118  if (xaccAccountGetPlaceholder (account))
1119  {
1120  /* This is a placeholder account. Only only show/hide
1121  * subaccount list if there is one.
1122  */
1123  if (gtk_tree_model_iter_has_child(model, &iter))
1124  {
1125  /* There are children,
1126  * just expand or collapse the row. */
1127  if (gtk_tree_view_row_expanded(treeview, path))
1128  gtk_tree_view_collapse_row(treeview, path);
1129  else
1130  gtk_tree_view_expand_row(treeview, path, FALSE);
1131  }
1132  }
1133  else
1134  {
1135  /* No placeholder account, so open its register */
1136 #ifdef REGISTER2_ENABLED
1137  gppat_open2_account_common (page, account, FALSE);
1138 #else
1139  gppat_open_account_common (page, account, FALSE);
1140 #endif
1141  }
1142  }
1143 }
1144 
1145 static void
1146 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
1148 {
1149  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
1150  update_inactive_actions (plugin_page);
1151 }
1152 
1153 
1154 /* Command callbacks */
1155 static void
1156 gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *page)
1157 {
1159  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1160  gnc_ui_new_account_window (parent, gnc_get_current_book(),
1161  account);
1162 }
1163 
1164 static void
1165 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *page)
1166 {
1167  gnc_ui_hierarchy_assistant(FALSE);
1168 }
1169 
1170 static void
1171 gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action,
1173 {
1174  Account *account;
1175 
1176  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1178  gppat_open_account_common (page, account, FALSE);
1179 }
1180 
1181 static void
1182 gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action,
1184 {
1185  Account *account;
1186 
1187  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1189  gppat_open_account_common (page, account, TRUE);
1190 }
1191 
1192 
1193 /*################## Added for Reg2 #################*/
1194 /* Register Firing - Single Account to start with */
1195 static void
1196 gnc_plugin_page_account_tree_cmd_open2_account (GtkAction *action,
1198 {
1199  Account *account;
1200 
1201  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1203  gppat_open2_account_common (page, account, FALSE);
1204 }
1205 
1206 static void
1207 gnc_plugin_page_account_tree_cmd_open2_subaccounts (GtkAction *action,
1209 {
1210  Account *account;
1211 
1212  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1214  gppat_open2_account_common (page, account, TRUE);
1215 }
1216 /*################## Added for Reg2 #################*/
1217 
1218 static void
1219 gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page)
1220 {
1221  Account *account;
1222  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1223  ENTER("action %p, page %p", action, page);
1224 
1226  g_return_if_fail (account != NULL);
1227 
1228  gnc_ui_edit_account_window (parent, account);
1229  LEAVE(" ");
1230 }
1231 
1232 static void
1233 gnc_plugin_page_account_tree_cmd_find_account (GtkAction *action, GncPluginPageAccountTree *page)
1234 {
1235  GtkWidget *window;
1236 
1237  ENTER("action %p, page %p", action, page);
1238 
1239  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1240 
1241  gnc_find_account_dialog (window, NULL);
1242  LEAVE(" ");
1243 }
1244 
1245 static void
1246 gnc_plugin_page_account_tree_cmd_find_account_popup (GtkAction *action, GncPluginPageAccountTree *page)
1247 {
1248  Account *account = NULL;
1249  GtkWidget *window;
1250 
1251  ENTER("action %p, page %p", action, page);
1252 
1254 
1255  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1256 
1257  gnc_find_account_dialog (window, account);
1258  LEAVE(" ");
1259 }
1260 
1261 static void
1262 gnc_plugin_page_account_tree_cmd_cascade_account_properties (GtkAction *action, GncPluginPageAccountTree *page)
1263 {
1264  Account *account = NULL;
1265  GtkWidget *window;
1266 
1267  ENTER("action %p, page %p", action, page);
1268 
1270 
1271  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page));
1272 
1273  if (account != NULL)
1274  gnc_account_cascade_properties_dialog (window, account);
1275 
1276  LEAVE(" ");
1277 }
1278 
1279 static gpointer
1280 delete_account_helper (Account * account, gpointer data)
1281 {
1282  delete_helper_t *helper_res = data;
1283  GList *splits;
1284 
1285  splits = xaccAccountGetSplitList (account);
1286  if (splits)
1287  {
1288  helper_res->has_splits = TRUE;
1289  while (splits)
1290  {
1291  Split *s = splits->data;
1292  Transaction *txn = xaccSplitGetParent (s);
1293  if (xaccTransGetReadOnly (txn))
1294  {
1295  helper_res->has_ro_splits = TRUE;
1296  break;
1297  }
1298  splits = splits->next;
1299  }
1300  }
1301 
1302  return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits);
1303 }
1304 
1305 /***
1306  *** The OK button of a Delete Account dialog is insensitive if
1307  *** and only if a sensitive account selector contains no accounts.
1308  ***/
1309 static void
1310 set_ok_sensitivity(GtkWidget *dialog)
1311 {
1312  GtkWidget *button;
1313  GtkWidget *sa_mas, *trans_mas;
1314  gint sa_mas_cnt, trans_mas_cnt;
1315  gboolean sensitive;
1316 
1317  sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
1318  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1319  sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas));
1320  trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas));
1321 
1322  sensitive = (((NULL == sa_mas) ||
1323  (!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) &&
1324  ((NULL == trans_mas) ||
1325  (!gtk_widget_is_sensitive(trans_mas) || trans_mas_cnt)));
1326 
1327  button = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON);
1328  gtk_widget_set_sensitive(button, sensitive);
1329 }
1330 
1331 static void
1332 gppat_populate_gas_list(GtkWidget *dialog,
1333  GNCAccountSel *gas,
1334  gboolean exclude_subaccounts)
1335 {
1336  Account *account;
1337  GList *filter;
1338 
1339  g_return_if_fail(GTK_IS_DIALOG(dialog));
1340  if (gas == NULL)
1341  return;
1342  account = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT);
1343  filter = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER);
1344 
1345  /* Setting the account type filter triggers GNCAccountSel population. */
1346  gnc_account_sel_set_acct_filters (gas, filter, NULL);
1347 
1348  /* Accounts to be deleted must be removed. */
1349  gnc_account_sel_purge_account( gas, account, exclude_subaccounts);
1350 
1351  /* The sensitivity of the OK button needs to be reevaluated. */
1352  set_ok_sensitivity(dialog);
1353 }
1354 
1355 void
1356 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb,
1357  GtkWidget *dialog)
1358 {
1359  GtkWidget *trans_mas;
1360 
1361  g_return_if_fail(GTK_IS_DIALOG(dialog));
1362 
1363  /* Cannot move transactions to subaccounts if they are to be deleted. */
1364  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1365  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb));
1366 }
1367 
1368 /* Note that the emitting object (the toggle button) and the signal data
1369  * are swapped in below callback function. This is a gtkbuilder feature:
1370  * it swaps if you explicitly set an object for a signal handler in the
1371  * gtkbuilder xml file.
1372  */
1373 void
1374 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b)
1375 {
1376  GtkWidget *dialog = gtk_widget_get_toplevel(widget);
1377  GtkWidget *subaccount_trans = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS);
1378  GtkWidget *sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
1379  gboolean have_splits = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS));
1380 
1381  gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b));
1382 
1383  // If we have subaccount splits & delete subaccounts, enable subaccount_trans
1384  if ((have_splits) && !gtk_widget_is_sensitive(sa_mas))
1385  gtk_widget_set_sensitive(subaccount_trans, TRUE);
1386  else
1387  gtk_widget_set_sensitive(subaccount_trans, FALSE);
1388 
1389  set_ok_sensitivity(dialog);
1390 }
1391 
1392 static GtkWidget *
1393 gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
1394  const gchar *hbox, const gchar *sel_name)
1395 {
1396  GtkWidget *selector = gnc_account_sel_new();
1397  GtkWidget *box = GTK_WIDGET(gtk_builder_get_object (builder, hbox));
1398 
1399  gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
1400  gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(selector), TRUE);
1401  g_object_set_data(G_OBJECT(dialog), sel_name, selector);
1402 
1403  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(selector), TRUE);
1404  gtk_widget_show_all(box);
1405 
1406  return selector;
1407 }
1408 
1409 static int
1410 commodity_mismatch_dialog (const Account* account, GtkWindow* parent)
1411 {
1412  int response;
1413  char *account_name = gnc_account_get_full_name (account);
1414  char* message = g_strdup_printf (
1415  _("Account %s does not have the same currency as the one you're "
1416  "moving transactions from.\nAre you sure you want to do this?"),
1417  account_name);
1418  GtkWidget* error_dialog =
1419  gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
1420  GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
1421  "%s", message);
1422  gtk_dialog_add_buttons (GTK_DIALOG(error_dialog),
1423  _("_Pick another account"), GTK_RESPONSE_CANCEL,
1424  _("_Do it anyway"), GTK_RESPONSE_ACCEPT,
1425  (gchar *)NULL);
1426  response = gtk_dialog_run (GTK_DIALOG (error_dialog));
1427  gtk_widget_destroy (error_dialog);
1428  g_free (message);
1429  return response;
1430 }
1431 
1432 typedef struct
1433 {
1434  Account *new_account;
1435  Account *old_account;
1436  GNCAccountSel *selector;
1437  gboolean match;
1438  gboolean for_account;
1439 } Adopter;
1440 
1441 static void
1442 adopter_set_account_and_match (Adopter* adopter)
1443 {
1444  if (!(adopter->selector &&
1445  gtk_widget_is_sensitive (GTK_WIDGET (adopter->selector))))
1446  return;
1447  adopter->new_account = gnc_account_sel_get_account(adopter->selector);
1448 /* We care about the commodity only if we're moving transactions. */
1449  if (!adopter->for_account && adopter->old_account && adopter->new_account)
1450  adopter->match =
1451  xaccAccountGetCommodity (adopter->new_account) ==
1452  xaccAccountGetCommodity (adopter->old_account);
1453 }
1454 
1455 static void
1456 adopter_init (Adopter* adopter, GtkWidget *selector, Account* account,
1457  gboolean for_account)
1458 {
1459  adopter->selector = GNC_ACCOUNT_SEL (selector);
1460  adopter->new_account = NULL;
1461  adopter->old_account = account;
1462  adopter->match = TRUE;
1463  adopter->for_account = for_account;
1464 }
1465 
1466 static gboolean
1467 adopter_match (Adopter* adopter, GtkWindow *parent)
1468 {
1469  int result;
1470  if (adopter->match || adopter->for_account)
1471  return TRUE;
1472  result = commodity_mismatch_dialog (adopter->new_account, parent);
1473  return (result == GTK_RESPONSE_ACCEPT);
1474 }
1475 
1476 typedef struct
1477 {
1478  Adopter trans;
1479  Adopter subacct;
1480  Adopter subtrans;
1481  delete_helper_t delete_res;
1482 } Adopters;
1483 
1484 static Account*
1485 account_subaccount (Account* account)
1486 {
1487  Account* subaccount = NULL;
1488  GList *subs = gnc_account_get_children (account);
1489  if (!gnc_list_length_cmp (subs, 1))
1490  subaccount = subs->data;
1491  g_list_free (subs);
1492  return subaccount;
1493 }
1494 
1495 static GtkWidget*
1496 account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
1497 {
1498  GtkWidget *dialog = NULL;
1499  GtkWidget *widget = NULL;
1500  gchar *title = NULL;
1501  GtkBuilder *builder = gtk_builder_new();
1502  gchar *acct_name = gnc_account_get_full_name(account);
1503  GList* splits = xaccAccountGetSplitList(account);
1504  GList* filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
1505 
1506  if (!acct_name)
1507  acct_name = g_strdup (_("(no name)"));
1508 
1509  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_delete_dialog");
1510 
1511  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_delete_dialog"));
1512  gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
1513 
1514  /* FIXME: Same account type used for subaccount. */
1515  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter);
1516  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account);
1517  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header"));
1518  title = g_strdup_printf(_("Deleting account %s"), acct_name);
1519  gtk_label_set_text(GTK_LABEL(widget), title);
1520  g_free(title);
1521  g_free(acct_name);
1522 
1523  widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON));
1524  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget);
1525 
1526  // Add the account selectors and enable sections as appropriate
1527  // setup transactions selector
1528  adopter_init (&adopt->trans,
1529  gppat_setup_account_selector (builder, dialog,
1530  "trans_mas_hbox",
1531  DELETE_DIALOG_TRANS_MAS),
1532  account, FALSE);
1533 
1534  // Does the selected account have splits
1535  if (splits)
1536  {
1537  delete_helper_t delete_res2 = { FALSE, FALSE };
1538 
1539  delete_account_helper(account, &delete_res2);
1540  if (delete_res2.has_ro_splits)
1541  {
1542  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw")));
1543  widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb"));
1544  gtk_widget_set_sensitive(widget, FALSE);
1545  }
1546  else
1547  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1548  }
1549  else
1550  {
1551  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "transactions")), FALSE);
1552  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1553  }
1554 
1555  // setup subaccount account selector
1556  adopter_init (&adopt->subacct,
1557  gppat_setup_account_selector (builder, dialog,
1558  "sa_mas_hbox",
1559  DELETE_DIALOG_SA_MAS),
1560  account, TRUE);
1561 
1562  // setup subaccount transaction selector
1563  adopter_init (&adopt->subtrans,
1564  gppat_setup_account_selector (builder, dialog,
1565  "sa_trans_mas_hbox",
1566  DELETE_DIALOG_SA_TRANS_MAS),
1567  account_subaccount (account), FALSE);
1568  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS,
1569  GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1570 
1571  if (gnc_account_n_children(account) > 0)
1572  {
1573  // Check for RO txns in descendants
1574  gnc_account_foreach_descendant_until(account, delete_account_helper,
1575  &adopt->delete_res);
1576  if (adopt->delete_res.has_splits)
1577  {
1578  if (adopt->delete_res.has_ro_splits)
1579  {
1580  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw")));
1581  widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb"));
1582  gtk_widget_set_sensitive(widget, FALSE);
1583  }
1584  else
1585  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1586 
1587  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(1));
1588  }
1589  else
1590  {
1591  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(0));
1592  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1593  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1594  }
1595  }
1596  else
1597  {
1598  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts")), FALSE);
1599  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1600  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1601  }
1602 
1603  /* default to cancel */
1604  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1605 
1606  gtk_builder_connect_signals(builder, dialog);
1607  g_object_unref(G_OBJECT(builder));
1608 
1609  return dialog;
1610 }
1611 
1612 static void
1613 gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page)
1614 {
1616  gchar *acct_name;
1617  GtkWidget *window;
1618  Adopters adopt;
1619  GList* list;
1620  gint response;
1621  GList *filter = NULL;
1622  GtkWidget *dialog = NULL;
1623 
1624  if (account == NULL)
1625  return;
1626 
1627  memset (&adopt, 0, sizeof (adopt));
1628  /* If the account has objects referring to it, show the list - the account can't be deleted until these
1629  references are dealt with. */
1630  list = qof_instance_get_referring_object_list(QOF_INSTANCE(account));
1631  if (list != NULL)
1632  {
1633 #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")
1634 
1635  gnc_ui_object_references_show(EXPLANATION, list);
1636  g_list_free(list);
1637  return;
1638  }
1639 
1640  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1641  acct_name = gnc_account_get_full_name(account);
1642  if (!acct_name)
1643  acct_name = g_strdup (_("(no name)"));
1644 
1645  if (gnc_account_n_children(account) > 1) {
1646  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);
1647  gnc_error_dialog(GTK_WINDOW(window),"%s", message);
1648  g_free (message);
1649  g_free(acct_name);
1650  return;
1651  }
1652 
1653  // If no transaction or children just delete it.
1654  if (!(xaccAccountGetSplitList (account) != NULL ||
1655  gnc_account_n_children (account)))
1656  {
1657  do_delete_account (account, NULL, NULL, NULL);
1658  return;
1659  }
1660 
1661  dialog = account_delete_dialog (account, GTK_WINDOW (window), &adopt);
1662 
1663  while (TRUE)
1664  {
1665  response = gtk_dialog_run(GTK_DIALOG(dialog));
1666 
1667  if (response != GTK_RESPONSE_ACCEPT)
1668  {
1669  /* Account deletion is cancelled, so clean up and return. */
1670  filter = g_object_get_data (G_OBJECT (dialog),
1671  DELETE_DIALOG_FILTER);
1672  gtk_widget_destroy(dialog);
1673  g_list_free(filter);
1674  return;
1675  }
1676  adopter_set_account_and_match (&adopt.trans);
1677  adopter_set_account_and_match (&adopt.subacct);
1678  adopter_set_account_and_match (&adopt.subtrans);
1679 
1680  if (adopter_match (&adopt.trans, GTK_WINDOW (window)) &&
1681  adopter_match (&adopt.subacct, GTK_WINDOW (window)) &&
1682  adopter_match (&adopt.subtrans, GTK_WINDOW (window)))
1683  break;
1684  }
1685  filter = g_object_get_data (G_OBJECT (dialog), DELETE_DIALOG_FILTER);
1686  gtk_widget_destroy(dialog);
1687  g_list_free(filter);
1688  if (confirm_delete_account (action, page, adopt.trans.new_account,
1689  adopt.subtrans.new_account,
1690  adopt.subacct.new_account,
1691  adopt.delete_res) == GTK_RESPONSE_ACCEPT)
1692  {
1693  do_delete_account (account, adopt.subacct.new_account,
1694  adopt.subtrans.new_account, adopt.trans.new_account);
1695  }
1696 }
1697 
1698 static int
1699 confirm_delete_account (GtkAction *action, GncPluginPageAccountTree *page,
1700  Account* ta, Account* sta, Account* saa,
1701  delete_helper_t delete_res)
1702 {
1704  GList* splits = xaccAccountGetSplitList(account);
1705  GtkWidget* window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1706  gint response;
1707 
1708  char *lines[6] = {0};
1709  char *message;
1710  int i = 0;
1711  GtkWidget *dialog;
1712  gchar* acct_name = gnc_account_get_full_name(account);
1713 
1714  lines[i] = g_strdup_printf (_("The account %s will be deleted."),
1715  acct_name);
1716  g_free(acct_name);
1717 
1718  if (splits)
1719  {
1720  if (ta)
1721  {
1722  char *name = gnc_account_get_full_name(ta);
1723  lines[++i] = g_strdup_printf (_("All transactions in this account "
1724  "will be moved to the account %s."),
1725  name);
1726  g_free (name);
1727  }
1728  else
1729  {
1730  lines[++i] = g_strdup_printf (_("All transactions in this account "
1731  "will be deleted."));
1732  }
1733  }
1734  if (gnc_account_n_children(account))
1735  {
1736  if (saa)
1737  {
1738  char *name = gnc_account_get_full_name(saa);
1739  lines[++i] = g_strdup_printf (_("Its sub-account will be "
1740  "moved to the account %s."), name);
1741  g_free (name);
1742  }
1743  else
1744  {
1745  lines[++i] = g_strdup_printf (_("Its subaccount will be deleted."));
1746  if (sta)
1747  {
1748  char *name = gnc_account_get_full_name(sta);
1749  lines[++i] = g_strdup_printf (_("All sub-account transactions "
1750  "will be moved to the "
1751  "account %s."), name);
1752  g_free (name);
1753  }
1754  else if (delete_res.has_splits)
1755  {
1756  lines[++i] = g_strdup_printf(_("All sub-account transactions "
1757  "will be deleted."));
1758  }
1759  }
1760  }
1761 
1762  lines[++i] = _("Are you sure you want to do this?");
1763 
1764  message = g_strjoinv(" ", lines);
1765  for (int j = 0; j < i; ++j) // Don't try to free the last one, it's const.
1766  g_free (lines[j]);
1767 
1768  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
1769  GTK_DIALOG_DESTROY_WITH_PARENT,
1770  GTK_MESSAGE_QUESTION,
1771  GTK_BUTTONS_NONE,
1772  "%s", message);
1773  g_free(message);
1774  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
1775  _("_Cancel"), GTK_RESPONSE_CANCEL,
1776  _("_Delete"), GTK_RESPONSE_ACCEPT,
1777  (gchar *)NULL);
1778  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1779  response = gtk_dialog_run(GTK_DIALOG(dialog));
1780  gtk_widget_destroy(dialog);
1781  return response;
1782 }
1783 
1784 void do_delete_account (Account* account, Account* saa, Account* sta, Account* ta)
1785 {
1786  GList *acct_list, *ptr;
1787  const GncGUID *guid;
1788  gchar guidstr[GUID_ENCODING_LENGTH+1];
1789 
1790  gnc_set_busy_cursor(NULL, TRUE);
1791  gnc_suspend_gui_refresh ();
1792 
1793  /* Move subaccounts and transactions if this was requested */
1794  xaccAccountBeginEdit (account);
1795  if (saa)
1796  {
1797  xaccAccountBeginEdit (saa);
1798  acct_list = gnc_account_get_children(account);
1799  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1800  gnc_account_append_child (saa, ptr->data);
1801  g_list_free(acct_list);
1802  xaccAccountCommitEdit (saa);
1803  }
1804  else if (sta)
1805  {
1806  /* Move the splits of its subaccounts, if any. */
1808  (AccountCb)xaccAccountMoveAllSplits,
1809  sta);
1810  }
1811  if (ta)
1812  {
1813  /* Move the splits of the account to be deleted. */
1814  xaccAccountMoveAllSplits (account, ta);
1815  }
1816  xaccAccountCommitEdit (account);
1817 
1818  /* Drop all references from the state file for
1819  * any subaccount the account still has
1820  */
1821  acct_list = gnc_account_get_children(account);
1822  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1823  {
1824  guid = xaccAccountGetGUID (ptr->data);
1825  guid_to_string_buff (guid, guidstr);
1826  gnc_state_drop_sections_for (guidstr);
1827  }
1828  g_list_free(acct_list);
1829 
1830  /* Drop all references from the state file for this account
1831  */
1832  guid = xaccAccountGetGUID (account);
1833  guid_to_string_buff (guid, guidstr);
1834  gnc_state_drop_sections_for (guidstr);
1835 
1836  /*
1837  * Finally, delete the account, any subaccounts it may still
1838  * have, and any splits it or its subaccounts may still have.
1839  */
1840  xaccAccountBeginEdit (account);
1841  xaccAccountDestroy (account);
1842  gnc_resume_gui_refresh ();
1843  gnc_unset_busy_cursor(NULL);
1844 }
1845 
1846 static void
1847 gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action,
1849 {
1850  Account *account;
1851  GtkWidget *window;
1852 
1853  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1855  if (!window || !account)
1856  return;
1857 
1858  gnc_account_renumber_create_dialog(window, account);
1859 }
1860 
1861 static void
1862 gnc_plugin_page_account_tree_cmd_refresh (GtkAction *action,
1864 {
1866 
1867  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1868 
1869  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1870 
1871  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
1872  gtk_widget_queue_draw (priv->widget);
1873 }
1874 
1875 /*********************/
1876 
1877 static void
1878 gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action,
1880 {
1882 
1883  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1884  ENTER("(action %p, page %p)", action, page);
1885 
1886  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1887  account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page));
1888  LEAVE(" ");
1889 }
1890 
1891 static void
1892 gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action,
1894 {
1895  GtkWidget *window;
1896  Account *account;
1897  RecnWindow *recnData;
1898 
1900  g_return_if_fail (account != NULL);
1901 
1902  window = GNC_PLUGIN_PAGE (page)->window;
1903  recnData = recnWindow (window, account);
1904  gnc_ui_reconcile_window_raise (recnData);
1905 }
1906 
1907 static void
1908 gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action,
1910 {
1911  GtkWidget *window;
1912  Account *account;
1913  AutoClearWindow *autoClearData;
1914 
1916  g_return_if_fail (account != NULL);
1917 
1918  window = GNC_PLUGIN_PAGE (page)->window;
1919  autoClearData = autoClearWindow (window, account);
1920  gnc_ui_autoclear_window_raise (autoClearData);
1921 }
1922 
1923 static void
1924 gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action,
1926 {
1927  GtkWidget *window;
1928  Account *account;
1929 
1931  window = GNC_PLUGIN_PAGE (page)->window;
1932  gnc_xfer_dialog (window, account);
1933 }
1934 
1935 static void
1936 gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action,
1938 {
1939  GtkWidget *window;
1940  Account *account;
1941 
1943  window = GNC_PLUGIN_PAGE (page)->window;
1944  gnc_stock_split_dialog (window, account);
1945 }
1946 
1947 static void
1948 gnc_plugin_page_account_tree_cmd_edit_tax_options (GtkAction *action,
1950 {
1951  GtkWidget *window;
1952  Account *account;
1953 
1955  window = GNC_PLUGIN_PAGE (page)->window;
1956  gnc_tax_info_dialog (window, account);
1957 }
1958 
1959 static void
1960 gnc_plugin_page_account_tree_cmd_lots (GtkAction *action,
1962 {
1964  GtkWidget *window = GNC_PLUGIN_PAGE (page)->window;
1965  gnc_lot_viewer_dialog (GTK_WINDOW(window), account);
1966 }
1967 
1968 static gboolean scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
1969 {
1970  if (event->length == 0) return FALSE;
1971 
1972  switch (event->keyval)
1973  {
1974  case GDK_KEY_Escape:
1975  {
1976  gboolean abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), FALSE,
1977  _("'Check & Repair' is currently running, do you want to abort it?"));
1978 
1979  if (abort_scrub)
1980  gnc_set_abort_scrub (TRUE);
1981 
1982  return TRUE;
1983  }
1984  default:
1985  break;
1986  }
1987  return FALSE;
1988 }
1989 
1990 static void
1991 gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page)
1992 {
1994  GncWindow *window;
1995  gulong scrub_kp_handler_ID;
1996 
1997  g_return_if_fail (account != NULL);
1998 
1999  prepare_scrubbing ();
2000 
2001  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2002  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2003  G_CALLBACK(scrub_kp_handler), NULL);
2004  gnc_window_set_progressbar_window (window);
2005 
2006  xaccAccountScrubOrphans (account, gnc_window_show_progress);
2007  xaccAccountScrubImbalance (account, gnc_window_show_progress);
2008 
2009  // XXX: Lots/capital gains scrubbing is disabled
2010  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2011  xaccAccountScrubLots(account);
2012 
2013  gncScrubBusinessAccount(account, gnc_window_show_progress);
2014 
2015  finish_scrubbing (window, scrub_kp_handler_ID);
2016 }
2017 
2018 static void
2019 gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page)
2020 {
2022  GncWindow *window;
2023  gulong scrub_kp_handler_ID;
2024 
2025  g_return_if_fail (account != NULL);
2026 
2027  prepare_scrubbing ();
2028 
2029  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2030  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2031  G_CALLBACK(scrub_kp_handler), NULL);
2032  gnc_window_set_progressbar_window (window);
2033 
2034  xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
2035  xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
2036 
2037  // XXX: Lots/capital gains scrubbing is disabled
2038  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2039  xaccAccountTreeScrubLots(account);
2040 
2041  gncScrubBusinessAccountTree(account, gnc_window_show_progress);
2042 
2043  finish_scrubbing (window, scrub_kp_handler_ID);
2044 }
2045 
2046 static void
2047 gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page)
2048 {
2049  Account *root = gnc_get_current_root_account ();
2050  GncWindow *window;
2051  gulong scrub_kp_handler_ID;
2052 
2053  prepare_scrubbing ();
2054 
2055  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2056  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2057  G_CALLBACK(scrub_kp_handler), NULL);
2058  gnc_window_set_progressbar_window (window);
2059 
2060  xaccAccountTreeScrubOrphans (root, gnc_window_show_progress);
2061  xaccAccountTreeScrubImbalance (root, gnc_window_show_progress);
2062  // XXX: Lots/capital gains scrubbing is disabled
2063  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2064  xaccAccountTreeScrubLots(root);
2065 
2066  gncScrubBusinessAccountTree(root, gnc_window_show_progress);
2067 
2068  finish_scrubbing (window, scrub_kp_handler_ID);
2069 }
2070 
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2899
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_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:2801
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.
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:4007
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...
void gnc_account_foreach_descendant(const Account *acc, AccountCb 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:3245
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 gnc_get_ongoing_scrub(void)
The gnc_get_ongoing_scrub () method returns TRUE if a scrub operation is ongoing. ...
Definition: Scrub.c:84
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3279
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...
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
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Definition: Transaction.c:2596
Functions that are supported by all types of windows.
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:3253
A structure for defining alternate action names for use in the toolbar.
Definition: gnc-plugin.h:228
GncPluginPage * gnc_plugin_page_register2_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
GtkWidget * window
The window that contains the display widget for this plugin.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
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:174
void xaccAccountScrubLots(Account *acc)
The xaccAccountScrubLots() routine makes sure that every split in the account is assigned to a lot...
Definition: Scrub3.c:159
void xaccAccountMoveAllSplits(Account *accfrom, Account *accto)
The xaccAccountMoveAllSplits() routine reassigns each of the splits in accfrom to accto...
Definition: Account.cpp:2203
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 ...
GtkActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GtkActionGroup object associated with this page.
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:1569
#define xaccAccountGetGUID(X)
Definition: Account.h:248
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.c:72
convert single-entry accounts to clean double-entry
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:3308
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.
void xaccAccountTreeScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its childr...
Definition: Scrub.c:92
#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.
void gnc_plugin_init_short_names(GtkActionGroup *action_group, action_toolbar_labels *toolbar_labels)
Add "short" labels to existing actions.
Definition: gnc-plugin.c:234
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.c:140
Gnome specific utility functions.
gint gnc_account_n_children(const Account *account)
Return the number of children of the specified account.
Definition: Account.cpp:2952
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.
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:582
void gnc_plugin_update_actions(GtkActionGroup *action_group, const gchar **action_names, const gchar *property_name, gboolean value)
Update a property on a set of existing GtkActions.
Definition: gnc-plugin.c:280
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2930
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1449
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4262
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.
GtkActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GtkActionGroup object associated with this page.
void gncScrubBusinessAccountTree(Account *acc, QofPercentageFunc percentagefunc)
The gncScrubBusinessAccountTreeLots() function will call gncScrubBusinessAccount() on the given accou...
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:1490
GtkAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *name)
Find action in main window.
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