GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <[email protected]>
5  * Copyright (C) 2003,2005,2006 David Hampton <[email protected]>
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 [email protected]
23  */
24 
35 #include "config.h"
36 
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
41 #include "gnc-plugin-page-register2.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 "dialog-lot-viewer.h"
67 #include "window-reconcile.h"
68 #include "window-autoclear.h"
69 #include "window-main-summarybar.h"
71 
72 /* This static indicates the debugging module that this .o belongs to. */
73 static QofLogModule log_module = GNC_MOD_GUI;
74 
75 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-acct-tree"
76 #define STATE_SECTION "Account Hierarchy"
77 
78 #define DELETE_DIALOG_FILTER "filter"
79 #define DELETE_DIALOG_ACCOUNT "account"
80 #define DELETE_DIALOG_TRANS_MAS "trans_mas"
81 #define DELETE_DIALOG_SA_MAS "sa_mas"
82 #define DELETE_DIALOG_SA_TRANS_MAS "sa_trans_mas"
83 #define DELETE_DIALOG_OK_BUTTON "deletebutton"
84 
85 enum
86 {
87  ACCOUNT_SELECTED,
88  LAST_SIGNAL
89 };
90 
92 {
93  GtkWidget *widget;
94  GtkTreeView *tree_view;
95  gint component_id;
98 
99 #define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(o) \
100  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, GncPluginPageAccountTreePrivate))
101 
102 static GObjectClass *parent_class = NULL;
103 
104 /************************************************************
105  * Prototypes *
106  ************************************************************/
107 /* Plugin Actions */
108 static void gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass);
109 static void gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page);
110 static void gnc_plugin_page_account_tree_finalize (GObject *object);
111 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data);
112 
113 static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page);
114 static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page);
115 static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
116 static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
117 
118 /* Callbacks */
119 static void gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data);
120 static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
121  GdkEventButton *event,
122  GncPluginPage *page);
123 static void gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
124  GtkTreePath *path,
125  GtkTreeViewColumn *col,
127 
128 static void gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
130 void gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb, GtkWidget *dialog);
131 void gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b);
132 
133 /* Command callbacks */
134 static void gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *plugin_page);
135 static void gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *plugin_page);
136 static void gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action, GncPluginPageAccountTree *page);
137 static void gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action, GncPluginPageAccountTree *page);
138 static void gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page);
139 static void gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page);
140 static void gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action, GncPluginPageAccountTree *page);
141 static void gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action, GncPluginPageAccountTree *plugin_page);
142 static void gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action, GncPluginPageAccountTree *page);
143 static void gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action, GncPluginPageAccountTree *page);
144 static void gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action, GncPluginPageAccountTree *page);
145 static void gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action, GncPluginPageAccountTree *page);
146 static void gnc_plugin_page_account_tree_cmd_lots (GtkAction *action, GncPluginPageAccountTree *page);
147 static void gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page);
148 static void gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page);
149 static void gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page);
150 
151 /* Command callback for new Register Test */
152 static void gnc_plugin_page_account_tree_cmd_open2_account (GtkAction *action, GncPluginPageAccountTree *page);
153 static void gnc_plugin_page_account_tree_cmd_open2_subaccounts (GtkAction *action, GncPluginPageAccountTree *page);
154 
155 static guint plugin_page_signals[LAST_SIGNAL] = { 0 };
156 
157 
158 static GtkActionEntry gnc_plugin_page_account_tree_actions [] =
159 {
160  /* Toplevel */
161  { "FakeToplevel", NULL, "", NULL, NULL, NULL },
162 
163  /* File menu */
164  {
165  "FileNewAccountAction", GNC_STOCK_NEW_ACCOUNT, N_("New _Account..."), NULL,
166  N_("Create a new Account"),
167  G_CALLBACK (gnc_plugin_page_account_tree_cmd_new_account)
168  },
169  {
170  "FileAddAccountHierarchyAssistantAction", GNC_STOCK_NEW_ACCOUNT, N_("New Account _Hierarchy..."), NULL,
171  N_("Extend the current book by merging with new account type categories"),
172  G_CALLBACK (gnc_plugin_page_account_tree_cmd_file_new_hierarchy)
173  },
174 #ifdef REGISTER2_ENABLED
175  {
176  "FileOpenAccount2Action", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL,
177  N_("Open the selected account"),
178  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_account)
179  },
180  {
181  "FileOpenAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Old Style Register Account"), NULL,
182  N_("Open the old style register selected account"),
183  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account)
184  },
185 #else
186  {
187  "FileOpenAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL,
188  N_("Open the selected account"),
189  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account)
190  },
191 #endif
192 
193 #ifdef REGISTER2_ENABLED
194  {
195  "FileOpenSubaccounts2Action", GNC_STOCK_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
196  N_("Open the selected account and all its subaccounts"),
197  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_subaccounts)
198  },
199  {
200  "FileOpenSubaccountsAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open Old St_yle Subaccounts"), NULL,
201  N_("Open the old style register selected account and all its subaccounts"),
202  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_subaccounts)
203  },
204 #else
205  {
206  "FileOpenSubaccountsAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
207  N_("Open the selected account and all its subaccounts"),
208  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_subaccounts)
209  },
210 #endif
211 
212  /* Edit menu */
213  {
214  "EditEditAccountAction", GNC_STOCK_EDIT_ACCOUNT, N_("Edit _Account"), "<control>e",
215  N_("Edit the selected account"),
216  G_CALLBACK (gnc_plugin_page_account_tree_cmd_edit_account)
217  },
218  {
219  "EditDeleteAccountAction", GNC_STOCK_DELETE_ACCOUNT, N_("_Delete Account..."), "Delete",
220  N_("Delete selected account"),
221  G_CALLBACK (gnc_plugin_page_account_tree_cmd_delete_account)
222  },
223  {
224  "EditRenumberSubaccountsAction", NULL, N_("_Renumber Subaccounts..."), NULL,
225  N_("Renumber the children of the selected account"),
226  G_CALLBACK (gnc_plugin_page_account_tree_cmd_renumber_accounts)
227  },
228 
229  /* View menu */
230  {
231  "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, NULL,
232  G_CALLBACK (gnc_plugin_page_account_tree_cmd_view_filter_by)
233  },
234 
235  /* Actions menu */
236  {
237  "ActionsReconcileAction", NULL, N_("_Reconcile..."), NULL,
238  N_("Reconcile the selected account"),
239  G_CALLBACK (gnc_plugin_page_account_tree_cmd_reconcile)
240  },
241  {
242  "ActionsAutoClearAction", NULL, N_("_Auto-clear..."), NULL,
243  N_("Automatically clear individual transactions, given a cleared amount"),
244  G_CALLBACK (gnc_plugin_page_account_tree_cmd_autoclear)
245  },
246  {
247  "ActionsTransferAction", NULL, N_("_Transfer..."), "<control>t",
248  N_("Transfer funds from one account to another"),
249  G_CALLBACK (gnc_plugin_page_account_tree_cmd_transfer)
250  },
251  {
252  "ActionsStockSplitAction", NULL, N_("Stoc_k Split..."), NULL,
253  N_("Record a stock split or a stock merger"),
254  G_CALLBACK (gnc_plugin_page_account_tree_cmd_stock_split)
255  },
256  {
257  "ActionsLotsAction", NULL, N_("View _Lots..."), NULL,
258  N_("Bring up the lot viewer/editor window"),
259  G_CALLBACK (gnc_plugin_page_account_tree_cmd_lots)
260  },
261  {
262  "ScrubAction", NULL, N_("Check & Repair A_ccount"), NULL,
263  N_("Check for and repair unbalanced transactions and orphan splits " "in this account"),
264  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub)
265  },
266  {
267  "ScrubSubAction", NULL, N_("Check & Repair Su_baccounts"), NULL,
268  N_("Check for and repair unbalanced transactions and orphan splits "
269  "in this account and its subaccounts"),
270  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_sub)
271  },
272  {
273  "ScrubAllAction", NULL, N_("Check & Repair A_ll"), NULL,
274  N_("Check for and repair unbalanced transactions and orphan splits " "in all accounts"),
275  G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_all)
276  },
277  /* Extensions Menu */
278  { "Register2TestAction", NULL, N_("_Register2"), NULL, NULL, NULL },
279  {
280  "Register2TestAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL,
281  N_("Open the selected account"),
282  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_account)
283  },
284  {
285  "Register2TestSubAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _SubAccounts"), NULL,
286  N_("Open the selected account and all its subaccounts"),
287  G_CALLBACK (gnc_plugin_page_account_tree_cmd_open2_subaccounts)
288  },
289 };
291 static guint gnc_plugin_page_account_tree_n_actions = G_N_ELEMENTS (gnc_plugin_page_account_tree_actions);
292 
293 
296 static const gchar *actions_requiring_account_rw[] =
297 {
298  "EditEditAccountAction",
299  "EditDeleteAccountAction",
300  "ActionsReconcileAction",
301  "ActionsAutoClearAction",
302  NULL
303 };
304 
307 static const gchar *actions_requiring_account_always[] =
308 {
309  "FileOpenAccountAction",
310 #ifdef REGISTER2_ENABLED
311  "FileOpenAccount2Action",
312 #endif
313  "FileOpenSubaccountsAction",
314  "ActionsLotsAction",
315  NULL
316 };
317 
318 /* This is the list of actions which are switched inactive in a read-only book. */
319 static const gchar* readonly_inactive_actions[] =
320 {
321  "FileNewAccountAction",
322  "FileAddAccountHierarchyAssistantAction",
323  "EditEditAccountAction",
324  "EditDeleteAccountAction",
325  "EditRenumberSubaccountsAction",
326  "ActionsTransferAction",
327  "ActionsReconcileAction",
328  "ActionsAutoClearAction",
329  "ActionsStockSplitAction",
330  "ScrubAction",
331  "ScrubSubAction",
332  "ScrubAllAction",
333  NULL
334 };
335 
337 static action_toolbar_labels toolbar_labels[] =
338 {
339  { "FileOpenAccountAction", N_("Open") },
340 #ifdef REGISTER2_ENABLED
341  { "FileOpenAccount2Action", N_("Open2") },
342 #endif
343  { "EditEditAccountAction", N_("Edit") },
344  { "FileNewAccountAction", N_("New") },
345  { "EditDeleteAccountAction", N_("Delete") },
346  { NULL, NULL },
347 };
348 
349 
350 GType
352 {
353  static GType gnc_plugin_page_account_tree_type = 0;
354 
355  if (gnc_plugin_page_account_tree_type == 0)
356  {
357  static const GTypeInfo our_info =
358  {
360  NULL,
361  NULL,
362  (GClassInitFunc) gnc_plugin_page_account_tree_class_init,
363  NULL,
364  NULL,
365  sizeof (GncPluginPageAccountTree),
366  0,
367  (GInstanceInitFunc) gnc_plugin_page_account_tree_init
368  };
369 
370  gnc_plugin_page_account_tree_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
371  GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME,
372  &our_info, 0);
373  }
374 
375  return gnc_plugin_page_account_tree_type;
376 }
377 
380 {
381  GncPluginPageAccountTree *plugin_page;
382 
383  ENTER(" ");
384  plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE,
385  NULL);
386 
387  LEAVE("new account tree page %p", plugin_page);
388  return GNC_PLUGIN_PAGE (plugin_page);
389 }
390 
391 static void
392 gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass)
393 {
394  GObjectClass *object_class = G_OBJECT_CLASS (klass);
395  GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
396 
397  parent_class = g_type_class_peek_parent (klass);
398 
399  object_class->finalize = gnc_plugin_page_account_tree_finalize;
400 
401  gnc_plugin_class->tab_icon = GNC_STOCK_ACCOUNT;
402  gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME;
403  gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget;
404  gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget;
405  gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page;
406  gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page;
407 
408  g_type_class_add_private(klass, sizeof(GncPluginPageAccountTreePrivate));
409 
410  plugin_page_signals[ACCOUNT_SELECTED] =
411  g_signal_new ("account_selected",
412  G_OBJECT_CLASS_TYPE (object_class),
413  G_SIGNAL_RUN_FIRST,
414  G_STRUCT_OFFSET (GncPluginPageAccountTreeClass, account_selected),
415  NULL, NULL,
416  g_cclosure_marshal_VOID__POINTER,
417  G_TYPE_NONE, 1,
418  G_TYPE_POINTER);
419 }
420 
421 static void
422 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page)
423 {
424  GtkActionGroup *action_group;
426  GncPluginPage *parent;
427  const GList *page_list;
428 
429  ENTER("page %p", plugin_page);
430  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(plugin_page);
431 
432  /* Init parent declared variables */
433  parent = GNC_PLUGIN_PAGE(plugin_page);
434 #ifdef REGISTER2_ENABLED
435  g_object_set(G_OBJECT(plugin_page),
436  "page-name", _("Accounts"),
437  "page-uri", "default:",
438  "ui-description", "gnc-plugin-page-account-tree2-ui.xml",
439  NULL);
440 #else
441  g_object_set(G_OBJECT(plugin_page),
442  "page-name", _("Accounts"),
443  "page-uri", "default:",
444  "ui-description", "gnc-plugin-page-account-tree-ui.xml",
445  NULL);
446 #endif
447  g_signal_connect (G_OBJECT (plugin_page), "selected",
448  G_CALLBACK (gnc_plugin_page_account_tree_selected), plugin_page);
449 
450  /* change me when the system supports multiple books */
451  gnc_plugin_page_add_book(parent, gnc_get_current_book());
452 
453  /* Is this the first accounts page? */
454  page_list =
455  gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME);
456  if (plugin_page == page_list->data)
457  {
458  g_object_set_data(G_OBJECT(plugin_page), PLUGIN_PAGE_IMMUTABLE,
459  GINT_TO_POINTER(1));
460  }
461 
462  /* Create menu and toolbar information */
463  action_group =
465  "GncPluginPageAccountTreeActions");
466  gtk_action_group_add_actions(action_group,
467  gnc_plugin_page_account_tree_actions,
468  gnc_plugin_page_account_tree_n_actions,
469  plugin_page);
470  gnc_plugin_init_short_names (action_group, toolbar_labels);
471 
472  /* Visible types */
473  priv->fd.visible_types = -1; /* Start with all types */
474  priv->fd.show_hidden = FALSE;
475  priv->fd.show_zero_total = TRUE;
476 
477  LEAVE("page %p, priv %p, action group %p",
478  plugin_page, priv, action_group);
479 }
480 
481 static void
482 gnc_plugin_page_account_tree_finalize (GObject *object)
483 {
486 
487  ENTER("object %p", object);
488  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (object);
489  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
490  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
491  g_return_if_fail (priv != NULL);
492 
493  G_OBJECT_CLASS (parent_class)->finalize (object);
494  LEAVE(" ");
495 }
496 
497 Account *
499 {
501  Account *account;
502 
503  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
504  ENTER("page %p (tree view %p)", page, priv->tree_view);
505  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view));
506  if (account == NULL)
507  {
508  LEAVE("no account");
509  return NULL;
510  }
511 
512  LEAVE("account %p", account);
513  return account;
514 }
515 
516 
517 /* Virtual Functions */
518 
519 static void
520 gnc_plugin_page_account_refresh_cb (GHashTable *changes, gpointer user_data)
521 {
522  GncPluginPageAccountTree *page = user_data;
524 
525  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
526 
527  /* We're only looking for forced updates here. */
528  if (changes)
529  return;
530 
531  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
532  gtk_widget_queue_draw(priv->widget);
533 }
534 
535 static void
536 gnc_plugin_page_account_tree_close_cb (gpointer user_data)
537 {
538  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
539  gnc_main_window_close_page(plugin_page);
540 }
541 
542 static GtkWidget *
543 gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page)
544 {
547  GtkTreeSelection *selection;
548  GtkTreeView *tree_view;
549  GtkWidget *scrolled_window;
550  GtkTreeViewColumn *col;
551 
552  ENTER("page %p", plugin_page);
553  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
554  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
555  if (priv->widget != NULL)
556  {
557  LEAVE("widget = %p", priv->widget);
558  return priv->widget;
559  }
560 
561  priv->widget = gtk_vbox_new (FALSE, 0);
562  gtk_widget_show (priv->widget);
563 
564  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
565  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
566  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
567  gtk_widget_show (scrolled_window);
568  gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window,
569  TRUE, TRUE, 0);
570 
571  tree_view = gnc_tree_view_account_new(FALSE);
573  GNC_TREE_VIEW(tree_view), "description");
574  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
576  GNC_TREE_VIEW(tree_view), "total");
577  g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
578  gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view));
579  g_object_set(G_OBJECT(tree_view),
580  "state-section", STATE_SECTION,
581  "show-column-menu", TRUE,
582  NULL);
583 
584  /* No name handler; then the user can't click on the name of the
585  account to open its register. */
586  gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
587  gnc_tree_view_account_code_edited_cb);
588  gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
589  gnc_tree_view_account_description_edited_cb);
590  gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view),
591  gnc_tree_view_account_notes_edited_cb);
592 
593  priv->tree_view = tree_view;
594  selection = gtk_tree_view_get_selection(tree_view);
595  g_signal_connect (G_OBJECT (selection), "changed",
596  G_CALLBACK (gnc_plugin_page_account_tree_selection_changed_cb), page);
597  g_signal_connect (G_OBJECT (tree_view), "button-press-event",
598  G_CALLBACK (gnc_plugin_page_account_tree_button_press_cb), page);
599  g_signal_connect (G_OBJECT (tree_view), "row-activated",
600  G_CALLBACK (gnc_plugin_page_account_tree_double_click_cb), page);
601 
602  gtk_tree_view_set_headers_visible(tree_view, TRUE);
603  gnc_plugin_page_account_tree_selection_changed_cb (NULL, page);
604  gtk_widget_show (GTK_WIDGET (tree_view));
605  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(tree_view));
606 
607  priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view);
609  GNC_TREE_VIEW_ACCOUNT(tree_view),
611 
612  priv->component_id =
613  gnc_register_gui_component(PLUGIN_PAGE_ACCT_TREE_CM_CLASS,
614  gnc_plugin_page_account_refresh_cb,
615  gnc_plugin_page_account_tree_close_cb,
616  page);
617  gnc_gui_component_set_session (priv->component_id,
618  gnc_get_current_session());
619 
620  plugin_page->summarybar = gnc_main_window_summary_new();
621  gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar,
622  FALSE, FALSE, 0);
623  gtk_widget_show(plugin_page->summarybar);
624  gnc_plugin_page_account_tree_summarybar_position_changed(NULL, NULL, page);
625  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
626  GNC_PREF_SUMMARYBAR_POSITION_TOP,
627  gnc_plugin_page_account_tree_summarybar_position_changed,
628  page);
629  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
630  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
631  gnc_plugin_page_account_tree_summarybar_position_changed,
632  page);
633 
634  LEAVE("widget = %p", priv->widget);
635  return priv->widget;
636 }
637 
638 static void
639 gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page)
640 {
643 
644  ENTER("page %p", plugin_page);
645  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page);
646  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
647 
648  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
649  GNC_PREF_SUMMARYBAR_POSITION_TOP,
650  gnc_plugin_page_account_tree_summarybar_position_changed,
651  page);
652  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
653  GNC_PREF_SUMMARYBAR_POSITION_BOTTOM,
654  gnc_plugin_page_account_tree_summarybar_position_changed,
655  page);
656 
657  if (priv->widget)
658  {
659  g_object_unref(G_OBJECT(priv->widget));
660  priv->widget = NULL;
661  }
662 
663  if (priv->component_id)
664  {
665  gnc_unregister_gui_component(priv->component_id);
666  priv->component_id = 0;
667  }
668 
669  LEAVE("widget destroyed");
670 }
671 
672 static void update_inactive_actions(GncPluginPage *plugin_page)
673 {
674  GtkActionGroup *action_group;
675  gboolean is_sensitive = !qof_book_is_readonly(gnc_get_current_book());
676 
677  // We are readonly - so we have to switch particular actions to inactive.
678  g_return_if_fail(plugin_page);
679  g_return_if_fail(GNC_IS_PLUGIN_PAGE(plugin_page));
680 
681  /* Get the action group */
682  action_group = gnc_plugin_page_get_action_group(plugin_page);
683  g_return_if_fail(GTK_IS_ACTION_GROUP (action_group));
684 
685  /* Set the action's sensitivity */
686  gnc_plugin_update_actions (action_group, readonly_inactive_actions,
687  "sensitive", is_sensitive);
688 }
689 
694 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data)
695 {
696  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object);
697  g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page));
698  update_inactive_actions(plugin_page);
699 }
700 
710 static void
711 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page,
712  GKeyFile *key_file,
713  const gchar *group_name)
714 {
715  GncPluginPageAccountTree *account_page;
717 
718  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page));
719  g_return_if_fail (key_file != NULL);
720  g_return_if_fail (group_name != NULL);
721 
722  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
723  group_name);
724 
725  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page);
726  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
727 
728  gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
729  &priv->fd, key_file, group_name);
730  LEAVE(" ");
731 }
732 
733 
734 
744 static GncPluginPage *
745 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window,
746  GKeyFile *key_file,
747  const gchar *group_name)
748 {
749  GncPluginPageAccountTree *account_page;
751  GncPluginPage *page;
752 
753  g_return_val_if_fail(key_file, NULL);
754  g_return_val_if_fail(group_name, NULL);
755  ENTER("key_file %p, group_name %s", key_file, group_name);
756 
757  /* Create the new page. */
759  account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page);
760  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page);
761 
762  /* Install it now so we can then manipulate the created widget */
763  gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page);
764 
765  gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view),
766  &priv->fd, key_file, group_name);
767  LEAVE(" ");
768  return page;
769 }
770 
771 
772 /* Callbacks */
773 
774 static void
775 gnc_plugin_page_account_tree_summarybar_position_changed(gpointer prefs, gchar* pref, gpointer user_data)
776 {
777  GncPluginPage *plugin_page;
780  GtkPositionType position = GTK_POS_BOTTOM;
781 
782  g_return_if_fail(user_data != NULL);
783 
784  plugin_page = GNC_PLUGIN_PAGE(user_data);
785  page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data);
786  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
787 
788  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_SUMMARYBAR_POSITION_TOP))
789  position = GTK_POS_TOP;
790 
791  gtk_box_reorder_child(GTK_BOX(priv->widget),
792  plugin_page->summarybar,
793  (position == GTK_POS_TOP ? 0 : -1) );
794 }
795 
803 static gboolean
804 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget,
805  GdkEventButton *event,
806  GncPluginPage *page)
807 {
808 
809  g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE);
810 
811  ENTER("widget %p, event %p, page %p", widget, event, page);
812  gnc_main_window_button_press_cb(widget, event, page);
813  LEAVE(" ");
814 
815  /* Always return FALSE. This will let the tree view callback run as
816  * well which will select the item under the cursor. By the time
817  * the user sees the menu both callbacks will have run and the menu
818  * actions will operate on the just-selected account. */
819  return FALSE;
820 }
821 
822 static void
823 gppat_open_account_common (GncPluginPageAccountTree *page,
824  Account *account,
825  gboolean include_subs)
826 {
827  GtkWidget *window;
828  GncPluginPage *new_page;
829 
830  if (account == NULL)
831  return;
832 
833  window = GNC_PLUGIN_PAGE (page)->window;
834  new_page = gnc_plugin_page_register_new (account, include_subs);
835  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
836 }
837 
838 /*################## Added for Reg2 #################*/
839 /* New Register Common */
840 static void
841 gppat_open2_account_common (GncPluginPageAccountTree *page,
842  Account *account,
843  gboolean include_subs)
844 {
845  GtkWidget *window;
846  GncPluginPage *new_page;
847 
848  if (account == NULL)
849  return;
850 
851  window = GNC_PLUGIN_PAGE (page)->window;
852  new_page = gnc_plugin_page_register2_new (account, include_subs);
853  gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
854 }
855 /*################## Added for Reg2 #################*/
856 
857 static void
858 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview,
859  GtkTreePath *path,
860  GtkTreeViewColumn *col,
862 {
863  GtkTreeModel *model;
864  GtkTreeIter iter;
865 
866  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
867  g_return_if_fail (treeview);
868 
869  model = gtk_tree_view_get_model(treeview);
870  if (gtk_tree_model_get_iter(model, &iter, path))
871  {
872  Account *account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path);
873  if (xaccAccountGetPlaceholder (account))
874  {
875  /* This is a placeholder account. Only only show/hide
876  * subaccount list if there is one.
877  */
878  if (gtk_tree_model_iter_has_child(model, &iter))
879  {
880  /* There are children,
881  * just expand or collapse the row. */
882  if (gtk_tree_view_row_expanded(treeview, path))
883  gtk_tree_view_collapse_row(treeview, path);
884  else
885  gtk_tree_view_expand_row(treeview, path, FALSE);
886  }
887  }
888  else
889  {
890  /* No placeholder account, so open its register */
891 #ifdef REGISTER2_ENABLED
892  gppat_open2_account_common (page, account, FALSE);
893 #else
894  gppat_open_account_common (page, account, FALSE);
895 #endif
896  }
897  }
898 }
899 
900 static void
901 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection,
903 {
904  GtkActionGroup *action_group;
905  GtkAction *action;
906  GtkTreeView *view;
907  Account *account = NULL;
908  gboolean sensitive;
909  gboolean subaccounts;
910  gboolean is_readwrite = !qof_book_is_readonly(gnc_get_current_book());
911 
912  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
913 
914  if (!selection)
915  {
916  sensitive = FALSE;
917  subaccounts = FALSE;
918  }
919  else
920  {
921  g_return_if_fail(GTK_IS_TREE_SELECTION(selection));
922  view = gtk_tree_selection_get_tree_view (selection);
923  account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(view));
924  sensitive = (account != NULL);
925 
926  subaccounts = account && (gnc_account_n_children(account) != 0);
927  /* Check here for placeholder accounts, etc. */
928  }
929 
930  action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(page));
931  gnc_plugin_update_actions (action_group, actions_requiring_account_rw,
932  "sensitive", is_readwrite && sensitive);
933  gnc_plugin_update_actions (action_group, actions_requiring_account_always,
934  "sensitive", sensitive);
935  g_signal_emit (page, plugin_page_signals[ACCOUNT_SELECTED], 0, account);
936 
937  action = gtk_action_group_get_action (action_group, "EditRenumberSubaccountsAction");
938  g_object_set (G_OBJECT(action), "sensitive",
939  is_readwrite && sensitive && subaccounts, NULL);
940 
941  gnc_plugin_update_actions (action_group, actions_requiring_account_rw,
942  "sensitive", is_readwrite && sensitive);
943  gnc_plugin_update_actions (action_group, actions_requiring_account_always,
944  "sensitive", sensitive);
945 }
946 
947 
948 /* Command callbacks */
949 static void
950 gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *page)
951 {
953 
954  gnc_ui_new_account_window (gnc_get_current_book(), account);
955 }
956 
957 static void
958 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *page)
959 {
960  gnc_ui_hierarchy_assistant(FALSE);
961 }
962 
963 static void
964 gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action,
966 {
967  Account *account;
968 
969  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
971  gppat_open_account_common (page, account, FALSE);
972 }
973 
974 static void
975 gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action,
977 {
978  Account *account;
979 
980  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
982  gppat_open_account_common (page, account, TRUE);
983 }
984 
985 
986 /*################## Added for Reg2 #################*/
987 /* Register Firing - Single Account to start with */
988 static void
989 gnc_plugin_page_account_tree_cmd_open2_account (GtkAction *action,
991 {
992  Account *account;
993 
994  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
996  gppat_open2_account_common (page, account, FALSE);
997 }
998 
999 static void
1000 gnc_plugin_page_account_tree_cmd_open2_subaccounts (GtkAction *action,
1002 {
1003  Account *account;
1004 
1005  g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page));
1007  gppat_open2_account_common (page, account, TRUE);
1008 }
1009 /*################## Added for Reg2 #################*/
1010 
1011 
1012 static void
1013 gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page)
1014 {
1015  Account *account;
1016 
1017  ENTER("action %p, page %p", action, page);
1018 
1020  g_return_if_fail (account != NULL);
1021 
1022  gnc_ui_edit_account_window (account);
1023  LEAVE(" ");
1024 }
1025 
1026 /********************************************************************
1027  * delete_account_helper
1028  * See if this account has any splits present. Set the user data
1029  * and return the same value to stop walking the account tree if
1030  * appropriate.
1031  ********************************************************************/
1032 typedef struct _delete_helper
1033 {
1034  gboolean has_splits;
1035  gboolean has_ro_splits;
1036 } delete_helper_t;
1037 
1038 static gpointer
1039 delete_account_helper (Account * account, gpointer data)
1040 {
1041  delete_helper_t *helper_res = data;
1042  GList *splits;
1043 
1044  splits = xaccAccountGetSplitList (account);
1045  if (splits)
1046  {
1047  helper_res->has_splits = TRUE;
1048  while (splits)
1049  {
1050  Split *s = splits->data;
1051  Transaction *txn = xaccSplitGetParent (s);
1052  if (xaccTransGetReadOnly (txn))
1053  {
1054  helper_res->has_ro_splits = TRUE;
1055  break;
1056  }
1057  splits = splits->next;
1058  }
1059  }
1060 
1061  return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits);
1062 }
1063 
1064 /***
1065  *** The OK button of a Delete Account dialog is insensitive if
1066  *** and only if a sensitive account selector contains no accounts.
1067  ***/
1068 static void
1069 set_ok_sensitivity(GtkWidget *dialog)
1070 {
1071  GtkWidget *button;
1072  GtkWidget *sa_mas, *trans_mas;
1073  gint sa_mas_cnt, trans_mas_cnt;
1074  gboolean sensitive;
1075 
1076  sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS);
1077  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1078  sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas));
1079  trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas));
1080 
1081  sensitive = (((NULL == sa_mas) ||
1082  (!gtk_widget_is_sensitive(sa_mas) || sa_mas_cnt)) &&
1083  ((NULL == trans_mas) ||
1084  (!gtk_widget_is_sensitive(trans_mas) || trans_mas_cnt)));
1085 
1086  button = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON);
1087  gtk_widget_set_sensitive(button, sensitive);
1088 }
1089 
1090 static void
1091 gppat_populate_gas_list(GtkWidget *dialog,
1092  GNCAccountSel *gas,
1093  gboolean exclude_subaccounts)
1094 {
1095  Account *account;
1096  GList *filter;
1097 
1098  g_return_if_fail(GTK_IS_DIALOG(dialog));
1099  if (gas == NULL)
1100  return;
1101  account = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT);
1102  filter = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER);
1103 
1104  /* Setting the account type filter triggers GNCAccountSel population. */
1105  gnc_account_sel_set_acct_filters (gas, filter, NULL);
1106 
1107  /* Accounts to be deleted must be removed. */
1108  gnc_account_sel_purge_account( gas, account, exclude_subaccounts);
1109 
1110  /* The sensitivity of the OK button needs to be reevaluated. */
1111  set_ok_sensitivity(dialog);
1112 }
1113 
1114 void
1115 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb,
1116  GtkWidget *dialog)
1117 {
1118  GtkWidget *trans_mas;
1119 
1120  g_return_if_fail(GTK_IS_DIALOG(dialog));
1121 
1122  /* Cannot move transactions to subaccounts if they are to be deleted. */
1123  trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS);
1124  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb));
1125 }
1126 
1127 /* Note that the emitting object (the toggle button) and the signal data
1128  * are swapped in below callback function. This is a gtkbuilder feature:
1129  * it swaps if you explicitly set an object for a signal handler in the
1130  * gtkbuilder xml file.
1131  */
1132 void
1133 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b)
1134 {
1135  gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b));
1136  set_ok_sensitivity(gtk_widget_get_toplevel(widget));
1137 }
1138 
1139 static void
1140 gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page)
1141 {
1143  gchar *acct_name;
1144  delete_helper_t delete_res = { FALSE, FALSE };
1145  GtkWidget *window;
1146  GtkWidget *trans_mas = NULL; /* transaction move to account selector */
1147  GtkWidget *sa_mas = NULL; /* subaccount move to account selector */
1148  GtkWidget *sa_trans_mas = NULL; /* subaccount's transaction move to account selector */
1149  Account *ta = NULL; /* transaction adopter */
1150  Account *saa = NULL; /* subaccount adopter */
1151  Account *sta = NULL; /* subaccount transaction adopter */
1152  GList *splits;
1153  GList* list;
1154  gint response;
1155 
1156  if (NULL == account)
1157  return;
1158 
1159  /* If the account has objects referring to it, show the list - the account can't be deleted until these
1160  references are dealt with. */
1161  list = qof_instance_get_referring_object_list(QOF_INSTANCE(account));
1162  if (list != NULL)
1163  {
1164 #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"
1165 
1166  gnc_ui_object_references_show( _(EXPLANATION), list);
1167  g_list_free(list);
1168  return;
1169  }
1170 
1171  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1172  acct_name = gnc_account_get_full_name(account);
1173  if (!acct_name)
1174  {
1175  acct_name = g_strdup (_("(no name)"));
1176  }
1177 
1178  splits = xaccAccountGetSplitList(account);
1179 
1180  /*
1181  * If the account has transactions or child accounts then conduct a
1182  * dialog to allow the user to specify what should be done with them.
1183  */
1184  if ((NULL != splits) || (gnc_account_n_children(account) > 0))
1185  {
1186  GList *filter = NULL;
1187  GtkBuilder *builder = NULL;
1188  GtkWidget *dialog = NULL;
1189  GtkWidget *box = NULL;
1190  GtkWidget *widget = NULL;
1191  gchar *title = NULL;
1192 
1193  builder = gtk_builder_new();
1194  gnc_builder_add_from_file (builder, "dialog-account.glade", "Delete Account");
1195 
1196  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Delete Account"));
1197  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
1198 
1199  widget = GTK_WIDGET(gtk_builder_get_object (builder, "header"));
1200  title = g_strdup_printf(_("Deleting account %s"), acct_name);
1201  gtk_label_set_text(GTK_LABEL(widget), title);
1202  g_free(title);
1203 
1204  widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON));
1205  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget);
1206 
1207  /*
1208  * Reparent only to accounts of the same
1209  * type as the one being deleted.
1210  */
1211  filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account));
1212  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter);
1213  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account);
1214 
1215  /*
1216  * Adjust the dialog based on whether the account has
1217  * transactions.
1218  */
1219  if (splits)
1220  {
1221  delete_helper_t delete_res2 = { FALSE, FALSE };
1222 
1223  trans_mas = gnc_account_sel_new();
1224  box = GTK_WIDGET(gtk_builder_get_object (builder, "trans_mas_hbox"));
1225  gtk_box_pack_start (GTK_BOX(box), trans_mas, TRUE, TRUE, 0);
1226  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS, trans_mas);
1227  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), FALSE);
1228 
1229  delete_account_helper(account, &delete_res2);
1230  if (delete_res2.has_ro_splits)
1231  {
1232  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw")));
1233  widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb"));
1234  gtk_widget_set_sensitive(widget, FALSE);
1235  }
1236  else
1237  {
1238  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro")));
1239  }
1240  }
1241  else
1242  {
1243  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "transactions")));
1244  }
1245 
1246  /*
1247  * Adjust the dialog based on whether the account has children.
1248  */
1249  if (gnc_account_n_children(account) > 0)
1250  {
1251  /*
1252  * Check for RO txns in descendants
1253  */
1254  gnc_account_foreach_descendant_until(account, delete_account_helper,
1255  &delete_res);
1256  if (delete_res.has_ro_splits)
1257  {
1258  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw")));
1259  widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb"));
1260  gtk_widget_set_sensitive(widget, FALSE);
1261  }
1262  else if (delete_res.has_splits)
1263  {
1264  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro")));
1265  }
1266  else
1267  {
1268  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1269  }
1270 
1271  sa_mas = gnc_account_sel_new();
1272  box = GTK_WIDGET(gtk_builder_get_object (builder, "sa_mas_hbox"));
1273  gtk_box_pack_start (GTK_BOX(box), sa_mas, TRUE, TRUE, 0);
1274  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS, sa_mas);
1275  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(sa_mas), TRUE);
1276 
1277  sa_trans_mas = gnc_account_sel_new();
1278  box = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_mas_hbox"));
1279  gtk_box_pack_start (GTK_BOX(box), sa_trans_mas, TRUE, TRUE, 0);
1280  g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS_MAS, sa_trans_mas);
1281  gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(sa_trans_mas), TRUE);
1282  }
1283  else
1284  {
1285  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts")));
1286  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans")));
1287  }
1288 
1289  /* default to cancel */
1290  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1291 
1292  gtk_builder_connect_signals(builder, dialog);
1293  g_object_unref(G_OBJECT(builder));
1294 
1295  /*
1296  * Note that one effect of the modal dialog is preventing
1297  * the account selectors from being repopulated.
1298  */
1299  gtk_widget_show_all(dialog);
1300  response = gtk_dialog_run(GTK_DIALOG(dialog));
1301  if (GTK_RESPONSE_ACCEPT != response)
1302  {
1303  /* Account deletion is cancelled, so clean up and return. */
1304  gtk_widget_destroy(dialog);
1305  g_list_free(filter);
1306  g_free(acct_name);
1307  return;
1308  }
1309  if (trans_mas && gtk_widget_is_sensitive(trans_mas))
1310  ta = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(trans_mas));
1311  if (sa_mas && gtk_widget_is_sensitive(sa_mas))
1312  saa = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(sa_mas));
1313  if (sa_trans_mas && gtk_widget_is_sensitive(sa_trans_mas))
1314  sta = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(sa_trans_mas));
1315  gtk_widget_destroy(dialog);
1316  g_list_free(filter);
1317  } /* (NULL != splits) || (NULL != children) */
1318 
1319  /*
1320  * Present a message to the user which specifies what will be
1321  * deleted and what will be reparented, then ask for verification.
1322  */
1323  {
1324  const char *format = _("The account %s will be deleted.");
1325  char *lines[8];
1326  char *message;
1327  char *name;
1328  int i = 0;
1329  GtkWidget *dialog;
1330 
1331  lines[0] = g_strdup_printf(format, acct_name);
1332  if (splits)
1333  {
1334  if (ta)
1335  {
1336  name = gnc_account_get_full_name(ta);
1337  format = _("All transactions in this account will be moved to "
1338  "the account %s.");
1339  lines[++i] = g_strdup_printf(format, name);
1340  }
1341  else if (splits)
1342  {
1343  format = _("All transactions in this account will be deleted.");
1344  lines[++i] = g_strdup_printf("%s", format);
1345  }
1346  }
1347  if (gnc_account_n_children(account) > 0)
1348  {
1349  if (saa)
1350  {
1351  name = gnc_account_get_full_name(saa);
1352  format = _("All of its sub-accounts will be moved to "
1353  "the account %s.");
1354  lines[++i] = g_strdup_printf(format, name);
1355  }
1356  else
1357  {
1358  format = _("All of its subaccounts will be deleted.");
1359  lines[++i] = g_strdup_printf("%s", format);
1360  if (sta)
1361  {
1362  name = gnc_account_get_full_name(sta);
1363  format = _("All sub-account transactions will be moved to "
1364  "the account %s.");
1365  lines[++i] = g_strdup_printf(format, name);
1366  }
1367  else if (delete_res.has_splits)
1368  {
1369  format = _("All sub-account transactions will be deleted.");
1370  lines[++i] = g_strdup_printf("%s", format);
1371  }
1372  }
1373  }
1374  lines[++i] = _("Are you sure you want to do this?");
1375  lines[i] = NULL;
1376  i--; /* Don't try to free the constant question. */
1377  message = g_strjoinv(" ", lines);
1378  while (i--)
1379  {
1380  g_free(lines[i]);
1381  }
1382 
1383  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
1384  GTK_DIALOG_DESTROY_WITH_PARENT,
1385  GTK_MESSAGE_QUESTION,
1386  GTK_BUTTONS_NONE,
1387  "%s", message);
1388  g_free(message);
1389  gtk_dialog_add_buttons(GTK_DIALOG(dialog),
1390  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1391  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
1392  (gchar *)NULL);
1393  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
1394  response = gtk_dialog_run(GTK_DIALOG(dialog));
1395  gtk_widget_destroy(dialog);
1396 
1397  if (GTK_RESPONSE_ACCEPT == response)
1398  {
1399  GList *acct_list, *ptr;
1400  const GncGUID *guid;
1401  gchar guidstr[GUID_ENCODING_LENGTH+1];
1402 
1403  gnc_set_busy_cursor(NULL, TRUE);
1404  gnc_suspend_gui_refresh ();
1405 
1406  /* Move subaccounts and transactions if this was requested */
1407  xaccAccountBeginEdit (account);
1408  if (NULL != saa)
1409  {
1410 
1411  xaccAccountBeginEdit (saa);
1412  acct_list = gnc_account_get_children(account);
1413  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1414  gnc_account_append_child (saa, ptr->data);
1415  g_list_free(acct_list);
1416  xaccAccountCommitEdit (saa);
1417  }
1418  else if (NULL != sta)
1419  {
1420  /* Move the splits of its subaccounts, if any. */
1422  (AccountCb)xaccAccountMoveAllSplits,
1423  sta);
1424  }
1425  if (NULL != ta)
1426  {
1427  /* Move the splits of the account to be deleted. */
1428  xaccAccountMoveAllSplits (account, ta);
1429  }
1430  xaccAccountCommitEdit (account);
1431 
1432  /* Drop all references from the state file for
1433  * any subaccount the account still has
1434  */
1435  acct_list = gnc_account_get_children(account);
1436  for (ptr = acct_list; ptr; ptr = g_list_next(ptr))
1437  {
1438  guid = xaccAccountGetGUID (ptr->data);
1439  guid_to_string_buff (guid, guidstr);
1440  gnc_state_drop_sections_for (guidstr);
1441  }
1442  g_list_free(acct_list);
1443 
1444  /* Drop all references from the state file for this account
1445  */
1446  guid = xaccAccountGetGUID (account);
1447  guid_to_string_buff (guid, guidstr);
1448  gnc_state_drop_sections_for (guidstr);
1449 
1450  /*
1451  * Finally, delete the account, any subaccounts it may still
1452  * have, and any splits it or its subaccounts may still have.
1453  */
1454  xaccAccountBeginEdit (account);
1455  xaccAccountDestroy (account);
1456  gnc_resume_gui_refresh ();
1457  gnc_unset_busy_cursor(NULL);
1458  }
1459  }
1460  g_free(acct_name);
1461 }
1462 
1463 static void
1464 gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action,
1466 {
1467  Account *account;
1468  GtkWidget *window;
1469 
1470  window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page));
1472  if (!window || !account)
1473  return;
1474 
1475  gnc_account_renumber_create_dialog(window, account);
1476 }
1477 
1478 /*********************/
1479 
1480 static void
1481 gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action,
1483 {
1485 
1486  g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page));
1487  ENTER("(action %p, page %p)", action, page);
1488 
1489  priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page);
1490  account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page));
1491  LEAVE(" ");
1492 }
1493 
1494 static void
1495 gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action,
1497 {
1498  GtkWidget *window;
1499  Account *account;
1500  RecnWindow *recnData;
1501 
1503  g_return_if_fail (account != NULL);
1504 
1505  window = GNC_PLUGIN_PAGE (page)->window;
1506  recnData = recnWindow (window, account);
1507  gnc_ui_reconcile_window_raise (recnData);
1508 }
1509 
1510 static void
1511 gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action,
1513 {
1514  GtkWidget *window;
1515  Account *account;
1516  AutoClearWindow *autoClearData;
1517 
1519  g_return_if_fail (account != NULL);
1520 
1521  window = GNC_PLUGIN_PAGE (page)->window;
1522  autoClearData = autoClearWindow (window, account);
1523  gnc_ui_autoclear_window_raise (autoClearData);
1524 }
1525 
1526 static void
1527 gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action,
1529 {
1530  GtkWidget *window;
1531  Account *account;
1532 
1534  window = GNC_PLUGIN_PAGE (page)->window;
1535  gnc_xfer_dialog (window, account);
1536 }
1537 
1538 static void
1539 gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action,
1541 {
1542  GtkWidget *window;
1543  Account *account;
1544 
1546  window = GNC_PLUGIN_PAGE (page)->window;
1547  gnc_stock_split_dialog (window, account);
1548 }
1549 
1550 static void
1551 gnc_plugin_page_account_tree_cmd_lots (GtkAction *action,
1553 {
1554  Account *account;
1555 
1557  gnc_lot_viewer_dialog (account);
1558 }
1559 
1560 static void
1561 gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page)
1562 {
1564 
1565  g_return_if_fail (account != NULL);
1566 
1567  gnc_suspend_gui_refresh ();
1568 
1569  xaccAccountScrubOrphans (account);
1570  xaccAccountScrubImbalance (account);
1571 
1572  // XXX: Lots/capital gains scrubbing is disabled
1573  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1574  xaccAccountScrubLots(account);
1575 
1576  gncScrubBusinessAccountLots(account);
1577 
1578 
1579  gnc_resume_gui_refresh ();
1580 }
1581 
1582 static void
1583 gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page)
1584 {
1586 
1587  g_return_if_fail (account != NULL);
1588 
1589  gnc_suspend_gui_refresh ();
1590 
1591  xaccAccountTreeScrubOrphans (account);
1592  xaccAccountTreeScrubImbalance (account);
1593 
1594  // XXX: Lots/capital gains scrubbing is disabled
1595  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1596  xaccAccountTreeScrubLots(account);
1597 
1599 
1600  gnc_resume_gui_refresh ();
1601 }
1602 
1603 static void
1604 gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page)
1605 {
1606  Account *root = gnc_get_current_root_account ();
1607 
1608  gnc_suspend_gui_refresh ();
1609 
1611  xaccAccountTreeScrubImbalance (root);
1612  // XXX: Lots/capital gains scrubbing is disabled
1613  if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
1614  xaccAccountTreeScrubLots(root);
1615 
1617 
1618  gnc_resume_gui_refresh ();
1619 }
1620 
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Account * gnc_plugin_page_account_tree_get_current_account(GncPluginPageAccountTree *page)
Functions to load, save and get gui state.
High-Level API for imposing Lot constraints.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
const gchar * tab_icon
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
const GList * gnc_gobject_tracking_get_list(const gchar *name)
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
gboolean gnc_main_window_button_press_cb(GtkWidget *whatever, GdkEventButton *event, GncPluginPage *page)
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
Dialog for create/edit an account.
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
GncPluginPage * gnc_plugin_page_account_tree_new(void)
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
void gncScrubBusinessAccountLots(Account *acc)
gint gnc_state_drop_sections_for(const gchar *partial_name)
Definition: gnc-state.c:264
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
Definition: Account.c:2979
GncPluginPage * gnc_plugin_page_register2_new(Account *account, gboolean subaccounts)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
void xaccAccountScrubLots(Account *acc)
Definition: Scrub3.c:159
void xaccAccountMoveAllSplits(Account *accfrom, Account *accto)
Definition: Account.c:1980
GtkActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
GtkTreeViewColumn * gnc_tree_view_find_column_by_name(GncTreeView *view, const gchar *wanted)
#define ENTER(format, args...)
Definition: qoflog.h:261
Cleanup functions for business objects.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
void gnc_ui_edit_account_window(Account *account)
Definition: guid.h:65
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
#define xaccAccountGetGUID(X)
Definition: Account.h:239
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)
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
Functions providing a register page for the GnuCash UI.
Gobject helper routines.
GtkTreeView implementation for gnucash account tree.
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
void(* destroy_widget)(GncPluginPage *plugin_page)
void gnc_plugin_init_short_names(GtkActionGroup *action_group, action_toolbar_labels *toolbar_labels)
Definition: gnc-plugin.c:263
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
void gnc_tree_view_configure_columns(GncTreeView *view)
GType gnc_plugin_page_account_tree_get_type(void)
gboolean gnc_plugin_page_account_tree_filter_accounts(Account *account, gpointer user_data)
const gchar * plugin_name
void xaccAccountScrubOrphans(Account *acc)
Definition: Scrub.c:102
Account * gnc_tree_view_account_get_account_from_path(GncTreeViewAccount *view, GtkTreePath *s_path)
Gnome specific utility functions.
gint gnc_account_n_children(const Account *account)
Definition: Account.c:2676
const char * xaccTransGetReadOnly(const Transaction *trans)
Definition: Transaction.c:2313
All type declarations for the whole Gnucash engine.
GtkTreeModel implementation to display account types in a GtkTreeView.
GList * qof_instance_get_referring_object_list(const QofInstance *inst)
Generic api to store and retrieve preferences.
Functions providing a chart of account page.
gboolean qof_book_is_readonly(const QofBook *book)
void gnc_plugin_update_actions(GtkActionGroup *action_group, const gchar **action_names, const gchar *property_name, gboolean value)
Definition: gnc-plugin.c:313
GList * gnc_account_get_children(const Account *account)
Definition: Account.c:2654
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
void gnc_ui_new_account_window(QofBook *book, Account *parent)
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Provide the menus to create a chart of account page.
void gnc_main_window_close_page(GncPluginPage *page)
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
#define LEAVE(format, args...)
Definition: qoflog.h:271
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
void xaccAccountTreeScrubOrphans(Account *acc)
Definition: Scrub.c:62
GtkActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
void gncScrubBusinessAccountTreeLots(Account *acc)
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
GtkWidget * summarybar
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:148