GnuCash  4.11-11-ge9df8d41d2+
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*)g_type_instance_get_private((GTypeInstance*)o, GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE))
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_account_always[] =
373 {
374  "FileOpenAccountAction",
375 #ifdef REGISTER2_ENABLED
376  "FileOpenAccount2Action",
377 #endif
378  "FileOpenSubaccountsAction",
379  "ActionsLotsAction",
380  NULL
381 };
382 
383 /* This is the list of actions which are switched inactive in a read-only book. */
384 static const gchar* readonly_inactive_actions[] =
385 {
386  "FileNewAccountAction",
387  "FileAddAccountHierarchyAssistantAction",
388  "EditEditAccountAction",
389  "EditDeleteAccountAction",
390  "EditRenumberSubaccountsAction",
391  "ActionsTransferAction",
392  "ActionsReconcileAction",
393  "ActionsAutoClearAction",
394  "ActionsStockSplitAction",
395  "ScrubAction",
396  "ScrubSubAction",
397  "ScrubAllAction",
398  NULL
399 };
400 
402 static action_toolbar_labels toolbar_labels[] =
403 {
404  { "FileOpenAccountAction", N_("Open") },
405 #ifdef REGISTER2_ENABLED
406  { "FileOpenAccount2Action", N_("Open2") },
407 #endif
408  { "EditEditAccountAction", N_("Edit") },
409  { "FileNewAccountAction", N_("New") },
410  { "EditDeleteAccountAction", N_("Delete") },
411  { NULL, NULL },
412 };
413 
416 {
417  GncPluginPageAccountTree *plugin_page;
418 
419  ENTER(" ");
420  plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE,
421  NULL);
422 
423  LEAVE("new account tree page %p", plugin_page);
424  return GNC_PLUGIN_PAGE (plugin_page);
425 }
426 
427 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageAccountTree, gnc_plugin_page_account_tree, GNC_TYPE_PLUGIN_PAGE)
428 
429 static gboolean show_abort_verify = TRUE;
430 
431 static void
432 prepare_scrubbing ()
433 {
434  gnc_suspend_gui_refresh ();
435  gnc_set_abort_scrub (FALSE);
436 }
437 
438 static void
439 finish_scrubbing (GncWindow *window, gulong handler_id)
440 {
441  g_signal_handler_disconnect (G_OBJECT(window), handler_id);
442  show_abort_verify = TRUE;
443  gnc_resume_gui_refresh ();
444 }
445 
446 static gboolean
447 gnc_plugin_page_account_finish_pending (GncPluginPage* page)
448 {
449  if (gnc_get_ongoing_scrub ())
450  {
451  if (show_abort_verify)
452  {
453  gboolean ret = gnc_verify_dialog (GTK_WINDOW(gnc_plugin_page_get_window
454  (GNC_PLUGIN_PAGE(page))), FALSE,
455  _("'Check & Repair' is currently running, do you want to abort it?"));
456 
457  show_abort_verify = FALSE;
458 
459  if (ret)
460  gnc_set_abort_scrub (TRUE);
461 
462  return ret; // verify response
463  }
464  else
465  {
466  if (gnc_get_abort_scrub ())
467  return TRUE; // close
468  else
469  return FALSE; // no close
470  }
471  }
472  else
473  return TRUE; // normal close
474 }
475 
476 static void
477 gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
478 {
479  GObjectClass *object_class = G_OBJECT_CLASS (klass);
480  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
481 
482  parent_class = g_type_class_peek_parent (klass);
483 
484  object_class->finalize = gnc_plugin_page_account_tree_finalize;
485 
486  gnc_plugin_class->tab_icon = GNC_ICON_ACCOUNT;
487  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
488  gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget;
489  gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget;
490  gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
491  gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
492  gnc_plugin_class->focus_page_function = gnc_plugin_page_account_tree_focus_widget;
493  gnc_plugin_class->finish_pending = gnc_plugin_page_account_finish_pending;
494 
495  plugin_page_signals[ACCOUNT_SELECTED] =
496  g_signal_new ("account_selected",
497  G_OBJECT_CLASS_TYPE (object_class),
498  G_SIGNAL_RUN_FIRST,
499  G_STRUCT_OFFSET (GncPluginPageAccountTreeClass, account_selected),
500  NULL, NULL,
501  g_cclosure_marshal_VOID__POINTER,
502  G_TYPE_NONE, 1,
503  G_TYPE_POINTER);
504 }
505 
506 static void
507 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
508 {
509  GtkActionGroup *action_group;
511  GncPluginPage *parent;
512  const GList *page_list;
513 
514  ENTER("page %p", plugin_page);
515  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(plugin_page);
516 
517  /* Init parent declared variables */
518  parent = GNC_PLUGIN_PAGE(plugin_page);
519 #ifdef REGISTER2_ENABLED
520  g_object_set(G_OBJECT(plugin_page),
521  "page-name", _("Accounts"),
522  "page-uri", "default:",
523  "ui-description", "gnc-plugin-page-account-tree2-ui.xml",
524  NULL);
525 #else
526  g_object_set(G_OBJECT(plugin_page),
527  "page-name", _("Accounts"),
528  "page-uri", "default:",
529  "ui-description", "gnc-plugin-page-account-tree-ui.xml",
530  NULL);
531 #endif
532  g_signal_connect (G_OBJECT (plugin_page), "selected",
533  G_CALLBACK (gnc_plugin_page_account_tree_selected), plugin_page);
534 
535  /* change me when the system supports multiple books */
536  gnc_plugin_page_add_book(parent, gnc_get_current_book());
537 
538  /* Is this the first accounts page? */
539  page_list =
540  gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
541  if (!page_list || plugin_page == page_list->data)
542  {
543  g_object_set_data(G_OBJECT(plugin_page), PLUGIN_PAGE_IMMUTABLE,
544  GINT_TO_POINTER(1));
545  }
546 
547  /* Create menu and toolbar information */
548  action_group =
550  "GncPluginPageAccountTreeActions");
551  gtk_action_group_add_actions(action_group,
552  gnc_plugin_page_account_tree_actions,
553  gnc_plugin_page_account_tree_n_actions,
554  plugin_page);
555  gnc_plugin_init_short_names (action_group, toolbar_labels);
556 
557  /* Visible types */
558  priv->fd.visible_types = -1; /* Start with all types */
559  priv->fd.show_hidden = FALSE;
560  priv->fd.show_unused = TRUE;
561  priv->fd.show_zero_total = TRUE;
562  priv->fd.filter_override = g_hash_table_new (g_direct_hash, g_direct_equal);
563 
564  LEAVE("page %p, priv %p, action group %p",
565  plugin_page, priv, action_group);
566 }
567 
568 static void
569 gnc_plugin_page_account_tree_finalize (GObject *object)
570 {
573 
574  ENTER("object %p", object);
575  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (object);
576  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
577  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
578  g_return_if_fail (priv != NULL);
579 
580  G_OBJECT_CLASS (parent_class)->finalize (object);
581  LEAVE(" ");
582 }
583 
584 void
585 gnc_plugin_page_account_tree_open (Account *account, GtkWindow *win)
586 {
589  GncPluginPage *plugin_page = NULL;
590  const GList *page_list;
591  GtkWidget *window;
592 
593  /* Find Accounts page */
594  page_list = gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
595 
596  // If we have a window, look for account page in that window
597  if (gnc_list_length_cmp (page_list, 0))
598  {
599  if (win != NULL)
600  {
601  for ( ; page_list; page_list = g_list_next(page_list))
602  {
603  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
604  if (GTK_WINDOW(plugin_page->window) == win)
605  break;
606  }
607  }
608  else // if no window, open first account page in list
609  plugin_page = GNC_PLUGIN_PAGE(page_list->data);
610  }
611  else // we have no account pages, create one
612  plugin_page = gnc_plugin_page_account_tree_new ();
613 
614  g_return_if_fail(plugin_page);
615  window = plugin_page->window;
616 
617  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), plugin_page);
618 
619  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
620  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
621 
622  if (account != NULL)
623  {
624  Account *root_account = gnc_get_current_root_account ();
625  Account *parent_account = NULL;
626  Account *temp_account = account;
627 
628  g_hash_table_insert (priv->fd.filter_override, account, account);
629 
630  // make sure we override all the parent accounts to root
631  while (parent_account != root_account)
632  {
633  parent_account = gnc_account_get_parent (temp_account);
634 
635  g_hash_table_insert (priv->fd.filter_override, parent_account, parent_account);
636  temp_account = parent_account;
637  }
638  gnc_tree_view_account_refilter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
639  gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), account);
640  }
641 }
642 
643 Account *
645 {
647  Account *account;
648 
649  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
650  ENTER("page %p (tree view %p)", page, priv->tree_view);
651  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
652  if (account == NULL)
653  {
654  LEAVE("no account");
655  return NULL;
656  }
657 
658  LEAVE("account %p", account);
659  return account;
660 }
661 
666 static gboolean
667 gnc_plugin_page_account_tree_focus_widget (GncPluginPage *account_plugin_page)
668 {
669  if (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(account_plugin_page))
670  {
671  GncPluginPageAccountTreePrivate *priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_plugin_page);
672  GtkTreeView *view = GTK_TREE_VIEW(priv->tree_view);
673 
674  if (!gtk_widget_is_focus (GTK_WIDGET(view)))
675  gtk_widget_grab_focus (GTK_WIDGET(view));
676  }
677  return FALSE;
678 }
679 
680 /* Virtual Functions */
681 
682 static void
683 gnc_plugin_page_account_refresh_cb (GHashTable *changes, gpointer user_data)
684 {
685  GncPluginPageAccountTree *page = user_data;
687 
688  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
689 
690  /* We're only looking for forced updates here. */
691  if (changes)
692  return;
693 
694  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
695 
696  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
697  gtk_widget_queue_draw(priv->widget);
698 }
699 
700 static void
701 gnc_plugin_page_account_tree_close_cb (gpointer user_data)
702 {
703  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
704  gnc_main_window_close_page(plugin_page);
705 }
706 
707 static void
708 gnc_plugin_page_account_editing_started_cd (gpointer various, GncPluginPageRegister *page)
709 {
710  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
711  GtkAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window),
712  "EditDeleteAccountAction");
713 
714  if (action != NULL)
715  gtk_action_set_sensitive (action, FALSE);
716 }
717 
718 static void
719 gnc_plugin_page_account_editing_finished_cb (gpointer various, GncPluginPageRegister *page)
720 {
721  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(page);
722  GtkAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(plugin_page->window),
723  "EditDeleteAccountAction");
724 
725  if (action != NULL)
726  gtk_action_set_sensitive (action, TRUE);
727 }
728 
729 static GtkWidget *
730 gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page)
731 {
734  GtkTreeSelection *selection;
735  GtkTreeView *tree_view;
736  GtkWidget *scrolled_window;
737  GtkTreeViewColumn *col;
738 
739  ENTER("page %p", plugin_page);
740  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
741  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
742  if (priv->widget != NULL)
743  {
744  LEAVE("widget = %p", priv->widget);
745  return priv->widget;
746  }
747 
748  priv->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
749  gtk_box_set_homogeneous (GTK_BOX (priv->widget), FALSE);
750  gtk_widget_show (priv->widget);
751 
752  // Set the name for this widget so it can be easily manipulated with css
753  gtk_widget_set_name (GTK_WIDGET(priv->widget), "gnc-id-account-page");
754 
755  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
756  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
757  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
758  gtk_widget_show (scrolled_window);
759  gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window,
760  TRUE, TRUE, 0);
761 
762  tree_view = gnc_tree_view_account_new(FALSE);
764  GNC_TREE_VIEW(tree_view), "description");
765  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
767  GNC_TREE_VIEW(tree_view), "total");
768  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
769  gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view));
770  g_object_set(G_OBJECT(tree_view),
771  "state-section", STATE_SECTION,
772  "show-column-menu", TRUE,
773  NULL);
774 
775  /* No name handler; then the user can't click on the name of the
776  account to open its register. */
777  gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
778  gnc_tree_view_account_code_edited_cb);
779  gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
780  gnc_tree_view_account_description_edited_cb);
781  gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
782  gnc_tree_view_account_notes_edited_cb);
783 
784  // Setup some callbacks so menu actions can be disabled/enabled
785  gnc_tree_view_account_set_editing_started_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
786  (GFunc)gnc_plugin_page_account_editing_started_cd, page);
787  gnc_tree_view_account_set_editing_finished_cb(GNC_TREE_VIEW_ACCOUNT(tree_view),
788  (GFunc)gnc_plugin_page_account_editing_finished_cb, page);
789 
790  priv->tree_view = tree_view;
791  selection = gtk_tree_view_get_selection(tree_view);
792  g_signal_connect (G_OBJECT (selection), "changed",
793  G_CALLBACK (gnc_plugin_page_account_tree_selection_changed_cb), page);
794  g_signal_connect (G_OBJECT (tree_view), "button-press-event",
795  G_CALLBACK (gnc_plugin_page_account_tree_button_press_cb), page);
796  g_signal_connect (G_OBJECT (tree_view), "row-activated",
797  G_CALLBACK (gnc_plugin_page_account_tree_double_click_cb), page);
798 
799  gtk_tree_view_set_headers_visible(tree_view, TRUE);
800  gnc_plugin_page_account_tree_selection_changed_cb (NULL, page);
801  gtk_widget_show (GTK_WIDGET (tree_view));
802  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(tree_view));
803 
804  priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view);
806  GNC_TREE_VIEW_ACCOUNT(tree_view),
808 
809  priv->component_id =
810  gnc_register_gui_component(PLUGIN_PAGE_ACCT_TREE_CM_CLASS,
811  gnc_plugin_page_account_refresh_cb,
812  gnc_plugin_page_account_tree_close_cb,
813  page);
814  gnc_gui_component_set_session (priv->component_id,
815  gnc_get_current_session());
816 
817  plugin_page->summarybar = gnc_main_window_summary_new();
818  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
819  FALSE, FALSE, 0);
820  gtk_widget_show(plugin_page->summarybar);
821  gnc_plugin_page_account_tree_summarybar_position_changed(NULL, NULL, page);
822  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
823  GNC_PREF_SUMMARYBAR_POSITION_TOP,
824  gnc_plugin_page_account_tree_summarybar_position_changed,
825  page);
826  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
827  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
828  gnc_plugin_page_account_tree_summarybar_position_changed,
829  page);
830 
831  g_signal_connect (G_OBJECT(plugin_page), "inserted",
832  G_CALLBACK(gnc_plugin_page_inserted_cb),
833  NULL);
834 
835  // Read account filter state information from account section
836  gnc_tree_view_account_restore_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
837  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
838 
839  LEAVE("widget = %p", priv->widget);
840  return priv->widget;
841 }
842 
843 static void
844 gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page)
845 {
848 
849  ENTER("page %p", plugin_page);
850  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
851  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
852 
853  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
854  GNC_PREF_SUMMARYBAR_POSITION_TOP,
855  gnc_plugin_page_account_tree_summarybar_position_changed,
856  page);
857  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
858  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
859  gnc_plugin_page_account_tree_summarybar_position_changed,
860  page);
861 
862  // Save account filter state information to account section
863  gnc_tree_view_account_save_filter (GNC_TREE_VIEW_ACCOUNT(priv->tree_view), &priv->fd,
864  gnc_state_get_current(), gnc_tree_view_get_state_section (GNC_TREE_VIEW(priv->tree_view)));
865 
866  // Destroy the filter override hash table
867  g_hash_table_destroy(priv->fd.filter_override);
868 
869  // Remove the page_changed signal callback
870  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
871 
872  // Remove the page focus idle function if present
873  g_idle_remove_by_data (plugin_page);
874 
875  if (priv->widget)
876  {
877  g_object_unref(G_OBJECT(priv->widget));
878  priv->widget = NULL;
879  }
880 
881  if (priv->component_id)
882  {
883  gnc_unregister_gui_component(priv->component_id);
884  priv->component_id = 0;
885  }
886 
887  LEAVE("widget destroyed");
888 }
889 
890 static void update_inactive_actions(GncPluginPage *plugin_page)
891 {
892  GtkActionGroup *action_group;
893  gboolean is_sensitive = !qof_book_is_readonly(gnc_get_current_book());
894 
895  // We are readonly - so we have to switch particular actions to inactive.
896  g_return_if_fail(plugin_page);
897  g_return_if_fail(GNC_IS_PLUGIN_PAGE(plugin_page));
898 
899  /* Get the action group */
900  action_group = gnc_plugin_page_get_action_group(plugin_page);
901  g_return_if_fail(GTK_IS_ACTION_GROUP (action_group));
902 
903  /* Set the action's sensitivity */
904  gnc_plugin_update_actions (action_group, readonly_inactive_actions,
905  "sensitive", is_sensitive);
906 }
907 
912 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data)
913 {
914  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object);
915  g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page));
916  update_inactive_actions(plugin_page);
917 }
918 
928 static void
929 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
930  GKeyFile *key_file,
931  const gchar *group_name)
932 {
933  GncPluginPageAccountTree *account_page;
935 
936  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
937  g_return_if_fail (key_file != NULL);
938  g_return_if_fail (group_name != NULL);
939 
940  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
941  group_name);
942 
943  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
944  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
945 
946  gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
947  &priv->fd, key_file, group_name);
948  LEAVE(" ");
949 }
950 
951 
952 
962 static GncPluginPage *
963 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
964  GKeyFile *key_file,
965  const gchar *group_name)
966 {
967  GncPluginPageAccountTree *account_page;
969  GncPluginPage *page;
970 
971  g_return_val_if_fail(key_file, NULL);
972  g_return_val_if_fail(group_name, NULL);
973  ENTER("key_file %p, group_name %s", key_file, group_name);
974 
975  /* Create the new page. */
977  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
978  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
979 
980  /* Install it now so we can then manipulate the created widget */
981  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
982 
983  gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
984  &priv->fd, key_file, group_name);
985  LEAVE(" ");
986  return page;
987 }
988 
989 
990 /* Callbacks */
991 
992 static void
993 gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data)
994 {
995  GncPluginPage *plugin_page;
998  GtkPositionType position = GTK_POS_BOTTOM;
999 
1000  g_return_if_fail(user_data != NULL);
1001 
1002  plugin_page = GNC_PLUGIN_PAGE(user_data);
1003  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data);
1004  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1005 
1006  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SUMMARYBAR_POSITION_TOP))
1007  position = GTK_POS_TOP;
1008 
1009  gtk_box_reorder_child(GTK_BOX(priv->widget),
1010  plugin_page->summarybar,
1011  (position == GTK_POS_TOP ? 0 : -1) );
1012 }
1013 
1021 static gboolean
1022 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
1023  GdkEventButton *event,
1024  GncPluginPage *page)
1025 {
1026 
1027  g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
1028 
1029  ENTER("widget %p, event %p, page %p", widget, event, page);
1030  gnc_main_window_button_press_cb(widget, event, page);
1031  LEAVE(" ");
1032 
1033  /* Always return FALSE. This will let the tree view callback run as
1034  * well which will select the item under the cursor. By the time
1035  * the user sees the menu both callbacks will have run and the menu
1036  * actions will operate on the just-selected account. */
1037  return FALSE;
1038 }
1039 
1040 static void
1041 gppat_open_account_common (GncPluginPageAccountTree *page,
1042  Account *account,
1043  gboolean include_subs)
1044 {
1045  GtkWidget *window;
1046  GncPluginPage *new_page;
1047 
1048  if (account == NULL)
1049  return;
1050 
1051  window = GNC_PLUGIN_PAGE (page)->window;
1052  new_page = gnc_plugin_page_register_new (account, include_subs);
1053  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
1054 }
1055 
1056 /*################## Added for Reg2 #################*/
1057 /* New Register Common */
1058 static void
1059 gppat_open2_account_common (GncPluginPageAccountTree *page,
1060  Account *account,
1061  gboolean include_subs)
1062 {
1063  GtkWidget *window;
1064  GncPluginPage *new_page;
1065 
1066  if (account == NULL)
1067  return;
1068 
1069  window = GNC_PLUGIN_PAGE (page)->window;
1070  new_page = gnc_plugin_page_register2_new (account, include_subs);
1071  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
1072 }
1073 /*################## Added for Reg2 #################*/
1074 
1075 static void
1076 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
1077  GtkTreePath *path,
1078  GtkTreeViewColumn *col,
1080 {
1081  GtkTreeModel *model;
1082  GtkTreeIter iter;
1083 
1084  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1085  g_return_if_fail (treeview);
1086 
1087  model = gtk_tree_view_get_model(treeview);
1088  if (gtk_tree_model_get_iter(model, &iter, path))
1089  {
1090  Account *account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path);
1091  if (xaccAccountGetPlaceholder (account))
1092  {
1093  /* This is a placeholder account. Only only show/hide
1094  * subaccount list if there is one.
1095  */
1096  if (gtk_tree_model_iter_has_child(model, &iter))
1097  {
1098  /* There are children,
1099  * just expand or collapse the row. */
1100  if (gtk_tree_view_row_expanded(treeview, path))
1101  gtk_tree_view_collapse_row(treeview, path);
1102  else
1103  gtk_tree_view_expand_row(treeview, path, FALSE);
1104  }
1105  }
1106  else
1107  {
1108  /* No placeholder account, so open its register */
1109 #ifdef REGISTER2_ENABLED
1110  gppat_open2_account_common (page, account, FALSE);
1111 #else
1112  gppat_open_account_common (page, account, FALSE);
1113 #endif
1114  }
1115  }
1116 }
1117 
1118 static void
1119 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
1121 {
1122  GtkActionGroup *action_group;
1123  GtkAction *action;
1124  GtkTreeView *view;
1125  Account *account = NULL;
1126  gboolean sensitive;
1127  gboolean subaccounts;
1128  gboolean is_readwrite = !qof_book_is_readonly(gnc_get_current_book());
1129 
1130  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1131 
1132  if (!selection)
1133  {
1134  sensitive = FALSE;
1135  subaccounts = FALSE;
1136  }
1137  else
1138  {
1139  g_return_if_fail(GTK_IS_TREE_SELECTION(selection));
1140  view = gtk_tree_selection_get_tree_view (selection);
1141  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(view));
1142  sensitive = (account != NULL);
1143 
1144  subaccounts = account && (gnc_account_n_children(account) != 0);
1145  /* Check here for placeholder accounts, etc. */
1146  }
1147 
1148  action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(page));
1149  gnc_plugin_update_actions (action_group, actions_requiring_account_rw,
1150  "sensitive", is_readwrite && sensitive);
1151  gnc_plugin_update_actions (action_group, actions_requiring_account_always,
1152  "sensitive", sensitive);
1153  g_signal_emit (page, plugin_page_signals[ACCOUNT_SELECTED], 0, account);
1154 
1155  action = gtk_action_group_get_action (action_group, "EditRenumberSubaccountsAction");
1156  g_object_set (G_OBJECT(action), "sensitive",
1157  is_readwrite && sensitive && subaccounts, NULL);
1158 
1159  action = gtk_action_group_get_action (action_group, "EditCascadeAccountAction");
1160  g_object_set (G_OBJECT(action), "sensitive", subaccounts, NULL);
1161 
1162  gnc_plugin_update_actions (action_group, actions_requiring_account_rw,
1163  "sensitive", is_readwrite && sensitive);
1164  gnc_plugin_update_actions (action_group, actions_requiring_account_always,
1165  "sensitive", sensitive);
1166 }
1167 
1168 
1169 /* Command callbacks */
1170 static void
1171 gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *page)
1172 {
1174  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1175  gnc_ui_new_account_window (parent, gnc_get_current_book(),
1176  account);
1177 }
1178 
1179 static void
1180 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *page)
1181 {
1182  gnc_ui_hierarchy_assistant(FALSE);
1183 }
1184 
1185 static void
1186 gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action,
1188 {
1189  Account *account;
1190 
1191  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1193  gppat_open_account_common (page, account, FALSE);
1194 }
1195 
1196 static void
1197 gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action,
1199 {
1200  Account *account;
1201 
1202  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1204  gppat_open_account_common (page, account, TRUE);
1205 }
1206 
1207 
1208 /*################## Added for Reg2 #################*/
1209 /* Register Firing - Single Account to start with */
1210 static void
1211 gnc_plugin_page_account_tree_cmd_open2_account (GtkAction *action,
1213 {
1214  Account *account;
1215 
1216  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1218  gppat_open2_account_common (page, account, FALSE);
1219 }
1220 
1221 static void
1222 gnc_plugin_page_account_tree_cmd_open2_subaccounts (GtkAction *action,
1224 {
1225  Account *account;
1226 
1227  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1229  gppat_open2_account_common (page, account, TRUE);
1230 }
1231 /*################## Added for Reg2 #################*/
1232 
1233 static void
1234 gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page)
1235 {
1236  Account *account;
1237  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (page)));
1238  ENTER("action %p, page %p", action, page);
1239 
1241  g_return_if_fail (account != NULL);
1242 
1243  gnc_ui_edit_account_window (parent, account);
1244  LEAVE(" ");
1245 }
1246 
1247 static void
1248 gnc_plugin_page_account_tree_cmd_find_account (GtkAction *action, GncPluginPageAccountTree *page)
1249 {
1250  GtkWidget *window;
1251 
1252  ENTER("action %p, page %p", action, page);
1253 
1254  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1255 
1256  gnc_find_account_dialog (window, NULL);
1257  LEAVE(" ");
1258 }
1259 
1260 static void
1261 gnc_plugin_page_account_tree_cmd_find_account_popup (GtkAction *action, GncPluginPageAccountTree *page)
1262 {
1263  Account *account = NULL;
1264  GtkWidget *window;
1265 
1266  ENTER("action %p, page %p", action, page);
1267 
1269 
1270  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1271 
1272  gnc_find_account_dialog (window, account);
1273  LEAVE(" ");
1274 }
1275 
1276 static void
1277 gnc_plugin_page_account_tree_cmd_cascade_account_properties (GtkAction *action, GncPluginPageAccountTree *page)
1278 {
1279  Account *account = NULL;
1280  GtkWidget *window;
1281 
1282  ENTER("action %p, page %p", action, page);
1283 
1285 
1286  window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page));
1287 
1288  if (account != NULL)
1289  gnc_account_cascade_properties_dialog (window, account);
1290 
1291  LEAVE(" ");
1292 }
1293 
1294 static gpointer
1295 delete_account_helper (Account * account, gpointer data)
1296 {
1297  delete_helper_t *helper_res = data;
1298  GList *splits;
1299 
1300  splits = xaccAccountGetSplitList (account);
1301  if (splits)
1302  {
1303  helper_res->has_splits = TRUE;
1304  while (splits)
1305  {
1306  Split *s = splits->data;
1307  Transaction *txn = xaccSplitGetParent (s);
1308  if (xaccTransGetReadOnly (txn))
1309  {
1310  helper_res->has_ro_splits = TRUE;
1311  break;
1312  }
1313  splits = splits->next;
1314  }
1315  }
1316 
1317  return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits);
1318 }
1319 
1320 /***
1321  *** The OK button of a Delete Account dialog is insensitive if
1322  *** and only if a sensitive account selector contains no accounts.
1323  ***/
1324 static void
1325 set_ok_sensitivity(GtkWidget *dialog)
1326 {
1327  GtkWidget *button;
1328  GtkWidget *sa_mas, *trans_mas;
1329  gint sa_mas_cnt, trans_mas_cnt;
1330  gboolean sensitive;
1331 
1332  sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
1333  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1334  sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas));
1335  trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas));
1336 
1337  sensitive = (((NULL == sa_mas) ||
1338  (!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) &&
1339  ((NULL == trans_mas) ||
1340  (!gtk_widget_is_sensitive(trans_mas) || trans_mas_cnt)));
1341 
1342  button = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON);
1343  gtk_widget_set_sensitive(button, sensitive);
1344 }
1345 
1346 static void
1347 gppat_populate_gas_list(GtkWidget *dialog,
1348  GNCAccountSel *gas,
1349  gboolean exclude_subaccounts)
1350 {
1351  Account *account;
1352  GList *filter;
1353 
1354  g_return_if_fail(GTK_IS_DIALOG(dialog));
1355  if (gas == NULL)
1356  return;
1357  account = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT);
1358  filter = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER);
1359 
1360  /* Setting the account type filter triggers GNCAccountSel population. */
1361  gnc_account_sel_set_acct_filters (gas, filter, NULL);
1362 
1363  /* Accounts to be deleted must be removed. */
1364  gnc_account_sel_purge_account( gas, account, exclude_subaccounts);
1365 
1366  /* The sensitivity of the OK button needs to be reevaluated. */
1367  set_ok_sensitivity(dialog);
1368 }
1369 
1370 void
1371 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb,
1372  GtkWidget *dialog)
1373 {
1374  GtkWidget *trans_mas;
1375 
1376  g_return_if_fail(GTK_IS_DIALOG(dialog));
1377 
1378  /* Cannot move transactions to subaccounts if they are to be deleted. */
1379  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1380  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb));
1381 }
1382 
1383 /* Note that the emitting object (the toggle button) and the signal data
1384  * are swapped in below callback function. This is a gtkbuilder feature:
1385  * it swaps if you explicitly set an object for a signal handler in the
1386  * gtkbuilder xml file.
1387  */
1388 void
1389 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b)
1390 {
1391  GtkWidget *dialog = gtk_widget_get_toplevel(widget);
1392  GtkWidget *subaccount_trans = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS);
1393  GtkWidget *sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
1394  gboolean have_splits = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS));
1395 
1396  gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b));
1397 
1398  // If we have subaccount splits & delete subaccounts, enable subaccount_trans
1399  if ((have_splits) && !gtk_widget_is_sensitive(sa_mas))
1400  gtk_widget_set_sensitive(subaccount_trans, TRUE);
1401  else
1402  gtk_widget_set_sensitive(subaccount_trans, FALSE);
1403 
1404  set_ok_sensitivity(dialog);
1405 }
1406 
1407 static GtkWidget *
1408 gppat_setup_account_selector (GtkBuilder *builder, GtkWidget *dialog,
1409  const gchar *hbox, const gchar *sel_name)
1410 {
1411  GtkWidget *selector = gnc_account_sel_new();
1412  GtkWidget *box = GTK_WIDGET(gtk_builder_get_object (builder, hbox));
1413 
1414  gtk_box_pack_start (GTK_BOX(box), selector, TRUE, TRUE, 0);
1415  gnc_account_sel_set_hexpand (GNC_ACCOUNT_SEL(selector), TRUE);
1416  g_object_set_data(G_OBJECT(dialog), sel_name, selector);
1417 
1418  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(selector), TRUE);
1419  gtk_widget_show_all(box);
1420 
1421  return selector;
1422 }
1423 
1424 static int
1425 commodity_mismatch_dialog (const Account* account, GtkWindow* parent)
1426 {
1427  int response;
1428  char *account_name = gnc_account_get_full_name (account);
1429  char* message = g_strdup_printf (
1430  _("Account %s does not have the same currency as the one you're "
1431  "moving transactions from.\nAre you sure you want to do this?"),
1432  account_name);
1433  GtkWidget* error_dialog =
1434  gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT,
1435  GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE,
1436  "%s", message);
1437  gtk_dialog_add_buttons (GTK_DIALOG(error_dialog),
1438  _("_Pick another account"), GTK_RESPONSE_CANCEL,
1439  _("_Do it anyway"), GTK_RESPONSE_ACCEPT,
1440  (gchar *)NULL);
1441  response = gtk_dialog_run (GTK_DIALOG (error_dialog));
1442  gtk_widget_destroy (error_dialog);
1443  g_free (message);
1444  return response;
1445 }
1446 
1447 typedef struct
1448 {
1449  Account *new_account;
1450  Account *old_account;
1451  GNCAccountSel *selector;
1452  gboolean match;
1453  gboolean for_account;
1454 } Adopter;
1455 
1456 static void
1457 adopter_set_account_and_match (Adopter* adopter)
1458 {
1459  if (!(adopter->selector &&
1460  gtk_widget_is_sensitive (GTK_WIDGET (adopter->selector))))
1461  return;
1462  adopter->new_account = gnc_account_sel_get_account(adopter->selector);
1463 /* We care about the commodity only if we're moving transactions. */
1464  if (!adopter->for_account && adopter->old_account && adopter->new_account)
1465  adopter->match =
1466  xaccAccountGetCommodity (adopter->new_account) ==
1467  xaccAccountGetCommodity (adopter->old_account);
1468 }
1469 
1470 static void
1471 adopter_init (Adopter* adopter, GtkWidget *selector, Account* account,
1472  gboolean for_account)
1473 {
1474  adopter->selector = GNC_ACCOUNT_SEL (selector);
1475  adopter->new_account = NULL;
1476  adopter->old_account = account;
1477  adopter->match = TRUE;
1478  adopter->for_account = for_account;
1479 }
1480 
1481 static gboolean
1482 adopter_match (Adopter* adopter, GtkWindow *parent)
1483 {
1484  int result;
1485  if (adopter->match || adopter->for_account)
1486  return TRUE;
1487  result = commodity_mismatch_dialog (adopter->new_account, parent);
1488  return (result == GTK_RESPONSE_ACCEPT);
1489 }
1490 
1491 typedef struct
1492 {
1493  Adopter trans;
1494  Adopter subacct;
1495  Adopter subtrans;
1496  delete_helper_t delete_res;
1497 } Adopters;
1498 
1499 static Account*
1500 account_subaccount (Account* account)
1501 {
1502  Account* subaccount = NULL;
1503  GList *subs = gnc_account_get_children (account);
1504  if (!gnc_list_length_cmp (subs, 1))
1505  subaccount = subs->data;
1506  g_list_free (subs);
1507  return subaccount;
1508 }
1509 
1510 static GtkWidget*
1511 account_delete_dialog (Account *account, GtkWindow *parent, Adopters* adopt)
1512 {
1513  GtkWidget *dialog = NULL;
1514  GtkWidget *widget = NULL;
1515  gchar *title = NULL;
1516  GtkBuilder *builder = gtk_builder_new();
1517  gchar *acct_name = gnc_account_get_full_name(account);
1518  GList* splits = xaccAccountGetSplitList(account);
1519  GList* filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
1520 
1521  if (!acct_name)
1522  acct_name = g_strdup (_("(no name)"));
1523 
1524  gnc_builder_add_from_file (builder, "dialog-account.glade", "account_delete_dialog");
1525 
1526  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "account_delete_dialog"));
1527  gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
1528 
1529  /* FIXME: Same account type used for subaccount. */
1530  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter);
1531  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account);
1532  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header"));
1533  title = g_strdup_printf(_("Deleting account %s"), acct_name);
1534  gtk_label_set_text(GTK_LABEL(widget), title);
1535  g_free(title);
1536  g_free(acct_name);
1537 
1538  widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON));
1539  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget);
1540 
1541  // Add the account selectors and enable sections as appropriate
1542  // setup transactions selector
1543  adopter_init (&adopt->trans,
1544  gppat_setup_account_selector (builder, dialog,
1545  "trans_mas_hbox",
1546  DELETE_DIALOG_TRANS_MAS),
1547  account, FALSE);
1548 
1549  // Does the selected account have splits
1550  if (splits)
1551  {
1552  delete_helper_t delete_res2 = { FALSE, FALSE };
1553 
1554  delete_account_helper(account, &delete_res2);
1555  if (delete_res2.has_ro_splits)
1556  {
1557  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw")));
1558  widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb"));
1559  gtk_widget_set_sensitive(widget, FALSE);
1560  }
1561  else
1562  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1563  }
1564  else
1565  {
1566  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "transactions")), FALSE);
1567  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1568  }
1569 
1570  // setup subaccount account selector
1571  adopter_init (&adopt->subacct,
1572  gppat_setup_account_selector (builder, dialog,
1573  "sa_mas_hbox",
1574  DELETE_DIALOG_SA_MAS),
1575  account, TRUE);
1576 
1577  // setup subaccount transaction selector
1578  adopter_init (&adopt->subtrans,
1579  gppat_setup_account_selector (builder, dialog,
1580  "sa_trans_mas_hbox",
1581  DELETE_DIALOG_SA_TRANS_MAS),
1582  account_subaccount (account), FALSE);
1583  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS,
1584  GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1585 
1586  if (gnc_account_n_children(account) > 0)
1587  {
1588  // Check for RO txns in descendants
1589  gnc_account_foreach_descendant_until(account, delete_account_helper,
1590  &adopt->delete_res);
1591  if (adopt->delete_res.has_splits)
1592  {
1593  if (adopt->delete_res.has_ro_splits)
1594  {
1595  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw")));
1596  widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb"));
1597  gtk_widget_set_sensitive(widget, FALSE);
1598  }
1599  else
1600  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1601 
1602  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(1));
1603  }
1604  else
1605  {
1606  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_SPLITS, GINT_TO_POINTER(0));
1607  gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1608  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1609  }
1610  }
1611  else
1612  {
1613  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts")), FALSE);
1614  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")), FALSE);
1615  gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1616  }
1617 
1618  /* default to cancel */
1619  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1620 
1621  gtk_builder_connect_signals(builder, dialog);
1622  g_object_unref(G_OBJECT(builder));
1623 
1624  return dialog;
1625 }
1626 
1627 static void
1628 gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page)
1629 {
1631  gchar *acct_name;
1632  GtkWidget *window;
1633  Adopters adopt;
1634  GList* list;
1635  gint response;
1636  GList *filter = NULL;
1637  GtkWidget *dialog = NULL;
1638 
1639  if (account == NULL)
1640  return;
1641 
1642  memset (&adopt, 0, sizeof (adopt));
1643  /* If the account has objects referring to it, show the list - the account can't be deleted until these
1644  references are dealt with. */
1645  list = qof_instance_get_referring_object_list(QOF_INSTANCE(account));
1646  if (list != NULL)
1647  {
1648 #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")
1649 
1650  gnc_ui_object_references_show(EXPLANATION, list);
1651  g_list_free(list);
1652  return;
1653  }
1654 
1655  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1656  acct_name = gnc_account_get_full_name(account);
1657  if (!acct_name)
1658  acct_name = g_strdup (_("(no name)"));
1659 
1660  if (gnc_account_n_children(account) > 1) {
1661  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);
1662  gnc_error_dialog(GTK_WINDOW(window),"%s", message);
1663  g_free (message);
1664  g_free(acct_name);
1665  return;
1666  }
1667 
1668  // If no transaction or children just delete it.
1669  if (!(xaccAccountGetSplitList (account) != NULL ||
1670  gnc_account_n_children (account)))
1671  {
1672  do_delete_account (account, NULL, NULL, NULL);
1673  return;
1674  }
1675 
1676  dialog = account_delete_dialog (account, GTK_WINDOW (window), &adopt);
1677 
1678  while (TRUE)
1679  {
1680  response = gtk_dialog_run(GTK_DIALOG(dialog));
1681 
1682  if (response != GTK_RESPONSE_ACCEPT)
1683  {
1684  /* Account deletion is cancelled, so clean up and return. */
1685  filter = g_object_get_data (G_OBJECT (dialog),
1686  DELETE_DIALOG_FILTER);
1687  gtk_widget_destroy(dialog);
1688  g_list_free(filter);
1689  return;
1690  }
1691  adopter_set_account_and_match (&adopt.trans);
1692  adopter_set_account_and_match (&adopt.subacct);
1693  adopter_set_account_and_match (&adopt.subtrans);
1694 
1695  if (adopter_match (&adopt.trans, GTK_WINDOW (window)) &&
1696  adopter_match (&adopt.subacct, GTK_WINDOW (window)) &&
1697  adopter_match (&adopt.subtrans, GTK_WINDOW (window)))
1698  break;
1699  }
1700  filter = g_object_get_data (G_OBJECT (dialog), DELETE_DIALOG_FILTER);
1701  gtk_widget_destroy(dialog);
1702  g_list_free(filter);
1703  if (confirm_delete_account (action, page, adopt.trans.new_account,
1704  adopt.subtrans.new_account,
1705  adopt.subacct.new_account,
1706  adopt.delete_res) == GTK_RESPONSE_ACCEPT)
1707  {
1708  do_delete_account (account, adopt.subacct.new_account,
1709  adopt.subtrans.new_account, adopt.trans.new_account);
1710  }
1711 }
1712 
1713 static int
1714 confirm_delete_account (GtkAction *action, GncPluginPageAccountTree *page,
1715  Account* ta, Account* sta, Account* saa,
1716  delete_helper_t delete_res)
1717 {
1719  GList* splits = xaccAccountGetSplitList(account);
1720  GtkWidget* window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1721  gint response;
1722 
1723  char *lines[6] = {0};
1724  char *message;
1725  int i = 0;
1726  GtkWidget *dialog;
1727  gchar* acct_name = gnc_account_get_full_name(account);
1728 
1729  lines[i] = g_strdup_printf (_("The account %s will be deleted."),
1730  acct_name);
1731  g_free(acct_name);
1732 
1733  if (splits)
1734  {
1735  if (ta)
1736  {
1737  char *name = gnc_account_get_full_name(ta);
1738  lines[++i] = g_strdup_printf (_("All transactions in this account "
1739  "will be moved to the account %s."),
1740  name);
1741  g_free (name);
1742  }
1743  else
1744  {
1745  lines[++i] = g_strdup_printf (_("All transactions in this account "
1746  "will be deleted."));
1747  }
1748  }
1749  if (gnc_account_n_children(account))
1750  {
1751  if (saa)
1752  {
1753  char *name = gnc_account_get_full_name(saa);
1754  lines[++i] = g_strdup_printf (_("Its sub-account will be "
1755  "moved to the account %s."), name);
1756  g_free (name);
1757  }
1758  else
1759  {
1760  lines[++i] = g_strdup_printf (_("Its subaccount will be deleted."));
1761  if (sta)
1762  {
1763  char *name = gnc_account_get_full_name(sta);
1764  lines[++i] = g_strdup_printf (_("All sub-account transactions "
1765  "will be moved to the "
1766  "account %s."), name);
1767  g_free (name);
1768  }
1769  else if (delete_res.has_splits)
1770  {
1771  lines[++i] = g_strdup_printf(_("All sub-account transactions "
1772  "will be deleted."));
1773  }
1774  }
1775  }
1776 
1777  lines[++i] = _("Are you sure you want to do this?");
1778 
1779  message = g_strjoinv(" ", lines);
1780  for (int j = 0; j < i; ++j) // Don't try to free the last one, it's const.
1781  g_free (lines[j]);
1782 
1783  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
1784  GTK_DIALOG_DESTROY_WITH_PARENT,
1785  GTK_MESSAGE_QUESTION,
1786  GTK_BUTTONS_NONE,
1787  "%s", message);
1788  g_free(message);
1789  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
1790  _("_Cancel"), GTK_RESPONSE_CANCEL,
1791  _("_Delete"), GTK_RESPONSE_ACCEPT,
1792  (gchar *)NULL);
1793  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1794  response = gtk_dialog_run(GTK_DIALOG(dialog));
1795  gtk_widget_destroy(dialog);
1796  return response;
1797 }
1798 
1799 void do_delete_account (Account* account, Account* saa, Account* sta, Account* ta)
1800 {
1801  GList *acct_list, *ptr;
1802  const GncGUID *guid;
1803  gchar guidstr[GUID_ENCODING_LENGTH+1];
1804 
1805  gnc_set_busy_cursor(NULL, TRUE);
1806  gnc_suspend_gui_refresh ();
1807 
1808  /* Move subaccounts and transactions if this was requested */
1809  xaccAccountBeginEdit (account);
1810  if (saa)
1811  {
1812  xaccAccountBeginEdit (saa);
1813  acct_list = gnc_account_get_children(account);
1814  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1815  gnc_account_append_child (saa, ptr->data);
1816  g_list_free(acct_list);
1817  xaccAccountCommitEdit (saa);
1818  }
1819  else if (sta)
1820  {
1821  /* Move the splits of its subaccounts, if any. */
1823  (AccountCb)xaccAccountMoveAllSplits,
1824  sta);
1825  }
1826  if (ta)
1827  {
1828  /* Move the splits of the account to be deleted. */
1829  xaccAccountMoveAllSplits (account, ta);
1830  }
1831  xaccAccountCommitEdit (account);
1832 
1833  /* Drop all references from the state file for
1834  * any subaccount the account still has
1835  */
1836  acct_list = gnc_account_get_children(account);
1837  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1838  {
1839  guid = xaccAccountGetGUID (ptr->data);
1840  guid_to_string_buff (guid, guidstr);
1841  gnc_state_drop_sections_for (guidstr);
1842  }
1843  g_list_free(acct_list);
1844 
1845  /* Drop all references from the state file for this account
1846  */
1847  guid = xaccAccountGetGUID (account);
1848  guid_to_string_buff (guid, guidstr);
1849  gnc_state_drop_sections_for (guidstr);
1850 
1851  /*
1852  * Finally, delete the account, any subaccounts it may still
1853  * have, and any splits it or its subaccounts may still have.
1854  */
1855  xaccAccountBeginEdit (account);
1856  xaccAccountDestroy (account);
1857  gnc_resume_gui_refresh ();
1858  gnc_unset_busy_cursor(NULL);
1859 }
1860 
1861 static void
1862 gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action,
1864 {
1865  Account *account;
1866  GtkWidget *window;
1867 
1868  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1870  if (!window || !account)
1871  return;
1872 
1873  gnc_account_renumber_create_dialog(window, account);
1874 }
1875 
1876 static void
1877 gnc_plugin_page_account_tree_cmd_refresh (GtkAction *action,
1879 {
1881 
1882  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1883 
1884  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1885 
1886  gnc_tree_view_account_clear_model_cache (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
1887  gtk_widget_queue_draw (priv->widget);
1888 }
1889 
1890 /*********************/
1891 
1892 static void
1893 gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action,
1895 {
1897 
1898  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1899  ENTER("(action %p, page %p)", action, page);
1900 
1901  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1902  account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page));
1903  LEAVE(" ");
1904 }
1905 
1906 static void
1907 gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action,
1909 {
1910  GtkWidget *window;
1911  Account *account;
1912  RecnWindow *recnData;
1913 
1915  g_return_if_fail (account != NULL);
1916 
1917  window = GNC_PLUGIN_PAGE (page)->window;
1918  recnData = recnWindow (window, account);
1919  gnc_ui_reconcile_window_raise (recnData);
1920 }
1921 
1922 static void
1923 gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action,
1925 {
1926  GtkWidget *window;
1927  Account *account;
1928  AutoClearWindow *autoClearData;
1929 
1931  g_return_if_fail (account != NULL);
1932 
1933  window = GNC_PLUGIN_PAGE (page)->window;
1934  autoClearData = autoClearWindow (window, account);
1935  gnc_ui_autoclear_window_raise (autoClearData);
1936 }
1937 
1938 static void
1939 gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action,
1941 {
1942  GtkWidget *window;
1943  Account *account;
1944 
1946  window = GNC_PLUGIN_PAGE (page)->window;
1947  gnc_xfer_dialog (window, account);
1948 }
1949 
1950 static void
1951 gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action,
1953 {
1954  GtkWidget *window;
1955  Account *account;
1956 
1958  window = GNC_PLUGIN_PAGE (page)->window;
1959  gnc_stock_split_dialog (window, account);
1960 }
1961 
1962 static void
1963 gnc_plugin_page_account_tree_cmd_edit_tax_options (GtkAction *action,
1965 {
1966  GtkWidget *window;
1967  Account *account;
1968 
1970  window = GNC_PLUGIN_PAGE (page)->window;
1971  gnc_tax_info_dialog (window, account);
1972 }
1973 
1974 static void
1975 gnc_plugin_page_account_tree_cmd_lots (GtkAction *action,
1977 {
1979  GtkWidget *window = GNC_PLUGIN_PAGE (page)->window;
1980  gnc_lot_viewer_dialog (GTK_WINDOW(window), account);
1981 }
1982 
1983 static gboolean scrub_kp_handler (GtkWidget *widget, GdkEventKey *event, gpointer data)
1984 {
1985  if (event->length == 0) return FALSE;
1986 
1987  switch (event->keyval)
1988  {
1989  case GDK_KEY_Escape:
1990  {
1991  gboolean abort_scrub = gnc_verify_dialog (GTK_WINDOW(widget), FALSE,
1992  _("'Check & Repair' is currently running, do you want to abort it?"));
1993 
1994  if (abort_scrub)
1995  gnc_set_abort_scrub (TRUE);
1996 
1997  return TRUE;
1998  }
1999  default:
2000  break;
2001  }
2002  return FALSE;
2003 }
2004 
2005 static void
2006 gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page)
2007 {
2009  GncWindow *window;
2010  gulong scrub_kp_handler_ID;
2011 
2012  g_return_if_fail (account != NULL);
2013 
2014  prepare_scrubbing ();
2015 
2016  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2017  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2018  G_CALLBACK(scrub_kp_handler), NULL);
2019  gnc_window_set_progressbar_window (window);
2020 
2021  xaccAccountScrubOrphans (account, gnc_window_show_progress);
2022  xaccAccountScrubImbalance (account, gnc_window_show_progress);
2023 
2024  // XXX: Lots/capital gains scrubbing is disabled
2025  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2026  xaccAccountScrubLots(account);
2027 
2028  gncScrubBusinessAccount(account, gnc_window_show_progress);
2029 
2030  finish_scrubbing (window, scrub_kp_handler_ID);
2031 }
2032 
2033 static void
2034 gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page)
2035 {
2037  GncWindow *window;
2038  gulong scrub_kp_handler_ID;
2039 
2040  g_return_if_fail (account != NULL);
2041 
2042  prepare_scrubbing ();
2043 
2044  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2045  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2046  G_CALLBACK(scrub_kp_handler), NULL);
2047  gnc_window_set_progressbar_window (window);
2048 
2049  xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
2050  xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
2051 
2052  // XXX: Lots/capital gains scrubbing is disabled
2053  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2054  xaccAccountTreeScrubLots(account);
2055 
2056  gncScrubBusinessAccountTree(account, gnc_window_show_progress);
2057 
2058  finish_scrubbing (window, scrub_kp_handler_ID);
2059 }
2060 
2061 static void
2062 gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page)
2063 {
2064  Account *root = gnc_get_current_root_account ();
2065  GncWindow *window;
2066  gulong scrub_kp_handler_ID;
2067 
2068  prepare_scrubbing ();
2069 
2070  window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
2071  scrub_kp_handler_ID = g_signal_connect (G_OBJECT(window), "key-press-event",
2072  G_CALLBACK(scrub_kp_handler), NULL);
2073  gnc_window_set_progressbar_window (window);
2074 
2075  xaccAccountTreeScrubOrphans (root, gnc_window_show_progress);
2076  xaccAccountTreeScrubImbalance (root, gnc_window_show_progress);
2077  // XXX: Lots/capital gains scrubbing is disabled
2078  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
2079  xaccAccountTreeScrubLots(root);
2080 
2081  gncScrubBusinessAccountTree(root, gnc_window_show_progress);
2082 
2083  finish_scrubbing (window, scrub_kp_handler_ID);
2084 }
2085 
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:2567
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:580
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