|
GnuCash 2.4.99
|
00001 /* 00002 * gnc-plugin-page-account-tree.c -- 00003 * 00004 * Copyright (C) 2003 Jan Arne Petersen <jpetersen@uni-bonn.de> 00005 * Copyright (C) 2003,2005,2006 David Hampton <hampton@employees.org> 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License as 00009 * published by the Free Software Foundation; either version 2 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, contact: 00019 * 00020 * Free Software Foundation Voice: +1-617-542-5942 00021 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 00022 * Boston, MA 02110-1301, USA gnu@gnu.org 00023 */ 00024 00035 #include "config.h" 00036 00037 #include <gtk/gtk.h> 00038 #include <glib/gi18n.h> 00039 #include "gnc-plugin-page-account-tree.h" 00040 #include "gnc-plugin-page-register.h" 00041 00042 #include "Scrub.h" 00043 #include "Scrub3.h" 00044 #include "Transaction.h" 00045 #include "dialog-account.h" 00046 #include "dialog-transfer.h" 00047 #include "dialog-utils.h" 00048 #include "assistant-hierarchy.h" 00049 #include "gnc-account-sel.h" 00050 #include "gnc-component-manager.h" 00051 #include "gnc-engine.h" 00052 #include "gnc-gconf-utils.h" 00053 #include "gnc-gnome-utils.h" 00054 #include "gnc-gobject-utils.h" 00055 #include "gnc-icons.h" 00056 #include "gnc-plugin-account-tree.h" 00057 #include "gnc-session.h" 00058 #include "gnc-split-reg.h" 00059 #include "gnc-tree-view-account.h" 00060 #include "gnc-tree-model-account-types.h" 00061 #include "gnc-ui.h" 00062 #include "gnc-ui-util.h" 00063 #include "dialog-lot-viewer.h" 00064 #include "window-reconcile.h" 00065 #include "window-autoclear.h" 00066 #include "window-main-summarybar.h" 00067 #include "dialog-object-references.h" 00068 00069 /* This static indicates the debugging module that this .o belongs to. */ 00070 static QofLogModule log_module = GNC_MOD_GUI; 00071 00072 #define PLUGIN_PAGE_ACCT_TREE_CM_CLASS "plugin-page-acct-tree" 00073 #define GCONF_SECTION "window/pages/account_tree" 00074 00075 #define DELETE_DIALOG_FILTER "filter" 00076 #define DELETE_DIALOG_ACCOUNT "account" 00077 #define DELETE_DIALOG_TRANS_MAS "trans_mas" 00078 #define DELETE_DIALOG_SA_MAS "sa_mas" 00079 #define DELETE_DIALOG_SA_TRANS_MAS "sa_trans_mas" 00080 #define DELETE_DIALOG_OK_BUTTON "deletebutton" 00081 00082 enum 00083 { 00084 ACCOUNT_SELECTED, 00085 LAST_SIGNAL 00086 }; 00087 00088 typedef struct GncPluginPageAccountTreePrivate 00089 { 00090 GtkWidget *widget; 00091 GtkTreeView *tree_view; 00092 gint component_id; 00093 AccountFilterDialog fd; 00094 } GncPluginPageAccountTreePrivate; 00095 00096 #define GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(o) \ 00097 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, GncPluginPageAccountTreePrivate)) 00098 00099 static GObjectClass *parent_class = NULL; 00100 00101 /************************************************************ 00102 * Prototypes * 00103 ************************************************************/ 00104 /* Plugin Actions */ 00105 static void gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass); 00106 static void gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page); 00107 static void gnc_plugin_page_account_tree_finalize (GObject *object); 00108 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data); 00109 00110 static GtkWidget *gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page); 00111 static void gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page); 00112 static void gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group); 00113 static GncPluginPage *gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group); 00114 00115 /* Callbacks */ 00116 static void gnc_plugin_page_account_tree_summarybar_position_changed(GConfEntry *entry, 00117 gpointer user_data); 00118 static gboolean gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget, 00119 GdkEventButton *event, 00120 GncPluginPage *page); 00121 static void gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview, 00122 GtkTreePath *path, 00123 GtkTreeViewColumn *col, 00124 GncPluginPageAccountTree *page); 00125 00126 static void gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection, 00127 GncPluginPageAccountTree *page); 00128 void gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb, GtkWidget *dialog); 00129 void gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b); 00130 00131 /* Command callbacks */ 00132 static void gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *plugin_page); 00133 static void gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *plugin_page); 00134 static void gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action, GncPluginPageAccountTree *page); 00135 static void gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action, GncPluginPageAccountTree *page); 00136 static void gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page); 00137 static void gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page); 00138 static void gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action, GncPluginPageAccountTree *page); 00139 static void gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action, GncPluginPageAccountTree *plugin_page); 00140 static void gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action, GncPluginPageAccountTree *page); 00141 static void gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action, GncPluginPageAccountTree *page); 00142 static void gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action, GncPluginPageAccountTree *page); 00143 static void gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action, GncPluginPageAccountTree *page); 00144 static void gnc_plugin_page_account_tree_cmd_lots (GtkAction *action, GncPluginPageAccountTree *page); 00145 static void gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page); 00146 static void gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page); 00147 static void gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page); 00148 00149 00150 static guint plugin_page_signals[LAST_SIGNAL] = { 0 }; 00151 00152 00153 static GtkActionEntry gnc_plugin_page_account_tree_actions [] = 00154 { 00155 /* Toplevel */ 00156 { "FakeToplevel", NULL, "", NULL, NULL, NULL }, 00157 00158 /* File menu */ 00159 { 00160 "FileNewAccountAction", GNC_STOCK_NEW_ACCOUNT, N_("New _Account..."), NULL, 00161 N_("Create a new Account"), 00162 G_CALLBACK (gnc_plugin_page_account_tree_cmd_new_account) 00163 }, 00164 { 00165 "FileAddAccountHierarchyAssistantAction", GNC_STOCK_NEW_ACCOUNT, N_("New Account _Hierarchy..."), NULL, 00166 N_("Extend the current book by merging with new account type categories"), 00167 G_CALLBACK (gnc_plugin_page_account_tree_cmd_file_new_hierarchy) 00168 }, 00169 { 00170 "FileOpenAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL, 00171 N_("Open the selected account"), 00172 G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_account) 00173 }, 00174 { 00175 "FileOpenSubaccountsAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Subaccounts"), NULL, 00176 N_("Open the selected account and all its subaccounts"), 00177 G_CALLBACK (gnc_plugin_page_account_tree_cmd_open_subaccounts) 00178 }, 00179 00180 /* Edit menu */ 00181 { 00182 "EditEditAccountAction", GNC_STOCK_EDIT_ACCOUNT, N_("Edit _Account"), "<control>e", 00183 N_("Edit the selected account"), 00184 G_CALLBACK (gnc_plugin_page_account_tree_cmd_edit_account) 00185 }, 00186 { 00187 "EditDeleteAccountAction", GNC_STOCK_DELETE_ACCOUNT, N_("_Delete Account..."), "Delete", 00188 N_("Delete selected account"), 00189 G_CALLBACK (gnc_plugin_page_account_tree_cmd_delete_account) 00190 }, 00191 { 00192 "EditRenumberSubaccountsAction", NULL, N_("_Renumber Subaccounts..."), NULL, 00193 N_("Renumber the children of the selected account"), 00194 G_CALLBACK (gnc_plugin_page_account_tree_cmd_renumber_accounts) 00195 }, 00196 00197 /* View menu */ 00198 { 00199 "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, NULL, 00200 G_CALLBACK (gnc_plugin_page_account_tree_cmd_view_filter_by) 00201 }, 00202 00203 /* Actions menu */ 00204 { 00205 "ActionsReconcileAction", NULL, N_("_Reconcile..."), NULL, 00206 N_("Reconcile the selected account"), 00207 G_CALLBACK (gnc_plugin_page_account_tree_cmd_reconcile) 00208 }, 00209 { 00210 "ActionsAutoClearAction", NULL, N_("_Auto-clear..."), NULL, 00211 N_("Automatically clear individual transactions, given a cleared amount"), 00212 G_CALLBACK (gnc_plugin_page_account_tree_cmd_autoclear) 00213 }, 00214 { 00215 "ActionsTransferAction", NULL, N_("_Transfer..."), "<control>t", 00216 N_("Transfer funds from one account to another"), 00217 G_CALLBACK (gnc_plugin_page_account_tree_cmd_transfer) 00218 }, 00219 { 00220 "ActionsStockSplitAction", NULL, N_("Stoc_k Split..."), NULL, 00221 N_("Record a stock split or a stock merger"), 00222 G_CALLBACK (gnc_plugin_page_account_tree_cmd_stock_split) 00223 }, 00224 { 00225 "ActionsLotsAction", NULL, N_("View _Lots..."), NULL, 00226 N_("Bring up the lot viewer/editor window"), 00227 G_CALLBACK (gnc_plugin_page_account_tree_cmd_lots) 00228 }, 00229 { 00230 "ScrubAction", NULL, N_("Check & Repair A_ccount"), NULL, 00231 N_("Check for and repair unbalanced transactions and orphan splits " "in this account"), 00232 G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub) 00233 }, 00234 { 00235 "ScrubSubAction", NULL, N_("Check & Repair Su_baccounts"), NULL, 00236 N_("Check for and repair unbalanced transactions and orphan splits " 00237 "in this account and its subaccounts"), 00238 G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_sub) 00239 }, 00240 { 00241 "ScrubAllAction", NULL, N_("Check & Repair A_ll"), NULL, 00242 N_("Check for and repair unbalanced transactions and orphan splits " "in all accounts"), 00243 G_CALLBACK (gnc_plugin_page_account_tree_cmd_scrub_all) 00244 }, 00245 }; 00247 static guint gnc_plugin_page_account_tree_n_actions = G_N_ELEMENTS (gnc_plugin_page_account_tree_actions); 00248 00249 00252 static const gchar *actions_requiring_account_rw[] = 00253 { 00254 "EditEditAccountAction", 00255 "EditDeleteAccountAction", 00256 "ActionsReconcileAction", 00257 "ActionsAutoClearAction", 00258 NULL 00259 }; 00260 00263 static const gchar *actions_requiring_account_always[] = 00264 { 00265 "FileOpenAccountAction", 00266 "FileOpenSubaccountsAction", 00267 "ActionsLotsAction", 00268 NULL 00269 }; 00270 00271 /* This is the list of actions which are switched inactive in a read-only book. */ 00272 static const gchar* readonly_inactive_actions[] = 00273 { 00274 "FileNewAccountAction", 00275 "FileAddAccountHierarchyAssistantAction", 00276 "EditEditAccountAction", 00277 "EditDeleteAccountAction", 00278 "EditRenumberSubaccountsAction", 00279 "ActionsTransferAction", 00280 "ActionsReconcileAction", 00281 "ActionsAutoClearAction", 00282 "ActionsStockSplitAction", 00283 "ScrubAction", 00284 "ScrubSubAction", 00285 "ScrubAllAction", 00286 NULL 00287 }; 00288 00290 static action_toolbar_labels toolbar_labels[] = 00291 { 00292 { "FileOpenAccountAction", N_("Open") }, 00293 { "EditEditAccountAction", N_("Edit") }, 00294 { "FileNewAccountAction", N_("New") }, 00295 { "EditDeleteAccountAction", N_("Delete") }, 00296 { NULL, NULL }, 00297 }; 00298 00299 00300 GType 00301 gnc_plugin_page_account_tree_get_type (void) 00302 { 00303 static GType gnc_plugin_page_account_tree_type = 0; 00304 00305 if (gnc_plugin_page_account_tree_type == 0) 00306 { 00307 static const GTypeInfo our_info = 00308 { 00309 sizeof (GncPluginPageAccountTreeClass), 00310 NULL, 00311 NULL, 00312 (GClassInitFunc) gnc_plugin_page_account_tree_class_init, 00313 NULL, 00314 NULL, 00315 sizeof (GncPluginPageAccountTree), 00316 0, 00317 (GInstanceInitFunc) gnc_plugin_page_account_tree_init 00318 }; 00319 00320 gnc_plugin_page_account_tree_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE, 00321 GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME, 00322 &our_info, 0); 00323 } 00324 00325 return gnc_plugin_page_account_tree_type; 00326 } 00327 00328 GncPluginPage * 00329 gnc_plugin_page_account_tree_new (void) 00330 { 00331 GncPluginPageAccountTree *plugin_page; 00332 00333 ENTER(" "); 00334 plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_ACCOUNT_TREE, 00335 NULL); 00336 00337 LEAVE("new account tree page %p", plugin_page); 00338 return GNC_PLUGIN_PAGE (plugin_page); 00339 } 00340 00341 static void 00342 gnc_plugin_page_account_tree_class_init (GncPluginPageAccountTreeClass *klass) 00343 { 00344 GObjectClass *object_class = G_OBJECT_CLASS (klass); 00345 GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass); 00346 00347 parent_class = g_type_class_peek_parent (klass); 00348 00349 object_class->finalize = gnc_plugin_page_account_tree_finalize; 00350 00351 gnc_plugin_class->tab_icon = GNC_STOCK_ACCOUNT; 00352 gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME; 00353 gnc_plugin_class->create_widget = gnc_plugin_page_account_tree_create_widget; 00354 gnc_plugin_class->destroy_widget = gnc_plugin_page_account_tree_destroy_widget; 00355 gnc_plugin_class->save_page = gnc_plugin_page_account_tree_save_page; 00356 gnc_plugin_class->recreate_page = gnc_plugin_page_account_tree_recreate_page; 00357 00358 g_type_class_add_private(klass, sizeof(GncPluginPageAccountTreePrivate)); 00359 00360 plugin_page_signals[ACCOUNT_SELECTED] = 00361 g_signal_new ("account_selected", 00362 G_OBJECT_CLASS_TYPE (object_class), 00363 G_SIGNAL_RUN_FIRST, 00364 G_STRUCT_OFFSET (GncPluginPageAccountTreeClass, account_selected), 00365 NULL, NULL, 00366 g_cclosure_marshal_VOID__POINTER, 00367 G_TYPE_NONE, 1, 00368 G_TYPE_POINTER); 00369 } 00370 00371 static void 00372 gnc_plugin_page_account_tree_init (GncPluginPageAccountTree *plugin_page) 00373 { 00374 GtkActionGroup *action_group; 00375 GncPluginPageAccountTreePrivate *priv; 00376 GncPluginPage *parent; 00377 const GList *page_list; 00378 00379 ENTER("page %p", plugin_page); 00380 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(plugin_page); 00381 00382 /* Init parent declared variables */ 00383 parent = GNC_PLUGIN_PAGE(plugin_page); 00384 g_object_set(G_OBJECT(plugin_page), 00385 "page-name", _("Accounts"), 00386 "page-uri", "default:", 00387 "ui-description", "gnc-plugin-page-account-tree-ui.xml", 00388 NULL); 00389 g_signal_connect (G_OBJECT (plugin_page), "selected", 00390 G_CALLBACK (gnc_plugin_page_account_tree_selected), plugin_page); 00391 00392 /* change me when the system supports multiple books */ 00393 gnc_plugin_page_add_book(parent, gnc_get_current_book()); 00394 00395 /* Is this the first accounts page? */ 00396 page_list = 00397 gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME); 00398 if (plugin_page == page_list->data) 00399 { 00400 g_object_set_data(G_OBJECT(plugin_page), PLUGIN_PAGE_IMMUTABLE, 00401 GINT_TO_POINTER(1)); 00402 } 00403 00404 /* Create menu and toolbar information */ 00405 action_group = 00406 gnc_plugin_page_create_action_group(parent, 00407 "GncPluginPageAccountTreeActions"); 00408 gtk_action_group_add_actions(action_group, 00409 gnc_plugin_page_account_tree_actions, 00410 gnc_plugin_page_account_tree_n_actions, 00411 plugin_page); 00412 gnc_plugin_init_short_names (action_group, toolbar_labels); 00413 00414 /* Visible types */ 00415 priv->fd.visible_types = -1; /* Start with all types */ 00416 priv->fd.show_hidden = FALSE; 00417 priv->fd.show_zero_total = TRUE; 00418 00419 LEAVE("page %p, priv %p, action group %p", 00420 plugin_page, priv, action_group); 00421 } 00422 00423 static void 00424 gnc_plugin_page_account_tree_finalize (GObject *object) 00425 { 00426 GncPluginPageAccountTree *page; 00427 GncPluginPageAccountTreePrivate *priv; 00428 00429 ENTER("object %p", object); 00430 page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (object); 00431 g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page)); 00432 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00433 g_return_if_fail (priv != NULL); 00434 00435 G_OBJECT_CLASS (parent_class)->finalize (object); 00436 LEAVE(" "); 00437 } 00438 00439 Account * 00440 gnc_plugin_page_account_tree_get_current_account (GncPluginPageAccountTree *page) 00441 { 00442 GncPluginPageAccountTreePrivate *priv; 00443 Account *account; 00444 00445 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00446 ENTER("page %p (tree view %p)", page, priv->tree_view); 00447 account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(priv->tree_view)); 00448 if (account == NULL) 00449 { 00450 LEAVE("no account"); 00451 return NULL; 00452 } 00453 00454 LEAVE("account %p", account); 00455 return account; 00456 } 00457 00458 00459 /* Virtual Functions */ 00460 00461 static void 00462 gnc_plugin_page_account_refresh_cb (GHashTable *changes, gpointer user_data) 00463 { 00464 GncPluginPageAccountTree *page = user_data; 00465 GncPluginPageAccountTreePrivate *priv; 00466 00467 g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page)); 00468 00469 /* We're only looking for forced updates here. */ 00470 if (changes) 00471 return; 00472 00473 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00474 gtk_widget_queue_draw(priv->widget); 00475 } 00476 00477 static void 00478 gnc_plugin_page_account_tree_close_cb (gpointer user_data) 00479 { 00480 GncPluginPage *plugin_page; 00481 GncPluginPageAccountTree *page; 00482 00483 plugin_page = GNC_PLUGIN_PAGE(user_data); 00484 page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page); 00485 gnc_main_window_close_page(plugin_page); 00486 } 00487 00488 static GtkWidget * 00489 gnc_plugin_page_account_tree_create_widget (GncPluginPage *plugin_page) 00490 { 00491 GncPluginPageAccountTree *page; 00492 GncPluginPageAccountTreePrivate *priv; 00493 GtkTreeSelection *selection; 00494 GtkTreeView *tree_view; 00495 GtkWidget *scrolled_window; 00496 GtkTreeViewColumn *col; 00497 00498 ENTER("page %p", plugin_page); 00499 page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page); 00500 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00501 if (priv->widget != NULL) 00502 { 00503 LEAVE("widget = %p", priv->widget); 00504 return priv->widget; 00505 } 00506 00507 priv->widget = gtk_vbox_new (FALSE, 0); 00508 gtk_widget_show (priv->widget); 00509 00510 scrolled_window = gtk_scrolled_window_new (NULL, NULL); 00511 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), 00512 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 00513 gtk_widget_show (scrolled_window); 00514 gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window, 00515 TRUE, TRUE, 0); 00516 00517 tree_view = gnc_tree_view_account_new(FALSE); 00518 col = gnc_tree_view_find_column_by_name( 00519 GNC_TREE_VIEW(tree_view), "description"); 00520 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); 00521 col = gnc_tree_view_find_column_by_name( 00522 GNC_TREE_VIEW(tree_view), "total"); 00523 g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); 00524 gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view)); 00525 g_object_set(G_OBJECT(tree_view), 00526 "gconf-section", GCONF_SECTION, 00527 "show-column-menu", TRUE, 00528 NULL); 00529 00530 /* No name handler; then the user can't click on the name of the 00531 account to open its register. */ 00532 gnc_tree_view_account_set_code_edited(GNC_TREE_VIEW_ACCOUNT(tree_view), 00533 gnc_tree_view_account_code_edited_cb); 00534 gnc_tree_view_account_set_description_edited(GNC_TREE_VIEW_ACCOUNT(tree_view), 00535 gnc_tree_view_account_description_edited_cb); 00536 gnc_tree_view_account_set_notes_edited(GNC_TREE_VIEW_ACCOUNT(tree_view), 00537 gnc_tree_view_account_notes_edited_cb); 00538 00539 priv->tree_view = tree_view; 00540 selection = gtk_tree_view_get_selection(tree_view); 00541 g_signal_connect (G_OBJECT (selection), "changed", 00542 G_CALLBACK (gnc_plugin_page_account_tree_selection_changed_cb), page); 00543 g_signal_connect (G_OBJECT (tree_view), "button-press-event", 00544 G_CALLBACK (gnc_plugin_page_account_tree_button_press_cb), page); 00545 g_signal_connect (G_OBJECT (tree_view), "row-activated", 00546 G_CALLBACK (gnc_plugin_page_account_tree_double_click_cb), page); 00547 00548 gtk_tree_view_set_headers_visible(tree_view, TRUE); 00549 gnc_plugin_page_account_tree_selection_changed_cb (NULL, page); 00550 gtk_widget_show (GTK_WIDGET (tree_view)); 00551 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(tree_view)); 00552 00553 priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view); 00554 gnc_tree_view_account_set_filter ( 00555 GNC_TREE_VIEW_ACCOUNT(tree_view), 00556 gnc_plugin_page_account_tree_filter_accounts, &priv->fd, NULL); 00557 00558 priv->component_id = 00559 gnc_register_gui_component(PLUGIN_PAGE_ACCT_TREE_CM_CLASS, 00560 gnc_plugin_page_account_refresh_cb, 00561 gnc_plugin_page_account_tree_close_cb, 00562 page); 00563 gnc_gui_component_set_session (priv->component_id, 00564 gnc_get_current_session()); 00565 00566 plugin_page->summarybar = gnc_main_window_summary_new(); 00567 gtk_box_pack_start (GTK_BOX (priv->widget), plugin_page->summarybar, 00568 FALSE, FALSE, 0); 00569 gtk_widget_show(plugin_page->summarybar); 00570 gnc_plugin_page_account_tree_summarybar_position_changed(NULL, page); 00571 gnc_gconf_general_register_cb(KEY_SUMMARYBAR_POSITION, 00572 gnc_plugin_page_account_tree_summarybar_position_changed, 00573 page); 00574 00575 LEAVE("widget = %p", priv->widget); 00576 return priv->widget; 00577 } 00578 00579 static void 00580 gnc_plugin_page_account_tree_destroy_widget (GncPluginPage *plugin_page) 00581 { 00582 GncPluginPageAccountTree *page; 00583 GncPluginPageAccountTreePrivate *priv; 00584 00585 ENTER("page %p", plugin_page); 00586 page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (plugin_page); 00587 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00588 00589 gnc_gconf_general_remove_cb(KEY_SUMMARYBAR_POSITION, 00590 gnc_plugin_page_account_tree_summarybar_position_changed, 00591 page); 00592 00593 if (priv->widget) 00594 { 00595 g_object_unref(G_OBJECT(priv->widget)); 00596 priv->widget = NULL; 00597 } 00598 00599 if (priv->component_id) 00600 { 00601 gnc_unregister_gui_component(priv->component_id); 00602 priv->component_id = 0; 00603 } 00604 00605 LEAVE("widget destroyed"); 00606 } 00607 00608 static void update_inactive_actions(GncPluginPage *plugin_page) 00609 { 00610 GtkActionGroup *action_group; 00611 gboolean is_sensitive = !qof_book_is_readonly(gnc_get_current_book()); 00612 00613 // We are readonly - so we have to switch particular actions to inactive. 00614 g_return_if_fail(plugin_page); 00615 g_return_if_fail(GNC_IS_PLUGIN_PAGE(plugin_page)); 00616 00617 /* Get the action group */ 00618 action_group = gnc_plugin_page_get_action_group(plugin_page); 00619 g_return_if_fail(GTK_IS_ACTION_GROUP (action_group)); 00620 00621 /* Set the action's sensitivity */ 00622 gnc_plugin_update_actions (action_group, readonly_inactive_actions, 00623 "sensitive", is_sensitive); 00624 } 00625 00630 static void gnc_plugin_page_account_tree_selected (GObject *object, gpointer user_data) 00631 { 00632 GncPluginPage *plugin_page = GNC_PLUGIN_PAGE (object); 00633 g_return_if_fail (GNC_IS_PLUGIN_PAGE (plugin_page)); 00634 update_inactive_actions(plugin_page); 00635 } 00636 00646 static void 00647 gnc_plugin_page_account_tree_save_page (GncPluginPage *plugin_page, 00648 GKeyFile *key_file, 00649 const gchar *group_name) 00650 { 00651 GncPluginPageAccountTree *account_page; 00652 GncPluginPageAccountTreePrivate *priv; 00653 00654 g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page)); 00655 g_return_if_fail (key_file != NULL); 00656 g_return_if_fail (group_name != NULL); 00657 00658 ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file, 00659 group_name); 00660 00661 account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(plugin_page); 00662 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page); 00663 00664 gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), 00665 &priv->fd, key_file, group_name); 00666 LEAVE(" "); 00667 } 00668 00669 00670 00680 static GncPluginPage * 00681 gnc_plugin_page_account_tree_recreate_page (GtkWidget *window, 00682 GKeyFile *key_file, 00683 const gchar *group_name) 00684 { 00685 GncPluginPageAccountTree *account_page; 00686 GncPluginPageAccountTreePrivate *priv; 00687 GncPluginPage *page; 00688 00689 g_return_val_if_fail(key_file, NULL); 00690 g_return_val_if_fail(group_name, NULL); 00691 ENTER("key_file %p, group_name %s", key_file, group_name); 00692 00693 /* Create the new page. */ 00694 page = gnc_plugin_page_account_tree_new(); 00695 account_page = GNC_PLUGIN_PAGE_ACCOUNT_TREE(page); 00696 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(account_page); 00697 00698 /* Install it now so we can then manipulate the created widget */ 00699 gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page); 00700 00701 gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), 00702 &priv->fd, key_file, group_name); 00703 LEAVE(" "); 00704 return page; 00705 } 00706 00707 00708 /* Callbacks */ 00709 00710 static void 00711 gnc_plugin_page_account_tree_summarybar_position_changed(GConfEntry *entry, 00712 gpointer user_data) 00713 { 00714 GncPluginPage *plugin_page; 00715 GncPluginPageAccountTree *page; 00716 GncPluginPageAccountTreePrivate *priv; 00717 GtkPositionType position = GTK_POS_BOTTOM; 00718 gchar *conf_string; 00719 00720 g_return_if_fail(user_data != NULL); 00721 00722 plugin_page = GNC_PLUGIN_PAGE(user_data); 00723 page = GNC_PLUGIN_PAGE_ACCOUNT_TREE (user_data); 00724 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00725 00726 conf_string = gnc_gconf_get_string (GCONF_GENERAL, 00727 KEY_SUMMARYBAR_POSITION, NULL); 00728 if (conf_string) 00729 { 00730 position = gnc_enum_from_nick (GTK_TYPE_POSITION_TYPE, 00731 conf_string, GTK_POS_BOTTOM); 00732 g_free (conf_string); 00733 } 00734 00735 gtk_box_reorder_child(GTK_BOX(priv->widget), 00736 plugin_page->summarybar, 00737 (position == GTK_POS_TOP ? 0 : -1) ); 00738 } 00739 00747 static gboolean 00748 gnc_plugin_page_account_tree_button_press_cb (GtkWidget *widget, 00749 GdkEventButton *event, 00750 GncPluginPage *page) 00751 { 00752 gboolean result; 00753 00754 g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE); 00755 00756 ENTER("widget %p, event %p, page %p", widget, event, page); 00757 result = gnc_main_window_button_press_cb(widget, event, page); 00758 LEAVE(" "); 00759 00760 /* Always return FALSE. This will let the tree view callback run as 00761 * well which will select the item under the cursor. By the time 00762 * the user sees the menu both callbacks will have run and the menu 00763 * actions will operate on the just-selected account. */ 00764 return FALSE; 00765 } 00766 00767 static void 00768 gppat_open_account_common (GncPluginPageAccountTree *page, 00769 Account *account, 00770 gboolean include_subs) 00771 { 00772 GncPluginPageAccountTreePrivate *priv; 00773 GtkWidget *window; 00774 GncPluginPage *new_page; 00775 00776 if (account == NULL) 00777 return; 00778 00779 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 00780 window = GNC_PLUGIN_PAGE (page)->window; 00781 new_page = gnc_plugin_page_register_new (account, include_subs); 00782 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page); 00783 } 00784 00785 static void 00786 gnc_plugin_page_account_tree_double_click_cb (GtkTreeView *treeview, 00787 GtkTreePath *path, 00788 GtkTreeViewColumn *col, 00789 GncPluginPageAccountTree *page) 00790 { 00791 Account *account; 00792 00793 g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page)); 00794 account = gnc_tree_view_account_get_account_from_path (GNC_TREE_VIEW_ACCOUNT(treeview), path); 00795 gppat_open_account_common (page, account, FALSE); 00796 } 00797 00798 static void 00799 gnc_plugin_page_account_tree_selection_changed_cb (GtkTreeSelection *selection, 00800 GncPluginPageAccountTree *page) 00801 { 00802 GtkActionGroup *action_group; 00803 GtkAction *action; 00804 GtkTreeView *view; 00805 Account *account = NULL; 00806 gboolean sensitive; 00807 gboolean subaccounts; 00808 gboolean is_readwrite = !qof_book_is_readonly(gnc_get_current_book()); 00809 00810 g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page)); 00811 00812 if (!selection) 00813 { 00814 sensitive = FALSE; 00815 subaccounts = FALSE; 00816 } 00817 else 00818 { 00819 g_return_if_fail(GTK_IS_TREE_SELECTION(selection)); 00820 view = gtk_tree_selection_get_tree_view (selection); 00821 account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(view)); 00822 sensitive = (account != NULL); 00823 00824 subaccounts = account && (gnc_account_n_children(account) != 0); 00825 /* Check here for placeholder accounts, etc. */ 00826 } 00827 00828 action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(page)); 00829 gnc_plugin_update_actions (action_group, actions_requiring_account_rw, 00830 "sensitive", is_readwrite && sensitive); 00831 gnc_plugin_update_actions (action_group, actions_requiring_account_always, 00832 "sensitive", sensitive); 00833 g_signal_emit (page, plugin_page_signals[ACCOUNT_SELECTED], 0, account); 00834 00835 action = gtk_action_group_get_action (action_group, "EditRenumberSubaccountsAction"); 00836 g_object_set (G_OBJECT(action), "sensitive", 00837 is_readwrite && sensitive && subaccounts, NULL); 00838 00839 gnc_plugin_update_actions (action_group, actions_requiring_account_rw, 00840 "sensitive", is_readwrite && sensitive); 00841 gnc_plugin_update_actions (action_group, actions_requiring_account_always, 00842 "sensitive", sensitive); 00843 } 00844 00845 00846 /* Command callbacks */ 00847 static void 00848 gnc_plugin_page_account_tree_cmd_new_account (GtkAction *action, GncPluginPageAccountTree *page) 00849 { 00850 Account *account = gnc_plugin_page_account_tree_get_current_account (page); 00851 00852 gnc_ui_new_account_window (gnc_get_current_book(), account); 00853 } 00854 00855 static void 00856 gnc_plugin_page_account_tree_cmd_file_new_hierarchy (GtkAction *action, GncPluginPageAccountTree *page) 00857 { 00858 gnc_ui_hierarchy_assistant(FALSE); 00859 } 00860 00861 static void 00862 gnc_plugin_page_account_tree_cmd_open_account (GtkAction *action, 00863 GncPluginPageAccountTree *page) 00864 { 00865 Account *account; 00866 00867 g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page)); 00868 account = gnc_plugin_page_account_tree_get_current_account (page); 00869 gppat_open_account_common (page, account, FALSE); 00870 } 00871 00872 static void 00873 gnc_plugin_page_account_tree_cmd_open_subaccounts (GtkAction *action, 00874 GncPluginPageAccountTree *page) 00875 { 00876 Account *account; 00877 00878 g_return_if_fail (GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE (page)); 00879 account = gnc_plugin_page_account_tree_get_current_account (page); 00880 gppat_open_account_common (page, account, TRUE); 00881 } 00882 00883 static void 00884 gnc_plugin_page_account_tree_cmd_edit_account (GtkAction *action, GncPluginPageAccountTree *page) 00885 { 00886 Account *account; 00887 00888 ENTER("action %p, page %p", action, page); 00889 00890 account = gnc_plugin_page_account_tree_get_current_account (page); 00891 g_return_if_fail (account != NULL); 00892 00893 gnc_ui_edit_account_window (account); 00894 LEAVE(" "); 00895 } 00896 00897 /******************************************************************** 00898 * delete_account_helper 00899 * See if this account has any splits present. Set the user data 00900 * and return the same value to stop walking the account tree if 00901 * appropriate. 00902 ********************************************************************/ 00903 typedef struct _delete_helper 00904 { 00905 gboolean has_splits; 00906 gboolean has_ro_splits; 00907 } delete_helper_t; 00908 00909 static gpointer 00910 delete_account_helper (Account * account, gpointer data) 00911 { 00912 delete_helper_t *helper_res = data; 00913 GList *splits; 00914 00915 splits = xaccAccountGetSplitList (account); 00916 if (splits) 00917 { 00918 helper_res->has_splits = TRUE; 00919 while (splits) 00920 { 00921 Split *s = splits->data; 00922 Transaction *txn = xaccSplitGetParent (s); 00923 if (xaccTransGetReadOnly (txn)) 00924 { 00925 helper_res->has_ro_splits = TRUE; 00926 break; 00927 } 00928 splits = splits->next; 00929 } 00930 } 00931 00932 return GINT_TO_POINTER (helper_res->has_splits || helper_res->has_ro_splits); 00933 } 00934 00935 /*** 00936 *** The OK button of a Delete Account dialog is insensitive if 00937 *** and only if a sensitive account selector contains no accounts. 00938 ***/ 00939 static void 00940 set_ok_sensitivity(GtkWidget *dialog) 00941 { 00942 GtkWidget *button; 00943 GtkWidget *sa_mas, *trans_mas; 00944 gint sa_mas_cnt, trans_mas_cnt; 00945 gboolean sensitive; 00946 00947 sa_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS); 00948 trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS); 00949 sa_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(sa_mas)); 00950 trans_mas_cnt = gnc_account_sel_get_num_account(GNC_ACCOUNT_SEL(trans_mas)); 00951 00952 sensitive = (((NULL == sa_mas) || 00953 (!GTK_WIDGET_IS_SENSITIVE(sa_mas) || sa_mas_cnt)) && 00954 ((NULL == trans_mas) || 00955 (!GTK_WIDGET_IS_SENSITIVE(trans_mas) || trans_mas_cnt))); 00956 00957 button = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON); 00958 gtk_widget_set_sensitive(button, sensitive); 00959 } 00960 00961 static void 00962 gppat_populate_gas_list(GtkWidget *dialog, 00963 GNCAccountSel *gas, 00964 gboolean exclude_subaccounts) 00965 { 00966 Account *account; 00967 GList *filter; 00968 00969 g_return_if_fail(GTK_IS_DIALOG(dialog)); 00970 if (gas == NULL) 00971 return; 00972 account = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT); 00973 filter = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER); 00974 00975 /* Setting the account type filter triggers GNCAccountSel population. */ 00976 gnc_account_sel_set_acct_filters (gas, filter, NULL); 00977 00978 /* Accounts to be deleted must be removed. */ 00979 gnc_account_sel_purge_account( gas, account, exclude_subaccounts); 00980 00981 /* The sensitivity of the OK button needs to be reevaluated. */ 00982 set_ok_sensitivity(dialog); 00983 } 00984 00985 void 00986 gppat_populate_trans_mas_list(GtkToggleButton *sa_mrb, 00987 GtkWidget *dialog) 00988 { 00989 GtkWidget *trans_mas; 00990 00991 g_return_if_fail(GTK_IS_DIALOG(dialog)); 00992 00993 /* Cannot move transactions to subaccounts if they are to be deleted. */ 00994 trans_mas = g_object_get_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS); 00995 gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), !gtk_toggle_button_get_active(sa_mrb)); 00996 } 00997 00998 /* Note that the emitting object (the toggle button) and the signal data 00999 * are swapped in below callback function. This is a gtkbuilder feature: 01000 * it swaps if you explicitly set an object for a signal handler in the 01001 * gtkbuilder xml file. 01002 */ 01003 void 01004 gppat_set_insensitive_iff_rb_active(GtkWidget *widget, GtkToggleButton *b) 01005 { 01006 gtk_widget_set_sensitive(widget, !gtk_toggle_button_get_active(b)); 01007 set_ok_sensitivity(gtk_widget_get_toplevel(widget)); 01008 } 01009 01010 static void 01011 gnc_plugin_page_account_tree_cmd_delete_account (GtkAction *action, GncPluginPageAccountTree *page) 01012 { 01013 Account *account = gnc_plugin_page_account_tree_get_current_account (page); 01014 gchar *acct_name; 01015 delete_helper_t delete_res = { FALSE, FALSE }; 01016 GtkWidget *window; 01017 GtkWidget *trans_mas = NULL; /* transaction move to account selector */ 01018 GtkWidget *sa_mas = NULL; /* subaccount move to account selector */ 01019 GtkWidget *sa_trans_mas = NULL; /* subaccount's transaction move to account selector */ 01020 Account *ta = NULL; /* transaction adopter */ 01021 Account *saa = NULL; /* subaccount adopter */ 01022 Account *sta = NULL; /* subaccount transaction adopter */ 01023 GList *splits; 01024 GList* list; 01025 gint response; 01026 01027 if (NULL == account) 01028 return; 01029 01030 /* If the account has objects referring to it, show the list - the account can't be deleted until these 01031 references are dealt with. */ 01032 list = qof_instance_get_referring_object_list(QOF_INSTANCE(account)); 01033 if (list != NULL) 01034 { 01035 #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" 01036 01037 gnc_ui_object_references_show( _(EXPLANATION), list); 01038 g_list_free(list); 01039 return; 01040 } 01041 01042 window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page)); 01043 acct_name = gnc_account_get_full_name(account); 01044 if (!acct_name) 01045 { 01046 acct_name = g_strdup (_("(no name)")); 01047 } 01048 01049 splits = xaccAccountGetSplitList(account); 01050 01051 /* 01052 * If the account has transactions or child accounts then conduct a 01053 * dialog to allow the user to specify what should be done with them. 01054 */ 01055 if ((NULL != splits) || (gnc_account_n_children(account) > 0)) 01056 { 01057 GList *filter = NULL; 01058 GtkBuilder *builder = NULL; 01059 GtkWidget *dialog = NULL; 01060 GtkWidget *box = NULL; 01061 GtkWidget *widget = NULL; 01062 gchar *title = NULL; 01063 01064 builder = gtk_builder_new(); 01065 gnc_builder_add_from_file (builder, "dialog-account.glade", "Delete Account"); 01066 01067 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Delete Account")); 01068 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window)); 01069 01070 widget = GTK_WIDGET(gtk_builder_get_object (builder, "header")); 01071 title = g_strdup_printf(_("Deleting account %s"), acct_name); 01072 gtk_label_set_text(GTK_LABEL(widget), title); 01073 g_free(title); 01074 01075 widget = GTK_WIDGET(gtk_builder_get_object (builder, DELETE_DIALOG_OK_BUTTON)); 01076 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_OK_BUTTON, widget); 01077 01078 /* 01079 * Reparent only to accounts of the same 01080 * type as the one being deleted. 01081 */ 01082 filter = g_list_prepend(NULL, (gpointer)xaccAccountGetType(account)); 01083 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_FILTER, filter); 01084 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_ACCOUNT, account); 01085 01086 /* 01087 * Adjust the dialog based on whether the account has 01088 * transactions. 01089 */ 01090 if (splits) 01091 { 01092 delete_helper_t delete_res2 = { FALSE, FALSE }; 01093 01094 trans_mas = gnc_account_sel_new(); 01095 box = GTK_WIDGET(gtk_builder_get_object (builder, "trans_mas_hbox")); 01096 gtk_box_pack_start (GTK_BOX(box), trans_mas, TRUE, TRUE, 0); 01097 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_TRANS_MAS, trans_mas); 01098 gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(trans_mas), FALSE); 01099 01100 delete_account_helper(account, &delete_res2); 01101 if (delete_res2.has_ro_splits) 01102 { 01103 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "trans_rw"))); 01104 widget = GTK_WIDGET(gtk_builder_get_object (builder, "trans_drb")); 01105 gtk_widget_set_sensitive(widget, FALSE); 01106 } 01107 else 01108 { 01109 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "trans_ro"))); 01110 } 01111 } 01112 else 01113 { 01114 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "transactions"))); 01115 } 01116 01117 /* 01118 * Adjust the dialog based on whether the account has children. 01119 */ 01120 if (gnc_account_n_children(account) > 0) 01121 { 01122 /* 01123 * Check for RO txns in descendants 01124 */ 01125 gnc_account_foreach_descendant_until(account, delete_account_helper, 01126 &delete_res); 01127 if (delete_res.has_ro_splits) 01128 { 01129 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_rw"))); 01130 widget = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_drb")); 01131 gtk_widget_set_sensitive(widget, FALSE); 01132 } 01133 else if (delete_res.has_splits) 01134 { 01135 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_ro"))); 01136 } 01137 else 01138 { 01139 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans"))); 01140 } 01141 01142 sa_mas = gnc_account_sel_new(); 01143 box = GTK_WIDGET(gtk_builder_get_object (builder, "sa_mas_hbox")); 01144 gtk_box_pack_start (GTK_BOX(box), sa_mas, TRUE, TRUE, 0); 01145 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_MAS, sa_mas); 01146 gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(sa_mas), TRUE); 01147 01148 sa_trans_mas = gnc_account_sel_new(); 01149 box = GTK_WIDGET(gtk_builder_get_object (builder, "sa_trans_mas_hbox")); 01150 gtk_box_pack_start (GTK_BOX(box), sa_trans_mas, TRUE, TRUE, 0); 01151 g_object_set_data(G_OBJECT(dialog), DELETE_DIALOG_SA_TRANS_MAS, sa_trans_mas); 01152 gppat_populate_gas_list(dialog, GNC_ACCOUNT_SEL(sa_trans_mas), TRUE); 01153 } 01154 else 01155 { 01156 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccounts"))); 01157 gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "subaccount_trans"))); 01158 } 01159 01160 /* default to cancel */ 01161 gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL); 01162 01163 gtk_builder_connect_signals(builder, dialog); 01164 g_object_unref(G_OBJECT(builder)); 01165 01166 /* 01167 * Note that one effect of the modal dialog is preventing 01168 * the account selectors from being repopulated. 01169 */ 01170 gtk_widget_show_all(dialog); 01171 response = gtk_dialog_run(GTK_DIALOG(dialog)); 01172 if (GTK_RESPONSE_ACCEPT != response) 01173 { 01174 /* Account deletion is cancelled, so clean up and return. */ 01175 gtk_widget_destroy(dialog); 01176 g_list_free(filter); 01177 g_free(acct_name); 01178 return; 01179 } 01180 if (trans_mas && GTK_WIDGET_IS_SENSITIVE(trans_mas)) 01181 ta = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(trans_mas)); 01182 if (sa_mas && GTK_WIDGET_IS_SENSITIVE(sa_mas)) 01183 saa = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(sa_mas)); 01184 if (sa_trans_mas && GTK_WIDGET_IS_SENSITIVE(sa_trans_mas)) 01185 sta = gnc_account_sel_get_account(GNC_ACCOUNT_SEL(sa_trans_mas)); 01186 gtk_widget_destroy(dialog); 01187 g_list_free(filter); 01188 } /* (NULL != splits) || (NULL != children) */ 01189 01190 /* 01191 * Present a message to the user which specifies what will be 01192 * deleted and what will be reparented, then ask for verification. 01193 */ 01194 { 01195 const char *format = _("The account %s will be deleted."); 01196 char *lines[8]; 01197 char *message; 01198 char *name; 01199 int i = 0; 01200 GtkWidget *dialog; 01201 01202 lines[0] = g_strdup_printf(format, acct_name); 01203 if (splits) 01204 { 01205 if (ta) 01206 { 01207 name = gnc_account_get_full_name(ta); 01208 format = _("All transactions in this account will be moved to " 01209 "the account %s."); 01210 lines[++i] = g_strdup_printf(format, name); 01211 } 01212 else if (splits) 01213 { 01214 format = _("All transactions in this account will be deleted."); 01215 lines[++i] = g_strdup_printf("%s", format); 01216 } 01217 } 01218 if (gnc_account_n_children(account) > 0) 01219 { 01220 if (saa) 01221 { 01222 name = gnc_account_get_full_name(saa); 01223 format = _("All of its sub-accounts will be moved to " 01224 "the account %s."); 01225 lines[++i] = g_strdup_printf(format, name); 01226 } 01227 else 01228 { 01229 format = _("All of its subaccounts will be deleted."); 01230 lines[++i] = g_strdup_printf("%s", format); 01231 if (sta) 01232 { 01233 name = gnc_account_get_full_name(sta); 01234 format = _("All sub-account transactions will be moved to " 01235 "the account %s."); 01236 lines[++i] = g_strdup_printf(format, name); 01237 } 01238 else if (delete_res.has_splits) 01239 { 01240 format = _("All sub-account transactions will be deleted."); 01241 lines[++i] = g_strdup_printf("%s", format); 01242 } 01243 } 01244 } 01245 lines[++i] = _("Are you sure you want to do this?"); 01246 lines[i] = NULL; 01247 i--; /* Don't try to free the constant question. */ 01248 message = g_strjoinv(" ", lines); 01249 while (i--) 01250 { 01251 g_free(lines[i]); 01252 } 01253 01254 dialog = gtk_message_dialog_new(GTK_WINDOW(window), 01255 GTK_DIALOG_DESTROY_WITH_PARENT, 01256 GTK_MESSAGE_QUESTION, 01257 GTK_BUTTONS_NONE, 01258 "%s", message); 01259 g_free(message); 01260 gtk_dialog_add_buttons(GTK_DIALOG(dialog), 01261 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 01262 GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT, 01263 (gchar *)NULL); 01264 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL); 01265 response = gtk_dialog_run(GTK_DIALOG(dialog)); 01266 gtk_widget_destroy(dialog); 01267 01268 if (GTK_RESPONSE_ACCEPT == response) 01269 { 01270 gnc_set_busy_cursor(NULL, TRUE); 01271 gnc_suspend_gui_refresh (); 01272 xaccAccountBeginEdit (account); 01273 if (NULL != saa) 01274 { 01275 GList *acct_list, *ptr; 01276 01277 xaccAccountBeginEdit (saa); 01278 acct_list = gnc_account_get_children(account); 01279 for (ptr = acct_list; ptr; ptr = g_list_next(ptr)) 01280 gnc_account_append_child (saa, ptr->data); 01281 g_list_free(acct_list); 01282 xaccAccountCommitEdit (saa); 01283 } 01284 else if (NULL != sta) 01285 { 01286 /* Move the splits of its subaccounts, if any. */ 01287 gnc_account_foreach_descendant(account, 01288 (AccountCb)xaccAccountMoveAllSplits, 01289 sta); 01290 } 01291 if (NULL != ta) 01292 { 01293 /* Move the splits of the account to be deleted. */ 01294 xaccAccountMoveAllSplits (account, ta); 01295 } 01296 /* 01297 * Finally, delete the account, any subaccounts it may still 01298 * have, and any splits it or its subaccounts may still have. 01299 */ 01300 xaccAccountDestroy (account); 01301 gnc_resume_gui_refresh (); 01302 gnc_unset_busy_cursor(NULL); 01303 } 01304 } 01305 g_free(acct_name); 01306 } 01307 01308 static void 01309 gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action, 01310 GncPluginPageAccountTree *page) 01311 { 01312 Account *account; 01313 GtkWidget *window; 01314 01315 window = gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page)); 01316 account = gnc_plugin_page_account_tree_get_current_account(page); 01317 if (!window || !account) 01318 return; 01319 01320 gnc_account_renumber_create_dialog(window, account); 01321 } 01322 01323 /*********************/ 01324 01325 static void 01326 gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action, 01327 GncPluginPageAccountTree *page) 01328 { 01329 GncPluginPageAccountTreePrivate *priv; 01330 01331 g_return_if_fail(GNC_IS_PLUGIN_PAGE_ACCOUNT_TREE(page)); 01332 ENTER("(action %p, page %p)", action, page); 01333 01334 priv = GNC_PLUGIN_PAGE_ACCOUNT_TREE_GET_PRIVATE(page); 01335 account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page)); 01336 LEAVE(" "); 01337 } 01338 01339 static void 01340 gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action, 01341 GncPluginPageAccountTree *page) 01342 { 01343 GtkWidget *window; 01344 Account *account; 01345 RecnWindow *recnData; 01346 01347 account = gnc_plugin_page_account_tree_get_current_account (page); 01348 g_return_if_fail (account != NULL); 01349 01350 window = GNC_PLUGIN_PAGE (page)->window; 01351 recnData = recnWindow (window, account); 01352 gnc_ui_reconcile_window_raise (recnData); 01353 } 01354 01355 static void 01356 gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action, 01357 GncPluginPageAccountTree *page) 01358 { 01359 GtkWidget *window; 01360 Account *account; 01361 AutoClearWindow *autoClearData; 01362 01363 account = gnc_plugin_page_account_tree_get_current_account (page); 01364 g_return_if_fail (account != NULL); 01365 01366 window = GNC_PLUGIN_PAGE (page)->window; 01367 autoClearData = autoClearWindow (window, account); 01368 gnc_ui_autoclear_window_raise (autoClearData); 01369 } 01370 01371 static void 01372 gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action, 01373 GncPluginPageAccountTree *page) 01374 { 01375 GtkWidget *window; 01376 Account *account; 01377 01378 account = gnc_plugin_page_account_tree_get_current_account (page); 01379 window = GNC_PLUGIN_PAGE (page)->window; 01380 gnc_xfer_dialog (window, account); 01381 } 01382 01383 static void 01384 gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action, 01385 GncPluginPageAccountTree *page) 01386 { 01387 GtkWidget *window; 01388 Account *account; 01389 01390 account = gnc_plugin_page_account_tree_get_current_account (page); 01391 window = GNC_PLUGIN_PAGE (page)->window; 01392 gnc_stock_split_dialog (window, account); 01393 } 01394 01395 static void 01396 gnc_plugin_page_account_tree_cmd_lots (GtkAction *action, 01397 GncPluginPageAccountTree *page) 01398 { 01399 Account *account; 01400 01401 account = gnc_plugin_page_account_tree_get_current_account (page); 01402 gnc_lot_viewer_dialog (account); 01403 } 01404 01405 static void 01406 gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page) 01407 { 01408 Account *account = gnc_plugin_page_account_tree_get_current_account (page); 01409 01410 g_return_if_fail (account != NULL); 01411 01412 gnc_suspend_gui_refresh (); 01413 01414 xaccAccountScrubOrphans (account); 01415 xaccAccountScrubImbalance (account); 01416 01417 // XXX: Lots are disabled 01418 if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL) 01419 xaccAccountScrubLots(account); 01420 01421 gnc_resume_gui_refresh (); 01422 } 01423 01424 static void 01425 gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page) 01426 { 01427 Account *account = gnc_plugin_page_account_tree_get_current_account (page); 01428 01429 g_return_if_fail (account != NULL); 01430 01431 gnc_suspend_gui_refresh (); 01432 01433 xaccAccountTreeScrubOrphans (account); 01434 xaccAccountTreeScrubImbalance (account); 01435 01436 // XXX: Lots are disabled 01437 if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL) 01438 xaccAccountTreeScrubLots(account); 01439 01440 gnc_resume_gui_refresh (); 01441 } 01442 01443 static void 01444 gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page) 01445 { 01446 Account *root = gnc_get_current_root_account (); 01447 01448 gnc_suspend_gui_refresh (); 01449 01450 xaccAccountTreeScrubOrphans (root); 01451 xaccAccountTreeScrubImbalance (root); 01452 // XXX: Lots are disabled 01453 if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL) 01454 xaccAccountTreeScrubLots(root); 01455 01456 gnc_resume_gui_refresh (); 01457 } 01458
1.7.4