GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-plugin-page-budget.cpp
1/********************************************************************
2 * gnc-plugin-page-budget.c -- Budget plugin based on *
3 * gnc-plugin-page-account-tree.c *
4 * *
5 * Copyright (C) 2005, Chris Shoemaker <c.shoemaker@cox.net> *
6 * Copyright (C) 2011, Robert Fewell *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation; either version 2 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License*
19 * along with this program; if not, contact: *
20 * *
21 * Free Software Foundation Voice: +1-617-542-5942 *
22 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23 * Boston, MA 02110-1301, USA gnu@gnu.org *
24 *******************************************************************/
25
26/*
27 * TODO:
28 *
29 * *) I'd like to be able to update the budget estimates on a per cell
30 * basis, instead of a whole row (account) at one time. But, that
31 * would require some major coding.
32 *
33 */
34
35#include <config.h>
36
37#include <gtk/gtk.h>
38#ifdef __G_IR_SCANNER__
39#undef __G_IR_SCANNER__
40#endif
41#include <gdk/gdkkeysyms.h>
42#include <glib/gi18n.h>
43#include "gnc-date-edit.h"
44
45#include "swig-runtime.h"
46#include "libguile.h"
47#include <guile-mappings.h>
48
51#include "gnc-budget.h"
52#include "gnc-features.h"
53
54#include "dialog-utils.h"
55#include "gnc-gnome-utils.h"
56#include "misc-gnome-utils.h"
57#include "gnc-gobject-utils.h"
58#include "gnc-icons.h"
60#include "gnc-plugin-budget.h"
61#include "gnc-budget-view.h"
62
63#include "gnc-session.h"
65#include "gnc-ui.h"
66#include "gnc-ui-util.h"
67#include "gnc-window.h"
68#include "gnc-main-window.h"
69#include "gnc-component-manager.h"
70
71#include "qof.h"
72
73#include "gnc-recurrence.h"
74#include "Recurrence.h"
76
77
78/* This static indicates the debugging module that this .o belongs to. */
79static QofLogModule log_module = GNC_MOD_BUDGET;
80
81#define PLUGIN_PAGE_BUDGET_CM_CLASS "plugin-page-budget"
82
83/************************************************************
84 * Prototypes *
85 ************************************************************/
86/* Plugin Actions */
87static void gnc_plugin_page_budget_finalize (GObject *object);
88
89static GtkWidget *
90gnc_plugin_page_budget_create_widget (GncPluginPage *plugin_page);
91static gboolean gnc_plugin_page_budget_focus_widget (GncPluginPage *plugin_page);
92static void gnc_plugin_page_budget_destroy_widget (GncPluginPage *plugin_page);
93static void gnc_plugin_page_budget_save_page (GncPluginPage *plugin_page,
94 GKeyFile *file,
95 const gchar *group);
96static GncPluginPage *gnc_plugin_page_budget_recreate_page (GtkWidget *window,
97 GKeyFile *file,
98 const gchar *group);
99static gboolean gppb_button_press_cb (GtkWidget *widget,
100 GdkEventButton *event,
101 GncPluginPage *page);
102static void gppb_account_activated_cb (GncBudgetView* view,
103 Account* account,
104 GncPluginPageBudget *page);
105#if 0
106static void gppb_selection_changed_cb (GtkTreeSelection *selection,
107 GncPluginPageBudget *page);
108#endif
109
110static void gnc_plugin_page_budget_cmd_view_filter_by (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
111static void gnc_plugin_page_budget_cmd_open_account (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
112static void gnc_plugin_page_budget_cmd_open_subaccounts (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
113static void gnc_plugin_page_budget_cmd_delete_budget (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
114static void gnc_plugin_page_budget_cmd_view_options (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
115static void gnc_plugin_page_budget_cmd_estimate_budget (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
116static void gnc_plugin_page_budget_cmd_allperiods_budget (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
117static void gnc_plugin_page_budget_cmd_refresh (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
118static void gnc_plugin_page_budget_cmd_budget_note (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
119static void gnc_plugin_page_budget_cmd_budget_report (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
120static void gnc_plugin_page_budget_cmd_edit_tax_options (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
121
122static void allperiods_budget_helper (GtkTreeModel *model, GtkTreePath *path,
123 GtkTreeIter *iter, gpointer data);
124
125static GActionEntry gnc_plugin_page_budget_actions [] =
126{
127 { "OpenAccountAction", gnc_plugin_page_budget_cmd_open_account, NULL, NULL, NULL },
128 { "OpenSubaccountsAction", gnc_plugin_page_budget_cmd_open_subaccounts, NULL, NULL, NULL },
129 { "DeleteBudgetAction", gnc_plugin_page_budget_cmd_delete_budget, NULL, NULL, NULL },
130 { "OptionsBudgetAction", gnc_plugin_page_budget_cmd_view_options, NULL, NULL, NULL },
131 { "EstimateBudgetAction", gnc_plugin_page_budget_cmd_estimate_budget, NULL, NULL, NULL },
132 { "AllPeriodsBudgetAction", gnc_plugin_page_budget_cmd_allperiods_budget, NULL, NULL, NULL },
133 { "BudgetNoteAction", gnc_plugin_page_budget_cmd_budget_note, NULL, NULL, NULL },
134 { "BudgetReportAction", gnc_plugin_page_budget_cmd_budget_report, NULL, NULL, NULL },
135 { "ViewFilterByAction", gnc_plugin_page_budget_cmd_view_filter_by, NULL, NULL, NULL },
136 { "ViewRefreshAction", gnc_plugin_page_budget_cmd_refresh, NULL, NULL, NULL },
137 { "EditTaxOptionsAction", gnc_plugin_page_budget_cmd_edit_tax_options, NULL, NULL, NULL },
138};
139static guint gnc_plugin_page_budget_n_actions = G_N_ELEMENTS(gnc_plugin_page_budget_actions);
140
142static const gchar *gnc_plugin_load_ui_items [] =
143{
144 "FilePlaceholder3",
145 "EditPlaceholder1",
146 "EditPlaceholder3",
147 "EditPlaceholder5",
148 "EditPlaceholder6",
149 "ViewPlaceholder1",
150 "ViewPlaceholder4",
151 NULL,
152};
153
154static const gchar *writeable_actions[] =
155{
156 /* actions which must be disabled on a readonly book. */
157 "DeleteBudgetAction",
158 "OptionsBudgetAction",
159 "EstimateBudgetAction",
160 "AllPeriodsBudgetAction",
161 "BudgetNoteAction",
162 NULL
163};
164
165#if 0
166static const gchar *actions_requiring_account[] =
167{
168 "OpenAccountAction",
169 "OpenSubaccountsAction",
170 NULL
171};
172#endif
173
175static GncToolBarShortNames toolbar_labels[] =
176{
177 { "OpenAccountAction", N_("Open") },
178 { "DeleteBudgetAction", N_("Delete") },
179 { "OptionsBudgetAction", N_("Options") },
180 { "EstimateBudgetAction", N_("Estimate") },
181 { "AllPeriodsBudgetAction", N_("All Periods") },
182 { "BudgetNoteAction", N_("Note") },
183 { "BudgetReportAction", N_("Run Report") },
184 { NULL, NULL },
185};
186
187typedef enum allperiods_action
188{
189 REPLACE,
190 ADD,
191 MULTIPLY,
192 UNSET
193} allperiods_action;
194
196{
197 GtkBuilder *builder;
198 GSimpleActionGroup *simple_action_group;
199
200 GncBudgetView* budget_view;
201 GtkTreeView *tree_view;
202
203 gint component_id;
204
205 GncBudget* budget;
206 GncGUID key;
207 GtkWidget *dialog;
208 /* To distinguish between closing a tab and deleting a budget */
209 gboolean delete_budget;
210
212
213 /* For the estimation dialog */
214 Recurrence r;
215 gint sigFigs;
216 gboolean useAvg;
217
218 /* For the allPeriods value dialog */
219 gnc_numeric allValue;
220 allperiods_action action;
221
222 /* the cached reportPage for this budget. note this is not saved
223 into .gcm file therefore the budget editor->report link is lost
224 upon restart. */
225 GncPluginPage *reportPage;
227
228G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageBudget, gnc_plugin_page_budget, GNC_TYPE_PLUGIN_PAGE)
229
230#define GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(o) \
231 ((GncPluginPageBudgetPrivate*)gnc_plugin_page_budget_get_instance_private((GncPluginPageBudget*)o))
232
234gnc_plugin_page_budget_new (GncBudget *budget)
235{
237 gchar* label;
238 const GList *item;
239
240 g_return_val_if_fail (GNC_IS_BUDGET(budget), NULL);
241 ENTER(" ");
242
243 /* Is there an existing page? */
244 item = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_BUDGET_NAME);
245 for ( ; item; item = g_list_next (item))
246 {
247 auto plugin_page = GNC_PLUGIN_PAGE_BUDGET(item->data);
248 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page);
249 if (priv->budget == budget)
250 {
251 LEAVE("existing budget page %p", plugin_page);
252 return GNC_PLUGIN_PAGE(plugin_page);
253 }
254 }
255
256 auto plugin_page = GNC_PLUGIN_PAGE_BUDGET (g_object_new (GNC_TYPE_PLUGIN_PAGE_BUDGET, nullptr));
257
258 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page);
259 priv->budget = budget;
260 priv->delete_budget = FALSE;
261 priv->key = *gnc_budget_get_guid (budget);
262 priv->reportPage = NULL;
263 label = g_strdup_printf ("%s: %s", _("Budget"), gnc_budget_get_name (budget));
264 g_object_set (G_OBJECT(plugin_page), "page-name", label, NULL);
265 g_free (label);
266 LEAVE("new budget page %p", plugin_page);
267 return GNC_PLUGIN_PAGE(plugin_page);
268}
269
270
271static void
272gnc_plugin_page_budget_class_init (GncPluginPageBudgetClass *klass)
273{
274 GObjectClass *object_class = G_OBJECT_CLASS(klass);
275 GncPluginPageClass *gnc_plugin_class = GNC_PLUGIN_PAGE_CLASS(klass);
276
277 object_class->finalize = gnc_plugin_page_budget_finalize;
278
279 gnc_plugin_class->tab_icon = GNC_ICON_BUDGET;
280 gnc_plugin_class->plugin_name = GNC_PLUGIN_PAGE_BUDGET_NAME;
281 gnc_plugin_class->create_widget = gnc_plugin_page_budget_create_widget;
282 gnc_plugin_class->destroy_widget = gnc_plugin_page_budget_destroy_widget;
283 gnc_plugin_class->save_page = gnc_plugin_page_budget_save_page;
284 gnc_plugin_class->recreate_page = gnc_plugin_page_budget_recreate_page;
285 gnc_plugin_class->focus_page_function = gnc_plugin_page_budget_focus_widget;
286}
287
288
289static void
290gnc_plugin_page_budget_init (GncPluginPageBudget *plugin_page)
291{
292 GSimpleActionGroup *simple_action_group;
294 GncPluginPage *parent;
295
296 ENTER("page %p", plugin_page);
297 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page);
298
299 /* Initialize parent declared variables */
300 parent = GNC_PLUGIN_PAGE(plugin_page);
301 g_object_set (G_OBJECT(plugin_page),
302 "page-name", _("Budget"),
303 "ui-description", "gnc-plugin-page-budget.ui",
304 NULL);
305
306 /* change me when the system supports multiple books */
307 gnc_plugin_page_add_book (parent, gnc_get_current_book());
308
309 /* Create menu and toolbar information */
310 simple_action_group = gnc_plugin_page_create_action_group (parent, "GncPluginPageBudgetActions");
311 g_action_map_add_action_entries (G_ACTION_MAP(simple_action_group),
312 gnc_plugin_page_budget_actions,
313 gnc_plugin_page_budget_n_actions,
314 plugin_page);
315
316 if (qof_book_is_readonly (gnc_get_current_book()))
317 gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), writeable_actions,
318 FALSE);
319
320 /* Visible types */
321 priv->fd.visible_types = -1; /* Start with all types */
322 priv->fd.show_hidden = FALSE;
323 priv->fd.show_unused = TRUE;
324 priv->fd.show_zero_total = TRUE;
325 priv->fd.filter_override = g_hash_table_new (g_direct_hash, g_direct_equal);
326
327 priv->sigFigs = 1;
328 priv->useAvg = FALSE;
329 recurrenceSet (&priv->r, 1, PERIOD_MONTH, NULL, WEEKEND_ADJ_NONE);
330
331 LEAVE("page %p, priv %p, action group %p",
332 plugin_page, priv, simple_action_group);
333}
334
335
336static void
337gnc_plugin_page_budget_finalize (GObject *object)
338{
340
341 ENTER("object %p", object);
342 page = GNC_PLUGIN_PAGE_BUDGET(object);
343 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
344
345 G_OBJECT_CLASS (gnc_plugin_page_budget_parent_class)->finalize (object);
346 LEAVE(" ");
347}
348
349
350/* Component Manager Callback Functions */
351static void
352gnc_plugin_page_budget_close_cb (gpointer user_data)
353{
354 GncPluginPage *page = GNC_PLUGIN_PAGE(user_data);
356}
357
358
363static gboolean
364gnc_plugin_page_budget_focus_widget (GncPluginPage *budget_plugin_page)
365{
366 if (GNC_IS_PLUGIN_PAGE_BUDGET(budget_plugin_page))
367 {
368 GncPluginPageBudgetPrivate *priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(budget_plugin_page);
369 GncBudgetView *budget_view = priv->budget_view;
370 GtkWidget *account_view = gnc_budget_view_get_account_tree_view (budget_view);
371
372 /* Disable the Transaction Menu */
373 GAction *action = gnc_main_window_find_action (GNC_MAIN_WINDOW(budget_plugin_page->window), "TransactionAction");
374 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
375 /* Disable the Schedule menu */
376 action = gnc_main_window_find_action (GNC_MAIN_WINDOW(budget_plugin_page->window), "ScheduledAction");
377 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
378 /* Disable the FilePrintAction */
379 action = gnc_main_window_find_action (GNC_MAIN_WINDOW(budget_plugin_page->window), "FilePrintAction");
380 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
381
382 gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(budget_plugin_page->window),
383 budget_plugin_page,
384 gnc_plugin_load_ui_items);
385
386 // setup any short toolbar names
387 gnc_main_window_init_short_names (GNC_MAIN_WINDOW(budget_plugin_page->window), toolbar_labels);
388
389 if (!gtk_widget_is_focus (GTK_WIDGET(account_view)))
390 gtk_widget_grab_focus (GTK_WIDGET(account_view));
391 }
392 return FALSE;
393}
394
395
396static void
397gnc_plugin_page_budget_refresh_cb (GHashTable *changes, gpointer user_data)
398{
401 const EventInfo* ei;
402
403 page = GNC_PLUGIN_PAGE_BUDGET(user_data);
404 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
405 if (changes)
406 {
407 ei = gnc_gui_get_entity_events (changes, &priv->key);
408 if (ei)
409 {
410 if (ei->event_mask & QOF_EVENT_DESTROY)
411 {
412 /* Budget has been deleted, close plugin page
413 * but prevent that action from writing state information
414 * for this budget account
415 */
416 priv->delete_budget = TRUE;
417 gnc_budget_view_delete_budget (priv->budget_view);
418 gnc_plugin_page_budget_close_cb (user_data);
419 return;
420 }
421 if (ei->event_mask & QOF_EVENT_MODIFY)
422 {
423 DEBUG("refreshing budget view because budget was modified");
424 gnc_budget_view_refresh (priv->budget_view);
425 }
426 }
427 }
428}
429
430
431/****************************
432 * GncPluginPage Functions *
433 ***************************/
434static GtkWidget *
435gnc_plugin_page_budget_create_widget (GncPluginPage *plugin_page)
436{
439
440 ENTER("page %p", plugin_page);
441 page = GNC_PLUGIN_PAGE_BUDGET(plugin_page);
442 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
443 if (priv->budget_view != NULL)
444 {
445 LEAVE("widget = %p", priv->budget_view);
446 return GTK_WIDGET(priv->budget_view);
447 }
448
449 priv->budget_view = gnc_budget_view_new (priv->budget, &priv->fd);
450
451#if 0
452 g_signal_connect (G_OBJECT(selection), "changed",
453 G_CALLBACK(gppb_selection_changed_cb), plugin_page);
454#endif
455 g_signal_connect (G_OBJECT(priv->budget_view), "button-press-event",
456 G_CALLBACK(gppb_button_press_cb), plugin_page);
457 g_signal_connect (G_OBJECT(priv->budget_view), "account-activated",
458 G_CALLBACK(gppb_account_activated_cb), page);
459
460 priv->component_id =
461 gnc_register_gui_component (PLUGIN_PAGE_BUDGET_CM_CLASS,
462 gnc_plugin_page_budget_refresh_cb,
463 gnc_plugin_page_budget_close_cb,
464 page);
465
466 gnc_gui_component_set_session (priv->component_id,
467 gnc_get_current_session ());
468
469 gnc_gui_component_watch_entity (priv->component_id,
470 gnc_budget_get_guid (priv->budget),
471 QOF_EVENT_DESTROY | QOF_EVENT_MODIFY);
472
473 g_signal_connect (G_OBJECT(plugin_page), "inserted",
474 G_CALLBACK(gnc_plugin_page_inserted_cb),
475 NULL);
476
477 LEAVE("widget = %p", priv->budget_view);
478 return GTK_WIDGET(priv->budget_view);
479}
480
481
482static void
483gnc_plugin_page_budget_destroy_widget (GncPluginPage *plugin_page)
484{
486
487 ENTER("page %p", plugin_page);
488 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(plugin_page);
489
490 // Remove the page_changed signal callback
491 gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
492
493 // Remove the page focus idle function if present
494 g_idle_remove_by_data (plugin_page);
495
496 if (priv->budget_view)
497 {
498 // save the account filter state information to budget section
499 gnc_budget_view_save_account_filter (priv->budget_view);
500
501 if (priv->delete_budget)
502 {
503 gnc_budget_view_delete_budget (priv->budget_view);
504 }
505
506 g_object_unref (G_OBJECT(priv->budget_view));
507 priv->budget_view = NULL;
508 }
509
510 // Destroy the filter override hash table
511 g_hash_table_destroy (priv->fd.filter_override);
512
513 gnc_gui_component_clear_watches (priv->component_id);
514
515 if (priv->component_id != NO_COMPONENT)
516 {
517 gnc_unregister_gui_component (priv->component_id);
518 priv->component_id = NO_COMPONENT;
519 }
520
521 LEAVE("widget destroyed");
522}
523
524
525#define BUDGET_GUID "Budget GncGUID"
526
527/***********************************************************************
528 * Save enough information about this plugin page that it can *
529 * be recreated next time the user starts gnucash. *
530 * *
531 * @param page The page to save. *
532 * *
533 * @param key_file A pointer to the GKeyFile data structure where the *
534 * page information should be written. *
535 * *
536 * @param group_name The group name to use when saving data. *
537 **********************************************************************/
538static void
539gnc_plugin_page_budget_save_page (GncPluginPage *plugin_page,
540 GKeyFile *key_file, const gchar *group_name)
541{
542 GncPluginPageBudget *budget_page;
544 char guid_str[GUID_ENCODING_LENGTH+1];
545
546 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(plugin_page));
547 g_return_if_fail (key_file != NULL);
548 g_return_if_fail (group_name != NULL);
549
550 ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
551 group_name);
552
553 budget_page = GNC_PLUGIN_PAGE_BUDGET(plugin_page);
554 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(budget_page);
555
556 guid_to_string_buff (gnc_budget_get_guid (priv->budget), guid_str);
557 g_key_file_set_string (key_file, group_name, BUDGET_GUID, guid_str);
558
559 // Save the Budget page information to state file
560 gnc_budget_view_save (priv->budget_view, key_file, group_name);
561
562 LEAVE(" ");
563}
564
565
566/***********************************************************************
567 * Create a new plugin page based on the information saved
568 * during a previous instantiation of gnucash.
569 *
570 * @param window The window where this page should be installed.
571 *
572 * @param key_file A pointer to the GKeyFile data structure where the
573 * page information should be read.
574 *
575 * @param group_name The group name to use when restoring data.
576 **********************************************************************/
577static GncPluginPage *
578gnc_plugin_page_budget_recreate_page (GtkWidget *window, GKeyFile *key_file,
579 const gchar *group_name)
580{
581 GncPluginPageBudget *budget_page;
583 GncPluginPage *page;
584 GError *error = NULL;
585 char *guid_str;
586 GncGUID guid;
587 GncBudget *bgt;
588 QofBook *book;
589
590 g_return_val_if_fail (key_file, NULL);
591 g_return_val_if_fail (group_name, NULL);
592 ENTER("key_file %p, group_name %s", key_file, group_name);
593
594 guid_str = g_key_file_get_string (key_file, group_name, BUDGET_GUID,
595 &error);
596 if (error)
597 {
598 g_warning("error reading group %s key %s: %s",
599 group_name, BUDGET_GUID, error->message);
600 g_error_free (error);
601 error = NULL;
602 return NULL;
603 }
604 if (!string_to_guid (guid_str, &guid))
605 {
606 g_free (guid_str);
607 return NULL;
608 }
609 g_free (guid_str);
610
611 book = qof_session_get_book (gnc_get_current_session());
612 bgt = gnc_budget_lookup (&guid, book);
613 if (!bgt)
614 {
615 return NULL;
616 }
617
618 /* Create the new page. */
619 page = gnc_plugin_page_budget_new(bgt);
620 budget_page = GNC_PLUGIN_PAGE_BUDGET(page);
621 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(budget_page);
622
623 /* Install it now so we can then manipulate the created widget */
624 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), page);
625
626 //FIXME
627 if (!gnc_budget_view_restore (priv->budget_view, key_file, group_name))
628 return NULL;
629
630 LEAVE(" ");
631 return page;
632}
633
634
635/***********************************************************************
636 * This button press handler calls the common button press handler
637 * for all pages. The GtkTreeView eats all button presses and
638 * doesn't pass them up the widget tree, even when it doesn't do
639 * anything with them. The only way to get access to the button
640 * presses in an account tree page is here on the tree view widget.
641 * Button presses on all other pages are caught by the signal
642 * registered in gnc-main-window.c.
643 **********************************************************************/
644static gboolean
645gppb_button_press_cb (GtkWidget *widget, GdkEventButton *event,
646 GncPluginPage *page)
647{
648 gboolean result;
649
650 g_return_val_if_fail (GNC_IS_PLUGIN_PAGE(page), FALSE);
651
652 ENTER("widget %p, event %p, page %p", widget, event, page);
653 result = gnc_main_window_button_press_cb (widget, event, page);
654 LEAVE(" ");
655 return result;
656}
657
658static void
659gppb_account_activated_cb (GncBudgetView* view, Account* account,
661{
662 GtkWidget *window;
663 GncPluginPage *new_page;
664
665 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page));
666
667 window = GNC_PLUGIN_PAGE(page)->window;
668 new_page = gnc_plugin_page_register_new (account, FALSE);
669 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
670}
671
672
673#if 0
674static void
675gppb_selection_changed_cb (GtkTreeSelection *selection,
677{
678 GSimpleActionGroup *simple_action_group;
679 GtkTreeView *view;
680 GList *acct_list;
681 gboolean sensitive;
682
683 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
684
685 if (!selection)
686 sensitive = FALSE;
687 else
688 {
689 g_return_if_fail (GTK_IS_TREE_SELECTION(selection));
690 view = gtk_tree_selection_get_tree_view (selection);
692 GNC_TREE_VIEW_ACCOUNT(view));
693
694 /* Check here for placeholder accounts, etc. */
695 sensitive = (g_list_length (acct_list) > 0);
696 g_list_free (acct_list);
697 }
698
699 simple_action_group = gnc_plugin_page_get_action_group (GNC_PLUGIN_PAGE(page));
700 gnc_plugin_set_actions_enabled (G_ACTION_MAP(simple_action_group), actions_requiring_account,
701 sensitive);
702}
703#endif
704
705
706/*********************
707 * Command callbacks *
708 ********************/
709static void
710gnc_plugin_page_budget_cmd_open_account (GSimpleAction *simple,
711 GVariant *parameter,
712 gpointer user_data)
713{
714 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
716 GtkWidget *window;
717 GncPluginPage *new_page;
718 GList *acct_list, *tmp;
719
720 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
721 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
722 acct_list = gnc_budget_view_get_selected_accounts (priv->budget_view);
723
724 window = GNC_PLUGIN_PAGE(page)->window;
725 for (tmp = acct_list; tmp; tmp = g_list_next (tmp))
726 {
727 auto account = GNC_ACCOUNT (tmp->data);
728 new_page = gnc_plugin_page_register_new (account, FALSE);
729 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
730 }
731 g_list_free (acct_list);
732}
733
734
735static void
736gnc_plugin_page_budget_cmd_open_subaccounts (GSimpleAction *simple,
737 GVariant *parameter,
738 gpointer user_data)
739{
740 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
742 GtkWidget *window;
743 GncPluginPage *new_page;
744 GList *acct_list, *tmp;
745
746 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
747 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
748 acct_list = gnc_budget_view_get_selected_accounts (priv->budget_view);
749
750 window = GNC_PLUGIN_PAGE(page)->window;
751 for (tmp = acct_list; tmp; tmp = g_list_next (tmp))
752 {
753 auto account = GNC_ACCOUNT(tmp->data);
754 new_page = gnc_plugin_page_register_new (account, TRUE);
755 gnc_main_window_open_page (GNC_MAIN_WINDOW(window), new_page);
756 }
757 g_list_free (acct_list);
758}
759
760
761static void
762gnc_plugin_page_budget_cmd_delete_budget (GSimpleAction *simple,
763 GVariant *parameter,
764 gpointer user_data)
765{
766 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
768 GncBudget *budget;
769
770 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
771 budget = priv->budget;
772 g_return_if_fail (GNC_IS_BUDGET(budget));
773 priv->delete_budget = TRUE;
774 gnc_budget_gui_delete_budget (budget);
775
776}
777
778
779static void
780gnc_plugin_page_budget_cmd_edit_tax_options (GSimpleAction *simple,
781 GVariant *parameter,
782 gpointer user_data)
783{
784 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
786 GtkTreeSelection *selection;
787 Account *account = NULL;
788 GtkWidget *window;
789
790 page = GNC_PLUGIN_PAGE_BUDGET(page);
791
792 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
793
794 ENTER ("(action %p, page %p)", simple, page);
795 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
796
797 selection = gnc_budget_view_get_selection (priv->budget_view);
798 window = GNC_PLUGIN_PAGE(page)->window;
799
800 if (gtk_tree_selection_count_selected_rows (selection) == 1)
801 {
802 GList *acc_list = gnc_budget_view_get_selected_accounts (priv->budget_view);
803 account = GNC_ACCOUNT (acc_list->data);
804 g_list_free (acc_list);
805 }
806 gnc_tax_info_dialog (window, account);
807 LEAVE (" ");
808}
809
810/******************************/
811/* Options Dialog */
812/******************************/
813static void
814gnc_plugin_page_budget_cmd_view_options (GSimpleAction *simple,
815 GVariant *parameter,
816 gpointer user_data)
817{
818 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
820 GncRecurrence *gr;
821 GtkBuilder *builder;
822 gint result;
823 gchar *name;
824 gchar *desc;
825 gint num_periods;
826 GtkWidget *gbname, *gbtreeview, *gbnumperiods, *gbhb;
827 const Recurrence *r;
828
829 GtkTextBuffer *buffer;
830 GtkTextIter start, end;
831 GtkWidget *show_account_code, *show_account_desc;
832 gboolean show_ac, show_ad;
833
834 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
835 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
836
837 if (!priv->dialog)
838 {
839 builder = gtk_builder_new ();
840 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "NumPeriods_Adj");
841 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "budget_options_container_dialog");
842
843 priv->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "budget_options_container_dialog"));
844
845 gtk_window_set_transient_for (GTK_WINDOW(priv->dialog),
846 GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))));
847
848 gbname = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetName"));
849 gtk_entry_set_text (GTK_ENTRY(gbname), gnc_budget_get_name (priv->budget));
850
851 gbtreeview = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetDescription"));
852 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(gbtreeview));
853 gtk_text_buffer_set_text (buffer, gnc_budget_get_description (priv->budget), -1);
854
855 gbhb = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetPeriod"));
856 gr = GNC_RECURRENCE(gnc_recurrence_new ());
857 gnc_recurrence_set (gr, gnc_budget_get_recurrence (priv->budget));
858 gtk_box_pack_start (GTK_BOX(gbhb), GTK_WIDGET(gr), TRUE, TRUE, 0);
859 gtk_widget_show (GTK_WIDGET(gr));
860
861 gbnumperiods = GTK_WIDGET(gtk_builder_get_object (builder, "BudgetNumPeriods"));
862 gtk_spin_button_set_value (GTK_SPIN_BUTTON(gbnumperiods), gnc_budget_get_num_periods (priv->budget));
863
864 show_account_code = GTK_WIDGET(gtk_builder_get_object (builder, "ShowAccountCode"));
865 show_account_desc = GTK_WIDGET(gtk_builder_get_object (builder, "ShowAccountDescription"));
866
867 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(show_account_code),
868 gnc_budget_view_get_show_account_code (priv->budget_view));
869
870 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(show_account_desc),
871 gnc_budget_view_get_show_account_description (priv->budget_view));
872
873 gtk_widget_show_all (priv->dialog);
874 result = gtk_dialog_run (GTK_DIALOG(priv->dialog));
875
876 switch (result)
877 {
878 case GTK_RESPONSE_OK:
879 name = (gchar *) gtk_entry_get_text (GTK_ENTRY(gbname));
880 DEBUG("%s", name);
881 if (name)
882 {
883 gchar* label;
884 gnc_budget_set_name (priv->budget, name);
885 label = g_strdup_printf ("%s: %s", _("Budget"), name);
886 main_window_update_page_name (GNC_PLUGIN_PAGE(page), label);
887 g_free (label);
888 }
889
890 gtk_text_buffer_get_bounds (gtk_text_view_get_buffer (GTK_TEXT_VIEW(gbtreeview)), &start, &end);
891 desc = gtk_text_buffer_get_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW(gbtreeview)), &start, &end, TRUE);
892
893 gnc_budget_set_description (priv->budget, desc);
894 g_free (desc);
895
896 show_ac = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(show_account_code));
897 gnc_budget_view_set_show_account_code (priv->budget_view, show_ac);
898
899 show_ad = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(show_account_desc));
900 gnc_budget_view_set_show_account_description (priv->budget_view, show_ad);
901
902 // if show account code or description is set then set feature
903 if ((show_ac || show_ad) && (!gnc_features_check_used (gnc_get_current_book (),
904 GNC_FEATURE_BUDGET_SHOW_EXTRA_ACCOUNT_COLS)))
905 {
906 gnc_features_set_used (gnc_get_current_book (), GNC_FEATURE_BUDGET_SHOW_EXTRA_ACCOUNT_COLS);
907 }
908
909 num_periods = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(gbnumperiods));
910 gnc_budget_set_num_periods (priv->budget, num_periods);
911
912 r = gnc_recurrence_get (gr);
913 gnc_budget_set_recurrence (priv->budget, r);
914 break;
915 case GTK_RESPONSE_CANCEL:
916 break;
917 default:
918 break;
919 }
920 g_object_unref (G_OBJECT(builder));
921 gtk_widget_destroy (priv->dialog);
922 }
923 priv->dialog = NULL;
924}
925
926
927void
928gnc_budget_gui_delete_budget (GncBudget *budget)
929{
930 const char *name;
931
932 g_return_if_fail (GNC_IS_BUDGET(budget));
933 name = gnc_budget_get_name (budget);
934 if (!name)
935 name = _("Unnamed Budget");
936
937 if (gnc_verify_dialog (NULL, FALSE, _("Delete %s?"), name))
938 {
939 QofBook* book = gnc_get_current_book ();
940
941 gnc_suspend_gui_refresh ();
942 gnc_budget_destroy (budget);
943
944 if (qof_collection_count (qof_book_get_collection (book, GNC_ID_BUDGET)) == 0)
945 {
946 gnc_features_set_unused (book, GNC_FEATURE_BUDGET_UNREVERSED);
947 PWARN ("No budgets left. Removing feature BUDGET_UNREVERSED.");
948 }
949 // Views should close themselves because the CM will notify them.
950 gnc_resume_gui_refresh ();
951 }
952}
953
954
955static void
956estimate_budget_helper (GtkTreeModel *model, GtkTreePath *path,
957 GtkTreeIter *iter, gpointer data)
958{
959 Account *acct;
960 guint num_periods, i;
961 gnc_numeric num;
963 auto page = GNC_PLUGIN_PAGE_BUDGET(data);
964
965 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
966 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
967
968 acct = gnc_budget_view_get_account_from_path (priv->budget_view, path);
969
970 num_periods = gnc_budget_get_num_periods (priv->budget);
971
972 if (priv->useAvg && num_periods)
973 {
974 num = xaccAccountGetNoclosingBalanceChangeForPeriod
975 (acct, recurrenceGetPeriodTime (&priv->r, 0, FALSE),
976 recurrenceGetPeriodTime (&priv->r, num_periods - 1, TRUE), TRUE);
977
978 num = gnc_numeric_div (num,
979 gnc_numeric_create (num_periods, 1),
981 GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
982 GNC_HOW_RND_ROUND_HALF_UP);
983
984 for (i = 0; i < num_periods; i++)
985 {
986 gnc_budget_set_account_period_value (priv->budget, acct, i, num);
987 }
988 }
989 else
990 {
991 for (i = 0; i < num_periods; i++)
992 {
993 num = xaccAccountGetNoclosingBalanceChangeForPeriod
994 (acct, recurrenceGetPeriodTime (&priv->r, i, FALSE),
995 recurrenceGetPeriodTime (&priv->r, i, TRUE), TRUE);
996
997 if (!gnc_numeric_check (num))
998 {
999 num = gnc_numeric_convert (num, GNC_DENOM_AUTO,
1000 GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
1001 GNC_HOW_RND_ROUND_HALF_UP);
1002 gnc_budget_set_account_period_value (priv->budget, acct, i, num);
1003 }
1004 }
1005 }
1006}
1007
1008
1009/*******************************/
1010/* Estimate Dialog */
1011/*******************************/
1012static void
1013gnc_plugin_page_budget_cmd_estimate_budget (GSimpleAction *simple,
1014 GVariant *parameter,
1015 gpointer user_data)
1016{
1017 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1019 GtkTreeSelection *sel;
1020 GtkWidget *dialog, *gde, *dtr, *hb, *avg;
1021 gint result;
1022 GDate date;
1023 const Recurrence *r;
1024 GtkBuilder *builder;
1025
1026 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
1027 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1028
1029 sel = gnc_budget_view_get_selection (priv->budget_view);
1030
1031 if (gtk_tree_selection_count_selected_rows (sel) <= 0)
1032 {
1033 dialog = gtk_message_dialog_new (
1034 GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))),
1035 (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL),
1036 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
1037 _("You must select at least one account to estimate."));
1038 gtk_dialog_run (GTK_DIALOG(dialog));
1039 gtk_widget_destroy (dialog);
1040 return;
1041 }
1042
1043 builder = gtk_builder_new ();
1044 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "DigitsToRound_Adj");
1045 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade", "budget_estimate_dialog");
1046
1047 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "budget_estimate_dialog"));
1048
1049 gtk_window_set_transient_for (GTK_WINDOW(dialog),
1050 GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))));
1051
1052 hb = GTK_WIDGET(gtk_builder_get_object (builder, "StartDate_hbox"));
1053 gde = gnc_date_edit_new (time (NULL), FALSE, FALSE);
1054 gtk_box_pack_start (GTK_BOX(hb), gde, TRUE, TRUE, 0);
1055 gtk_widget_show (gde);
1056
1057 date = recurrenceGetDate (&priv->r);
1058 gnc_date_edit_set_gdate (GNC_DATE_EDIT(gde), &date);
1059
1060 dtr = GTK_WIDGET(gtk_builder_get_object (builder, "DigitsToRound"));
1061 gtk_spin_button_set_value (GTK_SPIN_BUTTON(dtr),
1062 (gdouble)priv->sigFigs);
1063
1064 avg = GTK_WIDGET(gtk_builder_get_object (builder, "UseAverage"));
1065 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(avg), priv->useAvg);
1066
1067 gtk_widget_show_all (dialog);
1068 result = gtk_dialog_run (GTK_DIALOG(dialog));
1069 switch (result)
1070 {
1071 case GTK_RESPONSE_OK:
1072 r = gnc_budget_get_recurrence (priv->budget);
1073
1074 gnc_date_edit_get_gdate (GNC_DATE_EDIT(gde), &date);
1075 recurrenceSet (&priv->r, recurrenceGetMultiplier (r),
1076 recurrenceGetPeriodType (r), &date,
1077 recurrenceGetWeekendAdjust (r));
1078 priv->sigFigs =
1079 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(dtr));
1080
1081 priv->useAvg = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(avg));
1082
1083 gnc_budget_begin_edit (priv->budget);
1084 gtk_tree_selection_selected_foreach (sel, estimate_budget_helper, page);
1085 gnc_budget_commit_edit (priv->budget);
1086 break;
1087 default:
1088 break;
1089 }
1090 gtk_widget_destroy (dialog);
1091 g_object_unref (G_OBJECT(builder));
1092}
1093
1094static void
1095allperiods_budget_helper (GtkTreeModel *model, GtkTreePath *path,
1096 GtkTreeIter *iter, gpointer data)
1097{
1098 Account *acct;
1099 guint num_periods, i;
1100 gnc_numeric num, allvalue;
1102 auto page = GNC_PLUGIN_PAGE_BUDGET(data);
1103
1104 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
1105 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1106 acct = gnc_budget_view_get_account_from_path (priv->budget_view, path);
1107 num_periods = gnc_budget_get_num_periods (priv->budget);
1108 allvalue = priv->allValue;
1109
1110 if (gnc_reverse_balance (acct))
1111 allvalue = gnc_numeric_neg (allvalue);
1112
1113 for (i = 0; i < num_periods; i++)
1114 {
1115 switch (priv->action)
1116 {
1117 case ADD:
1118 num = gnc_budget_get_account_period_value (priv->budget, acct, i);
1119 num = gnc_numeric_add (num, allvalue, GNC_DENOM_AUTO,
1120 GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
1121 GNC_HOW_RND_ROUND_HALF_UP);
1122 gnc_budget_set_account_period_value (priv->budget, acct, i, num);
1123 break;
1124 case MULTIPLY:
1125 num = gnc_budget_get_account_period_value (priv->budget, acct, i);
1126 num = gnc_numeric_mul (num, priv->allValue, GNC_DENOM_AUTO,
1127 GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
1128 GNC_HOW_RND_ROUND_HALF_UP);
1129 gnc_budget_set_account_period_value (priv->budget, acct, i, num);
1130 break;
1131 case UNSET:
1132 gnc_budget_unset_account_period_value (priv->budget, acct, i);
1133 break;
1134 default:
1135 gnc_budget_set_account_period_value (priv->budget, acct, i,
1136 allvalue);
1137 break;
1138 }
1139 }
1140}
1141
1142/*******************************/
1143/* All Periods Value Dialog */
1144/*******************************/
1145static void
1146gnc_plugin_page_budget_cmd_allperiods_budget (GSimpleAction *simple,
1147 GVariant *parameter,
1148 gpointer user_data)
1149{
1150 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1152 GtkTreeSelection *sel;
1153 GtkWidget *dialog, *val, *dtr, *add, *mult;
1154 gint result;
1155 GtkBuilder *builder;
1156 const gchar *txt;
1157
1158 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
1159 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1160 sel = gnc_budget_view_get_selection (priv->budget_view);
1161
1162 if (gtk_tree_selection_count_selected_rows (sel) <= 0)
1163 {
1164 dialog = gtk_message_dialog_new (
1165 GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))),
1166 (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL),
1167 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
1168 _("You must select at least one account to edit."));
1169 gtk_dialog_run (GTK_DIALOG(dialog));
1170 gtk_widget_destroy (dialog);
1171 return;
1172 }
1173
1174 builder = gtk_builder_new ();
1175 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade",
1176 "DigitsToRound_Adj");
1177 gnc_builder_add_from_file (builder, "gnc-plugin-page-budget.glade",
1178 "budget_allperiods_dialog");
1179
1180 dialog = GTK_WIDGET(
1181 gtk_builder_get_object (builder, "budget_allperiods_dialog"));
1182
1183 gtk_window_set_transient_for (
1184 GTK_WINDOW(dialog),
1185 GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page))));
1186
1187 val = GTK_WIDGET(gtk_builder_get_object (builder, "Value"));
1188 gtk_entry_set_text (GTK_ENTRY(val), "");
1189
1190 dtr = GTK_WIDGET(gtk_builder_get_object (builder, "DigitsToRound1"));
1191 gtk_spin_button_set_value (GTK_SPIN_BUTTON(dtr), (gdouble)priv->sigFigs);
1192
1193 add = GTK_WIDGET(gtk_builder_get_object (builder, "RB_Add"));
1194 mult = GTK_WIDGET(gtk_builder_get_object (builder, "RB_Multiply"));
1195
1196 gtk_widget_show_all (dialog);
1197 result = gtk_dialog_run (GTK_DIALOG(dialog));
1198 switch (result)
1199 {
1200 case GTK_RESPONSE_OK:
1201
1202 priv->sigFigs = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(dtr));
1203 priv->action = REPLACE;
1204 txt = gtk_entry_get_text (GTK_ENTRY(val));
1205
1206 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(add)))
1207 priv->action = ADD;
1208 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(mult)))
1209 priv->action = MULTIPLY;
1210
1211 if (priv->action == REPLACE &&
1212 !gtk_entry_get_text_length (GTK_ENTRY(val)))
1213 priv->action = UNSET;
1214
1215 if (xaccParseAmount (txt, TRUE, &priv->allValue, NULL) ||
1216 priv->action == UNSET)
1217 {
1218 gnc_budget_begin_edit (priv->budget);
1219 gtk_tree_selection_selected_foreach (sel, allperiods_budget_helper,
1220 page);
1221 gnc_budget_commit_edit (priv->budget);
1222 }
1223 break;
1224 default:
1225 break;
1226 }
1227 gtk_widget_destroy (dialog);
1228 g_object_unref (G_OBJECT(builder));
1229}
1230
1231static void
1232gnc_plugin_page_budget_cmd_budget_note (GSimpleAction *simple,
1233 GVariant *parameter,
1234 gpointer user_data)
1235{
1236 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1238 GtkWidget *dialog, *note;
1239 gint result;
1240 GtkBuilder *builder;
1241 gchar *txt;
1242 GtkTreeViewColumn *col = NULL;
1243 GtkTreePath *path = NULL;
1244 guint period_num = 0;
1245 Account *acc = NULL;
1246
1247 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
1248 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1249 gtk_tree_view_get_cursor(
1250 GTK_TREE_VIEW(gnc_budget_view_get_account_tree_view(priv->budget_view)),
1251 &path, &col);
1252
1253 if (path)
1254 {
1255 period_num = col ? GPOINTER_TO_UINT(
1256 g_object_get_data(G_OBJECT(col), "period_num"))
1257 : 0;
1258
1259 acc = gnc_budget_view_get_account_from_path(priv->budget_view, path);
1260 gtk_tree_path_free(path);
1261 }
1262
1263 if (!acc)
1264 {
1265 dialog = gtk_message_dialog_new(
1266 GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page))),
1267 (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL),
1268 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
1269 _("You must select one budget cell to edit."));
1270 gtk_dialog_run(GTK_DIALOG(dialog));
1271 gtk_widget_destroy(dialog);
1272 return;
1273 }
1274
1275 builder = gtk_builder_new();
1276 gnc_builder_add_from_file(builder, "gnc-plugin-page-budget.glade",
1277 "budget_note_dialog");
1278
1279 dialog = GTK_WIDGET(gtk_builder_get_object(builder, "budget_note_dialog"));
1280
1281 gtk_window_set_transient_for(
1282 GTK_WINDOW(dialog),
1283 GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page))));
1284
1285 note = GTK_WIDGET(gtk_builder_get_object(builder, "BudgetNote"));
1286 xxxgtk_textview_set_text(GTK_TEXT_VIEW(note),
1287 gnc_budget_get_account_period_note(priv->budget, acc, period_num));
1288
1289 gtk_widget_show_all(dialog);
1290 result = gtk_dialog_run(GTK_DIALOG(dialog));
1291 switch (result)
1292 {
1293 case GTK_RESPONSE_OK:
1294 txt = xxxgtk_textview_get_text(GTK_TEXT_VIEW(note));
1295 gnc_budget_set_account_period_note (priv->budget, acc, period_num,
1296 (txt && *txt) ? txt : NULL);
1297 g_free (txt);
1298 break;
1299 default:
1300 break;
1301 }
1302 gtk_widget_destroy(dialog);
1303 g_object_unref(G_OBJECT(builder));
1304}
1305
1306static gboolean
1307equal_fn (gpointer find_data, gpointer elt_data)
1308{
1309 return (find_data && (find_data == elt_data));
1310}
1311
1312/* From the budget editor, open the budget report. This will reuse the
1313 budget report if generated from the current budget editor. Note the
1314 reuse is lost when GnuCash is restarted. This link may be restored
1315 by: scan the current session tabs, identify reports, checking
1316 whereby report's report-type matches a budget report, and the
1317 report's budget option value matches the current budget. */
1318static void
1319gnc_plugin_page_budget_cmd_budget_report (GSimpleAction *simple,
1320 GVariant *parameter,
1321 gpointer user_data)
1322{
1323 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1325
1326 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET (page));
1327
1328 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE (page);
1329
1330 if (gnc_find_first_gui_component (WINDOW_REPORT_CM_CLASS, equal_fn,
1331 priv->reportPage))
1332 gnc_plugin_page_report_reload (GNC_PLUGIN_PAGE_REPORT (priv->reportPage));
1333 else
1334 {
1335 SCM func = scm_c_eval_string ("gnc:budget-report-create");
1336 SCM arg = SWIG_NewPointerObj (priv->budget, SWIG_TypeQuery ("_p_budget_s"), 0);
1337 int report_id;
1338
1339 g_return_if_fail (scm_is_procedure (func));
1340
1341 arg = scm_apply_0 (func, scm_list_1 (arg));
1342 g_return_if_fail (scm_is_exact (arg));
1343
1344 report_id = scm_to_int (arg);
1345 g_return_if_fail (report_id >= 0);
1346
1347 priv->reportPage = gnc_plugin_page_report_new (report_id);
1348 }
1349
1350 gnc_main_window_open_page (GNC_MAIN_WINDOW (priv->dialog), priv->reportPage);
1351}
1352
1353static void
1354gnc_plugin_page_budget_cmd_view_filter_by (GSimpleAction *simple,
1355 GVariant *parameter,
1356 gpointer user_data)
1357{
1358 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1360
1361 g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
1362 ENTER("(action %p, page %p)", simple, page);
1363
1364 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1365 account_filter_dialog_create (&priv->fd, GNC_PLUGIN_PAGE(page));
1366
1367 LEAVE(" ");
1368}
1369
1370static void
1371gnc_plugin_page_budget_cmd_refresh (GSimpleAction *simple,
1372 GVariant *parameter,
1373 gpointer user_data)
1374{
1375 auto page = GNC_PLUGIN_PAGE_BUDGET (user_data);
1377
1378 g_return_if_fail (GNC_IS_PLUGIN_PAGE_BUDGET(page));
1379 ENTER("(action %p, page %p)", simple, page);
1380
1381 priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
1382
1383 gnc_budget_view_refresh (priv->budget_view);
1384 LEAVE(" ");
1385}
GnuCash Budgets.
Utility functions for file access.
Gnome specific utility functions.
Gobject helper routines.
Functions for adding content to a window.
Functions providing a register page for the GnuCash UI.
GtkTreeModel implementation to display account types in a GtkTreeView.
GtkTreeView implementation for gnucash account tree.
utility functions for the GnuCash UI
Functions that are supported by all types of windows.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition qofbook.cpp:521
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition qofbook.cpp:497
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
GSimpleActionGroup * gnc_plugin_page_get_action_group(GncPluginPage *page)
Retrieve the GSimpleActionGroup object associated with this page.
guint qof_collection_count(const QofCollection *col)
return the number of entities in the collection.
Definition qofid.cpp:221
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
gboolean gnc_main_window_button_press_cb(GtkWidget *whatever, GdkEventButton *event, GncPluginPage *page)
Callback function invoked when the user clicks in the content of any Gnucash window.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
void gnc_main_window_init_short_names(GncMainWindow *window, GncToolBarShortNames *toolbar_labels)
Update the labels of the toolbar items with short names.
void main_window_update_page_name(GncPluginPage *page, const gchar *name_in)
Update the name of the page in the main window.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
void gnc_main_window_update_menu_and_toolbar(GncMainWindow *window, GncPluginPage *page, const gchar **ui_updates)
Update the main window menu with the placeholders listed in ui_updates and load the page specific too...
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
const GList * gnc_gobject_tracking_get_list(const gchar *name)
Get a list of all known objects of a specified type.
GncPluginPage * gnc_plugin_page_report_new(int reportId)
GList * gnc_tree_view_account_get_selected_accounts(GncTreeViewAccount *view)
This function returns a list of the accounts associated with the selected items in the account tree v...
gboolean xaccParseAmount(const char *in_str, gboolean monetary, gnc_numeric *result, char **endstr)
Parses in_str to obtain a numeric result.
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
void gnc_plugin_set_actions_enabled(GActionMap *action_map, const gchar **action_names, gboolean enable)
This function sets the sensitivity of a GAction in a specific group.
Definition gnc-plugin.c:250
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
#define GNC_HOW_DENOM_SIGFIGS(n)
Build a 'how' value that will generate a denominator that will keep at least n significant figures in...
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
GncPluginPage * gnc_plugin_page_register_new(Account *account, gboolean subaccounts)
Create a new "register" plugin page, given a pointer to an account.
void gnc_features_set_unused(QofBook *book, const gchar *feature)
Indicate that the current book does not use the given feature.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
void gnc_budget_set_num_periods(GncBudget *budget, guint num_periods)
Set/Get the number of periods in the Budget.
void gnc_budget_destroy(GncBudget *budget)
Deletes the given budget object.
GncPluginPage * gnc_plugin_page_budget_new(GncBudget *budget)
Create a new "budget" plugin page.
void gnc_budget_view_refresh(GncBudgetView *budget_view)
refreshes the current budget view
void gnc_budget_set_description(GncBudget *budget, const gchar *description)
Set/Get the description of the Budget.
GtkTreeSelection * gnc_budget_view_get_selection(GncBudgetView *budget_view)
returns the current selection in the gnc budget view.
GncBudgetView * gnc_budget_view_new(GncBudget *budget, AccountFilterDialog *fd)
Create new gnc budget view.
void gnc_budget_set_name(GncBudget *budget, const gchar *name)
Set/Get the name of the Budget.
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
The class data structure for a content plugin.
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
const gchar * plugin_name
The textual name of this plugin.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
The instance data structure for a content plugin.
GtkWidget * window
The window that contains the display widget for this plugin.
A structure for defining alternate action names for use in the toolbar.
QofBook reference.
Definition qofbook-p.hpp:47