|
GnuCash 2.4.99
|
00001 /******************************************************************** 00002 * gnc-plugin-page-budget.c -- Budget plugin based on * 00003 * gnc-plugin-page-account-tree.c * 00004 * * 00005 * Copyright (C) 2005, Chris Shoemaker <c.shoemaker@cox.net> * 00006 * Copyright (C) 2011, Robert Fewell * 00007 * * 00008 * This program is free software; you can redistribute it and/or * 00009 * modify it under the terms of the GNU General Public License as * 00010 * published by the Free Software Foundation; either version 2 of * 00011 * the License, or (at your option) any later version. * 00012 * * 00013 * This program is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00016 * GNU General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU General Public License* 00019 * along with this program; if not, contact: * 00020 * * 00021 * Free Software Foundation Voice: +1-617-542-5942 * 00022 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00023 * Boston, MA 02110-1301, USA gnu@gnu.org * 00024 *******************************************************************/ 00025 00026 /* 00027 * TODO: 00028 * 00029 * *) I'd like to be able to update the budget estimates on a per cell 00030 * basis, instead of a whole row (account) at one time. But, that 00031 * would require some major coding. 00032 * 00033 */ 00034 00035 #include "config.h" 00036 00037 #include <gtk/gtk.h> 00038 #ifdef __G_IR_SCANNER__ 00039 #undef __G_IR_SCANNER__ 00040 #endif 00041 #include <gdk/gdkkeysyms.h> 00042 #include <glib/gi18n.h> 00043 #include "gnc-date-edit.h" 00044 00045 #include "gnc-plugin-page-register.h" 00046 #include "gnc-budget.h" 00047 00048 #include "dialog-options.h" 00049 #include "dialog-utils.h" 00050 #include "gnc-gconf-utils.h" 00051 #include "gnc-gnome-utils.h" 00052 #include "gnc-gobject-utils.h" 00053 #include "gnc-icons.h" 00054 #include "gnc-plugin-page-budget.h" 00055 #include "gnc-plugin-budget.h" 00056 00057 #include "gnc-session.h" 00058 #include "gnc-tree-view-account.h" 00059 #include "gnc-ui.h" 00060 #include "gnc-ui-util.h" 00061 #include "option-util.h" 00062 #include "libguile.h" 00063 #include "gnc-main-window.h" 00064 #include "gnc-component-manager.h" 00065 00066 #include "qof.h" 00067 00068 #include "gnc-recurrence.h" 00069 #include "Recurrence.h" 00070 #include "gnc-tree-model-account-types.h" 00071 00072 00073 /* This static indicates the debugging module that this .o belongs to. */ 00074 static QofLogModule log_module = GNC_MOD_BUDGET; 00075 00076 #define PLUGIN_PAGE_BUDGET_CM_CLASS "plugin-page-budget" 00077 #define GCONF_SECTION "window/pages/budget" 00078 00079 /************************************************************ 00080 * Prototypes * 00081 ************************************************************/ 00082 /* Plugin Actions */ 00083 static void 00084 gnc_plugin_page_budget_class_init (GncPluginPageBudgetClass *klass); 00085 static void gnc_plugin_page_budget_init (GncPluginPageBudget *plugin_page); 00086 static void gnc_plugin_page_budget_finalize (GObject *object); 00087 00088 static GtkWidget * 00089 gnc_plugin_page_budget_create_widget (GncPluginPage *plugin_page); 00090 static void gnc_plugin_page_budget_destroy_widget (GncPluginPage *plugin_page); 00091 static void gnc_plugin_page_budget_save_page ( 00092 GncPluginPage *plugin_page, GKeyFile *file, const gchar *group); 00093 static GncPluginPage *gnc_plugin_page_budget_recreate_page ( 00094 GtkWidget *window, GKeyFile *file, const gchar *group); 00095 00096 00097 static gboolean gppb_button_press_cb( 00098 GtkWidget *widget, GdkEventButton *event, GncPluginPage *page); 00099 static gboolean gppb_key_press_cb( 00100 GtkWidget *treeview, GdkEventKey *event, gpointer userdata); 00101 static void gppb_double_click_cb( 00102 GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, 00103 GncPluginPageBudget *page); 00104 static void gppb_selection_changed_cb( 00105 GtkTreeSelection *selection, GncPluginPageBudget *page); 00106 00107 static void gnc_plugin_page_budget_view_refresh (GncPluginPageBudget *page); 00108 static void gnc_plugin_page_budget_cmd_view_filter_by ( 00109 GtkAction *action, GncPluginPageBudget *page); 00110 00111 /* Command Callbacks */ 00112 static void gnc_plugin_page_budget_cmd_open_account( 00113 GtkAction *action, GncPluginPageBudget *page); 00114 static void gnc_plugin_page_budget_cmd_open_subaccounts( 00115 GtkAction *action, GncPluginPageBudget *page); 00116 static void gnc_plugin_page_budget_cmd_delete_budget( 00117 GtkAction *action, GncPluginPageBudget *page); 00118 static void gnc_plugin_page_budget_cmd_view_options( 00119 GtkAction *action, GncPluginPageBudget *page); 00120 static void gnc_plugin_page_budget_cmd_estimate_budget( 00121 GtkAction *action, GncPluginPageBudget *page); 00122 00123 static GtkActionEntry gnc_plugin_page_budget_actions [] = 00124 { 00125 /* Toplevel */ 00126 { "FakeToplevel", "", NULL, NULL, NULL, NULL }, 00127 00128 /* File menu */ 00129 { 00130 "OpenAccountAction", GNC_STOCK_OPEN_ACCOUNT, N_("Open _Account"), NULL, 00131 N_("Open the selected account"), 00132 G_CALLBACK (gnc_plugin_page_budget_cmd_open_account) 00133 }, 00134 { 00135 "OpenSubaccountsAction", GNC_STOCK_OPEN_ACCOUNT, 00136 N_("Open _Subaccounts"), NULL, 00137 N_("Open the selected account and all its subaccounts"), 00138 G_CALLBACK (gnc_plugin_page_budget_cmd_open_subaccounts) 00139 }, 00140 00141 /* Edit menu */ 00142 { 00143 "DeleteBudgetAction", GNC_STOCK_DELETE_BUDGET, N_("_Delete Budget"), 00144 NULL, N_("Delete this budget"), 00145 G_CALLBACK (gnc_plugin_page_budget_cmd_delete_budget) 00146 }, 00147 { 00148 "OptionsBudgetAction", GTK_STOCK_PROPERTIES, N_("Budget Options"), 00149 NULL, N_("Edit this budget's options"), 00150 G_CALLBACK (gnc_plugin_page_budget_cmd_view_options) 00151 }, 00152 { 00153 "EstimateBudgetAction", GTK_STOCK_EXECUTE, N_("Estimate Budget"), 00154 NULL, 00155 N_("Estimate a budget value for the selected accounts from past transactions"), 00156 G_CALLBACK (gnc_plugin_page_budget_cmd_estimate_budget) 00157 }, 00158 00159 /* View menu */ 00160 { 00161 "ViewFilterByAction", NULL, N_("_Filter By..."), NULL, NULL, 00162 G_CALLBACK (gnc_plugin_page_budget_cmd_view_filter_by) 00163 }, 00164 00165 }; 00166 00167 static guint gnc_plugin_page_budget_n_actions = 00168 G_N_ELEMENTS (gnc_plugin_page_budget_actions); 00169 00170 static const gchar *actions_requiring_account[] = 00171 { 00172 "OpenAccountAction", 00173 "OpenSubaccountsAction", 00174 NULL 00175 }; 00176 00178 static action_toolbar_labels toolbar_labels[] = 00179 { 00180 { "OpenAccountAction", N_("Open") }, 00181 { "DeleteBudgetAction", N_("Delete") }, 00182 { "OptionsBudgetAction", N_("Options") }, 00183 { "EstimateBudgetAction", N_("Estimate") }, 00184 { NULL, NULL }, 00185 }; 00186 00187 typedef struct GncPluginPageBudgetPrivate 00188 { 00189 GtkActionGroup *action_group; 00190 guint merge_id; 00191 GtkUIManager *ui_merge; 00192 00193 GtkWidget *widget; /* ends up being a vbox */ 00194 GtkTreeView *tree_view; 00195 00196 gint component_id; 00197 00198 GncBudget* budget; 00199 GncGUID key; 00200 GtkWidget *dialog; 00201 /* To distinguish between closing a tab and deleting a budget */ 00202 gboolean delete_budget; 00203 00204 GList *period_col_list; 00205 AccountFilterDialog fd; 00206 00207 /* For the estimation dialog */ 00208 Recurrence r; 00209 gint sigFigs; 00210 } GncPluginPageBudgetPrivate; 00211 00212 #define GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(o) \ 00213 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_BUDGET, GncPluginPageBudgetPrivate)) 00214 00215 static GObjectClass *parent_class = NULL; 00216 00217 00218 GType 00219 gnc_plugin_page_budget_get_type (void) 00220 { 00221 static GType gnc_plugin_page_budget_type = 0; 00222 00223 if (gnc_plugin_page_budget_type == 0) 00224 { 00225 static const GTypeInfo our_info = 00226 { 00227 sizeof (GncPluginPageBudgetClass), 00228 NULL, 00229 NULL, 00230 (GClassInitFunc) gnc_plugin_page_budget_class_init, 00231 NULL, 00232 NULL, 00233 sizeof (GncPluginPageBudget), 00234 0, 00235 (GInstanceInitFunc) gnc_plugin_page_budget_init 00236 }; 00237 00238 gnc_plugin_page_budget_type = 00239 g_type_register_static (GNC_TYPE_PLUGIN_PAGE, 00240 "GncPluginPageBudget", &our_info, 0); 00241 } 00242 00243 return gnc_plugin_page_budget_type; 00244 } 00245 00246 00247 GncPluginPage * 00248 gnc_plugin_page_budget_new (GncBudget *budget) 00249 { 00250 GncPluginPageBudget *plugin_page; 00251 GncPluginPageBudgetPrivate *priv; 00252 gchar* label; 00253 const GList *item; 00254 00255 g_return_val_if_fail(GNC_IS_BUDGET(budget), NULL); 00256 ENTER(" "); 00257 00258 /* Is there an existing page? */ 00259 item = gnc_gobject_tracking_get_list(GNC_PLUGIN_PAGE_BUDGET_NAME); 00260 for ( ; item; item = g_list_next(item)) 00261 { 00262 plugin_page = (GncPluginPageBudget *)item->data; 00263 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page); 00264 if (priv->budget == budget) 00265 { 00266 LEAVE("existing budget page %p", plugin_page); 00267 return GNC_PLUGIN_PAGE(plugin_page); 00268 } 00269 } 00270 00271 plugin_page = g_object_new(GNC_TYPE_PLUGIN_PAGE_BUDGET, NULL); 00272 00273 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page); 00274 priv->budget = budget; 00275 priv->delete_budget = FALSE; 00276 label = g_strdup_printf("%s: %s", _("Budget"), gnc_budget_get_name(budget)); 00277 g_object_set(G_OBJECT(plugin_page), "page-name", label, NULL); 00278 g_free(label); 00279 priv->key = *gnc_budget_get_guid(budget); 00280 LEAVE("new budget page %p", plugin_page); 00281 return GNC_PLUGIN_PAGE(plugin_page); 00282 } 00283 00284 00285 static void 00286 gnc_plugin_page_budget_class_init (GncPluginPageBudgetClass *klass) 00287 { 00288 GObjectClass *object_class = G_OBJECT_CLASS (klass); 00289 GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass); 00290 00291 parent_class = g_type_class_peek_parent (klass); 00292 00293 object_class->finalize = gnc_plugin_page_budget_finalize; 00294 00295 gnc_plugin_class->tab_icon = GNC_STOCK_BUDGET; 00296 gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_BUDGET_NAME; 00297 gnc_plugin_class->create_widget = gnc_plugin_page_budget_create_widget; 00298 gnc_plugin_class->destroy_widget = gnc_plugin_page_budget_destroy_widget; 00299 gnc_plugin_class->save_page = gnc_plugin_page_budget_save_page; 00300 gnc_plugin_class->recreate_page = gnc_plugin_page_budget_recreate_page; 00301 00302 g_type_class_add_private(klass, sizeof(GncPluginPageBudgetPrivate)); 00303 } 00304 00305 00306 static void 00307 gnc_plugin_page_budget_init (GncPluginPageBudget *plugin_page) 00308 { 00309 GtkActionGroup *action_group; 00310 GncPluginPageBudgetPrivate *priv; 00311 GncPluginPage *parent; 00312 00313 ENTER("page %p", plugin_page); 00314 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page); 00315 00316 /* Initialize parent declared variables */ 00317 parent = GNC_PLUGIN_PAGE(plugin_page); 00318 g_object_set(G_OBJECT(plugin_page), 00319 "page-name", _("Budget"), 00320 "page-uri", "default:", 00321 "ui-description", "gnc-plugin-page-budget-ui.xml", 00322 NULL); 00323 00324 /* change me when the system supports multiple books */ 00325 gnc_plugin_page_add_book(parent, gnc_get_current_book()); 00326 00327 /* Create menu and toolbar information */ 00328 action_group = 00329 gnc_plugin_page_create_action_group(parent, 00330 "GncPluginPageBudgetActions"); 00331 gtk_action_group_add_actions (action_group, 00332 gnc_plugin_page_budget_actions, 00333 gnc_plugin_page_budget_n_actions, 00334 plugin_page); 00335 gnc_plugin_init_short_names (action_group, toolbar_labels); 00336 00337 /* Visible types */ 00338 priv->fd.visible_types = -1; /* Start with all types */ 00339 priv->fd.show_hidden = FALSE; 00340 priv->fd.show_zero_total = TRUE; 00341 00342 priv->sigFigs = 1; 00343 recurrenceSet(&priv->r, 1, PERIOD_MONTH, NULL, WEEKEND_ADJ_NONE); 00344 00345 LEAVE("page %p, priv %p, action group %p", 00346 plugin_page, priv, action_group); 00347 } 00348 00349 00350 static void 00351 gnc_plugin_page_budget_finalize (GObject *object) 00352 { 00353 GncPluginPageBudget *page; 00354 GncPluginPageBudgetPrivate *priv; 00355 00356 ENTER("object %p", object); 00357 page = GNC_PLUGIN_PAGE_BUDGET (object); 00358 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page)); 00359 00360 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00361 g_list_free(priv->period_col_list); 00362 00363 G_OBJECT_CLASS (parent_class)->finalize (object); 00364 LEAVE(" "); 00365 } 00366 00367 00368 /* Component Manager Callback Functions */ 00369 static void 00370 gnc_plugin_page_budget_close_cb (gpointer user_data) 00371 { 00372 GncPluginPage *page = GNC_PLUGIN_PAGE(user_data); 00373 gnc_main_window_close_page (page); 00374 } 00375 00376 00377 static void 00378 gnc_plugin_page_budget_refresh_cb(GHashTable *changes, gpointer user_data) 00379 { 00380 GncPluginPageBudget *page; 00381 GncPluginPageBudgetPrivate *priv; 00382 const EventInfo* ei; 00383 00384 page = GNC_PLUGIN_PAGE_BUDGET(user_data); 00385 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00386 if (changes) 00387 { 00388 ei = gnc_gui_get_entity_events(changes, &priv->key); 00389 if (ei) 00390 { 00391 if (ei->event_mask & QOF_EVENT_DESTROY) 00392 { 00393 gnc_plugin_page_budget_close_cb(user_data); 00394 return; 00395 } 00396 if (ei->event_mask & QOF_EVENT_MODIFY) 00397 { 00398 DEBUG("refreshing budget view because budget was modified"); 00399 gnc_plugin_page_budget_view_refresh(page); 00400 } 00401 } 00402 } 00403 } 00404 00405 00406 /**************************** 00407 * GncPluginPage Functions * 00408 ***************************/ 00409 static GtkWidget * 00410 gnc_plugin_page_budget_create_widget (GncPluginPage *plugin_page) 00411 { 00412 GncPluginPageBudget *page; 00413 GncPluginPageBudgetPrivate *priv; 00414 GtkTreeSelection *selection; 00415 GtkTreeView *tree_view; 00416 GtkWidget *scrolled_window; 00417 gchar *priv_gconf_section; 00418 const gchar *budget_guid_str; 00419 00420 ENTER("page %p", plugin_page); 00421 page = GNC_PLUGIN_PAGE_BUDGET (plugin_page); 00422 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00423 if (priv->widget != NULL) 00424 { 00425 LEAVE("widget = %p", priv->widget); 00426 return priv->widget; 00427 } 00428 00429 priv->widget = gtk_vbox_new (FALSE, 0); 00430 gtk_widget_show (priv->widget); 00431 00432 scrolled_window = gtk_scrolled_window_new (NULL, NULL); 00433 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), 00434 GTK_POLICY_AUTOMATIC, 00435 GTK_POLICY_AUTOMATIC); 00436 gtk_widget_show (scrolled_window); 00437 gtk_box_pack_start (GTK_BOX (priv->widget), scrolled_window, 00438 TRUE, TRUE, 0); 00439 00440 tree_view = gnc_tree_view_account_new(FALSE); 00441 00442 /* Have one gconf section per budget */ 00443 budget_guid_str = guid_to_string (&priv->key); 00444 priv_gconf_section = g_strjoin ("/", GCONF_SECTION, budget_guid_str, NULL); 00445 g_object_set(G_OBJECT(tree_view), "gconf-section", priv_gconf_section, NULL); 00446 g_free (priv_gconf_section); 00447 00448 gnc_tree_view_configure_columns(GNC_TREE_VIEW(tree_view)); 00449 priv->tree_view = tree_view; 00450 selection = gtk_tree_view_get_selection(tree_view); 00451 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); 00452 00453 g_signal_connect(G_OBJECT(selection), "changed", 00454 G_CALLBACK(gppb_selection_changed_cb), plugin_page); 00455 g_signal_connect(G_OBJECT(tree_view), "button-press-event", 00456 G_CALLBACK(gppb_button_press_cb), plugin_page); 00457 g_signal_connect(G_OBJECT(tree_view), "row-activated", 00458 G_CALLBACK(gppb_double_click_cb), page); 00459 g_signal_connect_after(G_OBJECT(tree_view), "key-press-event", 00460 G_CALLBACK(gppb_key_press_cb), NULL); 00461 00462 gppb_selection_changed_cb (NULL, page); 00463 gtk_tree_view_set_headers_visible(tree_view, TRUE); 00464 gtk_widget_show (GTK_WIDGET (tree_view)); 00465 gtk_container_add (GTK_CONTAINER (scrolled_window), 00466 GTK_WIDGET(tree_view)); 00467 priv->fd.tree_view = GNC_TREE_VIEW_ACCOUNT(priv->tree_view); 00468 gnc_tree_view_account_set_filter( 00469 GNC_TREE_VIEW_ACCOUNT(tree_view), 00470 gnc_plugin_page_account_tree_filter_accounts, 00471 &priv->fd, NULL); 00472 00473 priv->component_id = 00474 gnc_register_gui_component(PLUGIN_PAGE_BUDGET_CM_CLASS, 00475 gnc_plugin_page_budget_refresh_cb, 00476 gnc_plugin_page_budget_close_cb, 00477 page); 00478 00479 gnc_gui_component_set_session (priv->component_id, 00480 gnc_get_current_session()); 00481 00482 gnc_gui_component_watch_entity (priv->component_id, 00483 gnc_budget_get_guid(priv->budget), 00484 QOF_EVENT_DESTROY | QOF_EVENT_MODIFY); 00485 00486 gnc_plugin_page_budget_view_refresh(page); 00487 00488 LEAVE("widget = %p", priv->widget); 00489 return priv->widget; 00490 } 00491 00492 00493 static void 00494 gnc_plugin_page_budget_destroy_widget (GncPluginPage *plugin_page) 00495 { 00496 GncPluginPageBudget *page; 00497 GncPluginPageBudgetPrivate *priv; 00498 gchar *priv_gconf_section = NULL; 00499 00500 ENTER("page %p", plugin_page); 00501 page = GNC_PLUGIN_PAGE_BUDGET (plugin_page); 00502 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page); 00503 00504 if (priv->delete_budget) 00505 { 00506 g_object_get (G_OBJECT(priv->tree_view), "gconf-section", &priv_gconf_section, NULL); 00507 if (priv_gconf_section) 00508 { 00509 gnc_gconf_unset_dir (priv_gconf_section, NULL); 00510 g_free (priv_gconf_section); 00511 } 00512 } 00513 00514 if (priv->widget) 00515 { 00516 g_object_unref(G_OBJECT(priv->widget)); 00517 priv->widget = NULL; 00518 } 00519 00520 gnc_gui_component_clear_watches (priv->component_id); 00521 00522 if (priv->component_id != NO_COMPONENT) 00523 { 00524 gnc_unregister_gui_component(priv->component_id); 00525 priv->component_id = NO_COMPONENT; 00526 } 00527 00528 LEAVE("widget destroyed"); 00529 } 00530 00531 00532 #define BUDGET_GUID "Budget GncGUID" 00533 00534 /*********************************************************************** 00535 * Save enough information about this plugin page that it can * 00536 * be recreated next time the user starts gnucash. * 00537 * * 00538 * @param page The page to save. * 00539 * * 00540 * @param key_file A pointer to the GKeyFile data structure where the * 00541 * page information should be written. * 00542 * * 00543 * @param group_name The group name to use when saving data. * 00544 **********************************************************************/ 00545 static void 00546 gnc_plugin_page_budget_save_page (GncPluginPage *plugin_page, 00547 GKeyFile *key_file, const gchar *group_name) 00548 { 00549 GncPluginPageBudget *budget_page; 00550 GncPluginPageBudgetPrivate *priv; 00551 char guid_str[GUID_ENCODING_LENGTH+1]; 00552 00553 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(plugin_page)); 00554 g_return_if_fail (key_file != NULL); 00555 g_return_if_fail (group_name != NULL); 00556 00557 ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file, 00558 group_name); 00559 00560 budget_page = GNC_PLUGIN_PAGE_BUDGET(plugin_page); 00561 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(budget_page); 00562 00563 guid_to_string_buff(gnc_budget_get_guid(priv->budget), guid_str); 00564 g_key_file_set_string(key_file, group_name, BUDGET_GUID, guid_str); 00565 00566 //FIXME 00567 gnc_tree_view_account_save(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), 00568 &priv->fd, key_file, group_name); 00569 LEAVE(" "); 00570 } 00571 00572 00573 /*********************************************************************** 00574 * Create a new plugin page based on the information saved 00575 * during a previous instantiation of gnucash. 00576 * 00577 * @param window The window where this page should be installed. 00578 * 00579 * @param key_file A pointer to the GKeyFile data structure where the 00580 * page information should be read. 00581 * 00582 * @param group_name The group name to use when restoring data. 00583 **********************************************************************/ 00584 static GncPluginPage * 00585 gnc_plugin_page_budget_recreate_page (GtkWidget *window, GKeyFile *key_file, 00586 const gchar *group_name) 00587 { 00588 GncPluginPageBudget *budget_page; 00589 GncPluginPageBudgetPrivate *priv; 00590 GncPluginPage *page; 00591 GError *error = NULL; 00592 char *guid_str; 00593 GncGUID guid; 00594 GncBudget *bgt; 00595 QofBook *book; 00596 00597 g_return_val_if_fail(key_file, NULL); 00598 g_return_val_if_fail(group_name, NULL); 00599 ENTER("key_file %p, group_name %s", key_file, group_name); 00600 00601 guid_str = g_key_file_get_string(key_file, group_name, BUDGET_GUID, 00602 &error); 00603 if (error) 00604 { 00605 g_warning("error reading group %s key %s: %s", 00606 group_name, BUDGET_GUID, error->message); 00607 g_error_free(error); 00608 error = NULL; 00609 return NULL; 00610 } 00611 if (!string_to_guid(guid_str, &guid)) 00612 return NULL; 00613 00614 book = qof_session_get_book(gnc_get_current_session()); 00615 bgt = gnc_budget_lookup(&guid, book); 00616 if (!bgt) 00617 return NULL; 00618 00619 /* Create the new page. */ 00620 page = gnc_plugin_page_budget_new(bgt); 00621 budget_page = GNC_PLUGIN_PAGE_BUDGET(page); 00622 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(budget_page); 00623 00624 /* Install it now so we can then manipulate the created widget */ 00625 gnc_main_window_open_page(GNC_MAIN_WINDOW(window), page); 00626 00627 //FIXME 00628 gnc_tree_view_account_restore(GNC_TREE_VIEW_ACCOUNT(priv->tree_view), 00629 &priv->fd, key_file, group_name); 00630 LEAVE(" "); 00631 return page; 00632 } 00633 00634 00635 /*********************************************************************** 00636 * This button press handler calls the common button press handler 00637 * for all pages. The GtkTreeView eats all button presses and 00638 * doesn't pass them up the widget tree, even when it doesn't do 00639 * anything with them. The only way to get access to the button 00640 * presses in an account tree page is here on the tree view widget. 00641 * Button presses on all other pages are caught by the signal 00642 * registered in gnc-main-window.c. 00643 **********************************************************************/ 00644 static gboolean 00645 gppb_button_press_cb(GtkWidget *widget, GdkEventButton *event, 00646 GncPluginPage *page) 00647 { 00648 gboolean result; 00649 00650 g_return_val_if_fail(GNC_IS_PLUGIN_PAGE(page), FALSE); 00651 00652 ENTER("widget %p, event %p, page %p", widget, event, page); 00653 result = gnc_main_window_button_press_cb(widget, event, page); 00654 LEAVE(" "); 00655 return result; 00656 } 00657 00658 00659 static gboolean 00660 gppb_key_press_cb(GtkWidget *treeview, GdkEventKey *event, gpointer userdata) 00661 { 00662 GtkTreeView *tv = GTK_TREE_VIEW(treeview); 00663 GtkTreeViewColumn *col; 00664 GtkTreePath *path = NULL; 00665 00666 if (event->type != GDK_KEY_PRESS) return TRUE; 00667 00668 switch (event->keyval) 00669 { 00670 case GDK_Tab: 00671 case GDK_ISO_Left_Tab: 00672 case GDK_KP_Tab: 00673 case GDK_Return: 00674 case GDK_KP_Enter: 00675 gtk_tree_view_get_cursor(tv, &path, &col); 00676 if (!path) return TRUE; 00677 //finish_edit(col); 00678 break; 00679 default: 00680 return TRUE; 00681 } 00682 gnc_tree_view_keynav(GNC_TREE_VIEW(tv), &col, path, event); 00683 00684 if (path && gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path)) 00685 gtk_tree_view_set_cursor(tv, path, col, TRUE); 00686 return TRUE; 00687 } 00688 00689 00690 static void 00691 gppb_double_click_cb(GtkTreeView *treeview, GtkTreePath *path, 00692 GtkTreeViewColumn *col, GncPluginPageBudget *page) 00693 { 00694 GtkWidget *window; 00695 GncPluginPage *new_page; 00696 Account *account; 00697 00698 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET (page)); 00699 account = gnc_tree_view_account_get_account_from_path( 00700 GNC_TREE_VIEW_ACCOUNT(treeview), path); 00701 if (account == NULL) 00702 return; 00703 00704 window = GNC_PLUGIN_PAGE(page)->window; 00705 new_page = gnc_plugin_page_register_new(account, FALSE); 00706 gnc_main_window_open_page(GNC_MAIN_WINDOW(window), new_page); 00707 } 00708 00709 00710 static void 00711 gppb_selection_changed_cb(GtkTreeSelection *selection, 00712 GncPluginPageBudget *page) 00713 { 00714 GtkActionGroup *action_group; 00715 GtkTreeView *view; 00716 GList *acct_list; 00717 gboolean sensitive; 00718 00719 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page)); 00720 00721 if (!selection) 00722 { 00723 sensitive = FALSE; 00724 } 00725 else 00726 { 00727 g_return_if_fail(GTK_IS_TREE_SELECTION(selection)); 00728 view = gtk_tree_selection_get_tree_view (selection); 00729 acct_list = gnc_tree_view_account_get_selected_accounts( 00730 GNC_TREE_VIEW_ACCOUNT(view)); 00731 00732 /* Check here for placeholder accounts, etc. */ 00733 sensitive = (g_list_length(acct_list) > 0); 00734 g_list_free(acct_list); 00735 } 00736 00737 action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(page)); 00738 gnc_plugin_update_actions (action_group, actions_requiring_account, 00739 "sensitive", sensitive); 00740 } 00741 00742 00743 /********************* 00744 * Command callbacks * 00745 ********************/ 00746 static void 00747 gnc_plugin_page_budget_cmd_open_account (GtkAction *action, 00748 GncPluginPageBudget *page) 00749 { 00750 GncPluginPageBudgetPrivate *priv; 00751 GtkWidget *window; 00752 GncPluginPage *new_page; 00753 GList *acct_list, *tmp; 00754 Account *account; 00755 00756 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page)); 00757 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00758 acct_list = gnc_tree_view_account_get_selected_accounts( 00759 GNC_TREE_VIEW_ACCOUNT(priv->tree_view)); 00760 00761 window = GNC_PLUGIN_PAGE (page)->window; 00762 for (tmp = acct_list; tmp; tmp = g_list_next(tmp)) 00763 { 00764 account = tmp->data; 00765 new_page = gnc_plugin_page_register_new (account, FALSE); 00766 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page); 00767 } 00768 g_list_free(acct_list); 00769 } 00770 00771 00772 static void 00773 gnc_plugin_page_budget_cmd_open_subaccounts (GtkAction *action, 00774 GncPluginPageBudget *page) 00775 { 00776 GncPluginPageBudgetPrivate *priv; 00777 GtkWidget *window; 00778 GncPluginPage *new_page; 00779 GList *acct_list, *tmp; 00780 Account *account; 00781 00782 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page)); 00783 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00784 acct_list = gnc_tree_view_account_get_selected_accounts( 00785 GNC_TREE_VIEW_ACCOUNT(priv->tree_view)); 00786 00787 window = GNC_PLUGIN_PAGE (page)->window; 00788 for (tmp = acct_list; tmp; tmp = g_list_next(tmp)) 00789 { 00790 account = tmp->data; 00791 new_page = gnc_plugin_page_register_new (account, TRUE); 00792 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page); 00793 } 00794 g_list_free(acct_list); 00795 } 00796 00797 00798 static void 00799 gnc_plugin_page_budget_cmd_delete_budget (GtkAction *action, 00800 GncPluginPageBudget *page) 00801 { 00802 GncPluginPageBudgetPrivate *priv; 00803 GncBudget *budget; 00804 00805 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00806 budget = priv->budget; 00807 g_return_if_fail (GNC_IS_BUDGET(budget)); 00808 priv->delete_budget = TRUE; 00809 gnc_budget_gui_delete_budget(budget); 00810 00811 } 00812 00813 00814 /******************************/ 00815 /* Options Dialog */ 00816 /******************************/ 00817 static void 00818 gnc_plugin_page_budget_cmd_view_options (GtkAction *action, 00819 GncPluginPageBudget *page) 00820 { 00821 GncPluginPageBudgetPrivate *priv; 00822 GncRecurrence *gr; 00823 GtkBuilder *builder; 00824 gint result; 00825 gchar *name; 00826 gchar *desc; 00827 gint num_periods; 00828 GtkWidget *gbname, *gbtreeview, *gbnumperiods, *gbhb; 00829 const Recurrence *r; 00830 00831 GtkTextBuffer *buffer; 00832 GtkTextIter start, end; 00833 00834 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page)); 00835 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00836 00837 if (!priv->dialog) 00838 { 00839 builder = gtk_builder_new(); 00840 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "NumPeriods_Adj"); 00841 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "OptionsContainer"); 00842 00843 priv->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "OptionsContainer")); 00844 00845 gtk_window_set_transient_for( 00846 GTK_WINDOW(priv->dialog), 00847 GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page)))); 00848 00849 gbname = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetName")); 00850 gtk_entry_set_text(GTK_ENTRY(gbname), gnc_budget_get_name(priv->budget)); 00851 00852 gbtreeview = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetDescription")); 00853 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gbtreeview)); 00854 gtk_text_buffer_set_text (buffer, gnc_budget_get_description(priv->budget), -1); 00855 00856 gbhb = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetPeriod")); 00857 gr = GNC_RECURRENCE(gnc_recurrence_new()); 00858 gnc_recurrence_set(gr, gnc_budget_get_recurrence(priv->budget)); 00859 gtk_box_pack_start (GTK_BOX (gbhb), GTK_WIDGET(gr), TRUE, TRUE, 0); 00860 gtk_widget_show (GTK_WIDGET(gr)); 00861 00862 gbnumperiods = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetNumPeriods")); 00863 gtk_spin_button_set_value(GTK_SPIN_BUTTON(gbnumperiods), gnc_budget_get_num_periods(priv->budget)); 00864 00865 gtk_widget_show_all (priv->dialog); 00866 result = gtk_dialog_run(GTK_DIALOG(priv->dialog)); 00867 00868 switch (result) 00869 { 00870 case GTK_RESPONSE_OK: 00871 name = (gchar *) gtk_entry_get_text(GTK_ENTRY(gbname)); 00872 DEBUG("%s", name); 00873 if (name) 00874 { 00875 gchar* label; 00876 gnc_budget_set_name(priv->budget, name); 00877 label = g_strdup_printf("%s: %s", _("Budget"), name); 00878 main_window_update_page_name(GNC_PLUGIN_PAGE(page), label); 00879 g_free(label); 00880 } 00881 00882 gtk_text_buffer_get_bounds (gtk_text_view_get_buffer(GTK_TEXT_VIEW (gbtreeview)), &start, &end); 00883 desc = gtk_text_buffer_get_text (gtk_text_view_get_buffer(GTK_TEXT_VIEW (gbtreeview)), &start, &end, TRUE); 00884 00885 gnc_budget_set_description(priv->budget, desc); 00886 g_free(desc); 00887 00888 num_periods = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gbnumperiods)); 00889 gnc_budget_set_num_periods(priv->budget, num_periods); 00890 00891 r = gnc_recurrence_get(gr); 00892 gnc_budget_set_recurrence(priv->budget, r); 00893 break; 00894 case GTK_RESPONSE_CANCEL: 00895 break; 00896 default: 00897 break; 00898 } 00899 g_object_unref(G_OBJECT(builder)); 00900 gtk_widget_destroy(priv->dialog); 00901 } 00902 priv->dialog = NULL; 00903 } 00904 00905 00906 void 00907 gnc_budget_gui_delete_budget(GncBudget *budget) 00908 { 00909 const char *name; 00910 00911 g_return_if_fail(GNC_IS_BUDGET(budget)); 00912 name = gnc_budget_get_name (budget); 00913 if (!name) 00914 name = _("Unnamed Budget"); 00915 00916 if (gnc_verify_dialog (NULL, FALSE, _("Delete %s?"), name)) 00917 { 00918 gnc_suspend_gui_refresh (); 00919 gnc_budget_destroy(budget); 00920 // Views should close themselves because the CM will notify them. 00921 gnc_resume_gui_refresh (); 00922 } 00923 } 00924 00925 00926 static void 00927 estimate_budget_helper(GtkTreeModel *model, GtkTreePath *path, 00928 GtkTreeIter *iter, gpointer data) 00929 { 00930 Account *acct; 00931 guint num_periods, i; 00932 gnc_numeric num; 00933 GncPluginPageBudgetPrivate *priv; 00934 GncPluginPageBudget *page = data; 00935 00936 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page)); 00937 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00938 00939 acct = gnc_tree_view_account_get_account_from_path( 00940 GNC_TREE_VIEW_ACCOUNT(priv->tree_view), path); 00941 00942 num_periods = g_list_length(priv->period_col_list); 00943 00944 for (i = 0; i < num_periods; i++) 00945 { 00946 num = recurrenceGetAccountPeriodValue(&priv->r, acct, i); 00947 if (!gnc_numeric_check(num)) 00948 { 00949 if (gnc_reverse_balance (acct)) 00950 num = gnc_numeric_neg (num); 00951 00952 00953 num = gnc_numeric_convert(num, GNC_DENOM_AUTO, 00954 GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) | GNC_HOW_RND_ROUND_HALF_UP); 00955 gnc_budget_set_account_period_value( 00956 priv->budget, acct, i, num); 00957 } 00958 } 00959 } 00960 00961 00962 /*******************************/ 00963 /* Estimate Dialog */ 00964 /*******************************/ 00965 static void 00966 gnc_plugin_page_budget_cmd_estimate_budget(GtkAction *action, 00967 GncPluginPageBudget *page) 00968 { 00969 GncPluginPageBudgetPrivate *priv; 00970 GtkTreeSelection *sel; 00971 GtkWidget *dialog, *gde, *dtr, *hb; 00972 gint result; 00973 GDate date; 00974 const Recurrence *r; 00975 GtkBuilder *builder; 00976 00977 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page)); 00978 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 00979 00980 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->tree_view)); 00981 00982 if (gtk_tree_selection_count_selected_rows(sel) <= 0) 00983 { 00984 dialog = gtk_message_dialog_new ( 00985 GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page))), 00986 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, 00987 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", 00988 _("You must select at least one account to estimate.")); 00989 gtk_dialog_run (GTK_DIALOG(dialog)); 00990 gtk_widget_destroy(dialog); 00991 return; 00992 } 00993 00994 builder = gtk_builder_new(); 00995 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "DigitsToRound_Adj"); 00996 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "BudgetEstimate"); 00997 00998 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetEstimate")); 00999 01000 gtk_window_set_transient_for( 01001 GTK_WINDOW(dialog), 01002 GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page)))); 01003 01004 hb = GTK_WIDGET(gtk_builder_get_object (builder, "StartDate_hbox")); 01005 gde = gnc_date_edit_new (time (NULL), FALSE, FALSE); 01006 gtk_box_pack_start (GTK_BOX (hb), gde, TRUE, TRUE, 0); 01007 gtk_widget_show (gde); 01008 01009 date = recurrenceGetDate(&priv->r); 01010 gnc_date_edit_set_gdate(GNC_DATE_EDIT(gde), &date); 01011 01012 dtr = GTK_WIDGET(gtk_builder_get_object (builder, "DigitsToRound")); 01013 gtk_spin_button_set_value(GTK_SPIN_BUTTON(dtr), 01014 (gdouble)priv->sigFigs); 01015 01016 gtk_widget_show_all (dialog); 01017 result = gtk_dialog_run(GTK_DIALOG(dialog)); 01018 switch (result) 01019 { 01020 case GTK_RESPONSE_OK: 01021 r = gnc_budget_get_recurrence(priv->budget); 01022 01023 gnc_date_edit_get_gdate(GNC_DATE_EDIT(gde), &date); 01024 recurrenceSet(&priv->r, recurrenceGetMultiplier(r), 01025 recurrenceGetPeriodType(r), &date, 01026 recurrenceGetWeekendAdjust(r)); 01027 priv->sigFigs = 01028 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dtr)); 01029 01030 gtk_tree_selection_selected_foreach(sel, estimate_budget_helper, page); 01031 break; 01032 default: 01033 break; 01034 } 01035 gtk_widget_destroy(dialog); 01036 g_object_unref(G_OBJECT(builder)); 01037 } 01038 01039 01040 static gchar * 01041 budget_col_source(Account *account, GtkTreeViewColumn *col, 01042 GtkCellRenderer *cell) 01043 { 01044 GncBudget *budget; 01045 guint period_num; 01046 gnc_numeric numeric; 01047 gchar amtbuff[100]; //FIXME: overkill, where's the #define? 01048 01049 budget = GNC_BUDGET(g_object_get_data(G_OBJECT(col), "budget")); 01050 period_num = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(col), 01051 "period_num")); 01052 01053 if (!gnc_budget_is_account_period_value_set(budget, account, period_num)) 01054 { 01055 amtbuff[0] = '\0'; 01056 } 01057 else 01058 { 01059 numeric = gnc_budget_get_account_period_value(budget, account, 01060 period_num); 01061 if (gnc_numeric_check(numeric)) 01062 { 01063 strcpy(amtbuff, "error"); 01064 } 01065 else 01066 { 01067 xaccSPrintAmount(amtbuff, numeric, 01068 gnc_account_print_info(account, FALSE)); 01069 } 01070 } 01071 return g_strdup(amtbuff); 01072 } 01073 01074 01075 static void 01076 budget_col_edited(Account *account, GtkTreeViewColumn *col, 01077 const gchar *new_text) 01078 { 01079 GncBudget *budget; 01080 guint period_num; 01081 gnc_numeric numeric = gnc_numeric_error(GNC_ERROR_ARG); 01082 01083 if (!xaccParseAmount (new_text, TRUE, &numeric, NULL) && 01084 !(new_text && *new_text == '\0')) 01085 return; 01086 01087 period_num = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(col), 01088 "period_num")); 01089 01090 budget = GNC_BUDGET(g_object_get_data(G_OBJECT(col), "budget")); 01091 01092 if (new_text && *new_text == '\0') 01093 gnc_budget_unset_account_period_value(budget, account, period_num); 01094 else 01095 gnc_budget_set_account_period_value(budget, account, period_num, 01096 numeric); 01097 } 01098 01099 01100 static void 01101 gnc_plugin_page_budget_refresh_col_titles(GncPluginPageBudget *page) 01102 { 01103 const Recurrence *r; 01104 GDate date, nextdate; 01105 GtkTreeViewColumn *col; 01106 guint titlelen; 01107 gint num_periods_visible; 01108 gchar title[MAX_DATE_LENGTH]; 01109 GncPluginPageBudgetPrivate *priv; 01110 GList *col_list; 01111 gint i; 01112 01113 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page)); 01114 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 01115 01116 col_list = priv->period_col_list; 01117 num_periods_visible = g_list_length(col_list); 01118 01119 /* Show the dates in column titles */ 01120 r = gnc_budget_get_recurrence(priv->budget); 01121 date = r->start; 01122 for (i = 0; i < num_periods_visible; i++) 01123 { 01124 col = GTK_TREE_VIEW_COLUMN(g_list_nth_data(col_list, i)); 01125 titlelen = qof_print_gdate(title, MAX_DATE_LENGTH, &date); 01126 if (titlelen > 0) 01127 gtk_tree_view_column_set_title(col, title); 01128 recurrenceNextInstance(r, &date, &nextdate); 01129 date = nextdate; 01130 } 01131 01132 } 01133 01134 01135 static void 01136 gnc_plugin_page_budget_view_refresh (GncPluginPageBudget *page) 01137 { 01138 GncPluginPageBudgetPrivate *priv; 01139 gint num_periods, num_periods_visible; 01140 GtkTreeViewColumn *col; 01141 GList *col_list; 01142 01143 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page)); 01144 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 01145 01146 num_periods = gnc_budget_get_num_periods(priv->budget); 01147 col_list = priv->period_col_list; 01148 num_periods_visible = g_list_length(col_list); 01149 01150 /* Hide any unneeded extra columns */ 01151 while (num_periods_visible > num_periods) 01152 { 01153 col = GTK_TREE_VIEW_COLUMN((g_list_last(col_list))->data); 01154 gtk_tree_view_remove_column(GTK_TREE_VIEW(priv->tree_view), col); 01155 col_list = g_list_delete_link(col_list, g_list_last(col_list)); 01156 num_periods_visible = g_list_length(col_list); 01157 } 01158 01159 gnc_tree_view_configure_columns(GNC_TREE_VIEW(priv->tree_view)); 01160 01161 /* Create any needed columns */ 01162 while (num_periods_visible < num_periods) 01163 { 01164 col = gnc_tree_view_account_add_custom_column( 01165 GNC_TREE_VIEW_ACCOUNT(priv->tree_view), "", 01166 budget_col_source, budget_col_edited); 01167 g_object_set_data(G_OBJECT(col), "budget", priv->budget); 01168 g_object_set_data(G_OBJECT(col), "period_num", 01169 GUINT_TO_POINTER(num_periods_visible)); 01170 col_list = g_list_append(col_list, col); 01171 num_periods_visible = g_list_length(col_list); 01172 } 01173 priv->period_col_list = col_list; 01174 01175 gnc_plugin_page_budget_refresh_col_titles(page); 01176 } 01177 01178 01179 static void 01180 gnc_plugin_page_budget_cmd_view_filter_by (GtkAction *action, 01181 GncPluginPageBudget *page) 01182 { 01183 GncPluginPageBudgetPrivate *priv; 01184 01185 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page)); 01186 ENTER("(action %p, page %p)", action, page); 01187 01188 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page); 01189 account_filter_dialog_create(&priv->fd, GNC_PLUGIN_PAGE(page)); 01190 01191 LEAVE(" "); 01192 }
1.7.4