Merge Adrién Panella's 'budget' into maint.

pull/513/head
John Ralls 7 years ago
commit 2d4f771bed

@ -118,10 +118,8 @@ static void gbv_create_widget(GncBudgetView *view);
static gboolean gbv_button_press_cb(
GtkWidget *widget, GdkEventButton *event, GncBudgetView *view);
#endif
#if 0
static gboolean gbv_key_press_cb(
GtkWidget *treeview, GdkEventKey *event, gpointer userdata);
#endif
static gboolean gbv_key_press_cb(GtkWidget *treeview, GdkEventKey *event,
gpointer userdata);
static void gbv_row_activated_cb(
GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col,
GncBudgetView *view);
@ -163,11 +161,10 @@ struct GncBudgetViewPrivate
GtkTreeViewColumn* total_col;
AccountFilterDialog *fd;
Account* income;
Account* expenses;
Account* assets;
Account* liabilities;
Account* rootAcct;
GtkCellRenderer *temp_cr;
GtkCellEditable *temp_ce;
};
G_DEFINE_TYPE_WITH_PRIVATE(GncBudgetView, gnc_budget_view, GTK_TYPE_BOX)
@ -234,29 +231,6 @@ gnc_budget_view_init(GncBudgetView *budget_view)
priv->rootAcct = root;
for (i = 0; i < num_top_accounts; ++i)
{
Account* acc = gnc_account_nth_child(root, i);
GNCAccountType type = xaccAccountGetType(acc);
if (type == ACCT_TYPE_ASSET)
{
priv->assets = acc;
}
else if (type == ACCT_TYPE_LIABILITY)
{
priv->liabilities = acc;
}
else if (type == ACCT_TYPE_INCOME)
{
priv->income = acc;
}
else if (type == ACCT_TYPE_EXPENSE)
{
priv->expenses = acc;
}
}
LEAVE("");
}
@ -427,9 +401,6 @@ gbv_create_widget(GncBudgetView *view)
G_CALLBACK(gbv_selection_changed_cb), view);
g_signal_connect(G_OBJECT(tree_view), "button-press-event",
G_CALLBACK(gbv_button_press_cb), view);
g_signal_connect_after(G_OBJECT(tree_view), "key-press-event",
G_CALLBACK(gbv_key_press_cb), NULL);
gbv_selection_changed_cb(NULL, view);
#endif
@ -669,39 +640,103 @@ gbv_button_press_cb(GtkWidget *widget, GdkEventButton *event,
}
#endif
#if 0
/** \brief Key press action for gnc budget view.
/** \brief Key press action for gnc budget view when in editing mode.
* Used for navigating with tab while editing.
* The handler is for the cell-editable, not for the treeview
*/
static gboolean
gbv_key_press_cb(GtkWidget *treeview, GdkEventKey *event, gpointer userdata)
gbv_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer userdata)
{
GtkTreeView *tv = GTK_TREE_VIEW(treeview);
GtkTreeViewColumn *col;
GtkTreePath *path = NULL;
if (event->type != GDK_KEY_PRESS) return TRUE;
GtkTreePath *path = NULL;
GncBudgetViewPrivate *priv = GNC_BUDGET_VIEW_GET_PRIVATE(userdata);
GtkTreeView *tv = priv->tree_view;
gboolean shifted;
gint period_num, num_periods;
gpointer data;
if (event->type != GDK_KEY_PRESS || !priv->temp_cr)
return FALSE;
switch (event->keyval)
{
case GDK_KEY_Tab:
case GDK_KEY_ISO_Left_Tab:
case GDK_KEY_KP_Tab:
case GDK_KEY_Return:
case GDK_KEY_KP_Enter:
shifted = event->state & GDK_SHIFT_MASK;
gtk_tree_view_get_cursor(tv, &path, &col);
if (!path) return TRUE;
//finish_edit(col);
if (!path)
return TRUE;
data = g_object_get_data(G_OBJECT(col), "period_num");
period_num = GPOINTER_TO_UINT(data);
num_periods = gnc_budget_get_num_periods(priv->budget);
if (period_num >= num_periods)
period_num = num_periods - 1;
if (shifted)
period_num--;
else
period_num++;
if (period_num >= num_periods)
{
period_num = 0;
if (gtk_tree_view_row_expanded(tv, path))
{
gtk_tree_path_down(path);
}
else
{
gtk_tree_path_next(path);
while (!gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path) &&
gtk_tree_path_get_depth(path) > 1)
{
gtk_tree_path_up(path);
gtk_tree_path_next(path);
}
}
}
else if (period_num < 0)
{
period_num = num_periods - 1;
if (!gtk_tree_path_prev(path))
gtk_tree_path_up(path);
else
while (gtk_tree_view_row_expanded(tv, path))
{
gtk_tree_path_down(path);
do
{
gtk_tree_path_next(path);
} while (
gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path));
gtk_tree_path_prev(path);
}
}
col = g_list_nth_data(priv->period_col_list, period_num);
// finish editing
if (priv->temp_ce)
{
gtk_cell_editable_editing_done(priv->temp_ce);
gtk_cell_editable_remove_widget(priv->temp_ce);
while (gtk_events_pending())
gtk_main_iteration();
}
if (gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path))
gtk_tree_view_set_cursor(tv, path, col, TRUE);
gtk_tree_path_free(path);
break;
default:
return TRUE;
return FALSE;
}
gnc_tree_view_keynav(GNC_TREE_VIEW(tv), &col, path, event);
if (path && gnc_tree_view_path_is_valid(GNC_TREE_VIEW(tv), path))
gtk_tree_view_set_cursor(tv, path, col, TRUE);
return TRUE;
}
#endif
/** \brief gnc budget view actions for resize of treeview.
*/
@ -804,6 +839,8 @@ typedef struct
gnc_numeric total;
GncBudget* budget;
guint period_num;
GNCPriceDB *pdb;
gnc_commodity *total_currency;
} BudgetAccumulationInfo;
/** \brief Function to assist in the calculation of sub-account totals.
@ -815,16 +852,29 @@ budget_accum_helper(Account* account, gpointer data)
{
BudgetAccumulationInfo* info = (BudgetAccumulationInfo*)data;
gnc_numeric numeric;
gnc_commodity *currency;
currency = gnc_account_get_currency_or_parent(account);
if (gnc_budget_is_account_period_value_set(info->budget, account, info->period_num))
{
numeric = gnc_budget_get_account_period_value(info->budget, account, info->period_num);
info->total = gnc_numeric_add(info->total, numeric, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
numeric = gnc_budget_get_account_period_value(info->budget, account,
info->period_num);
numeric = gnc_pricedb_convert_balance_nearest_price_t64(
info->pdb, numeric, currency, info->total_currency,
gnc_budget_get_period_start_date(info->budget, info->period_num));
info->total = gnc_numeric_add(info->total, numeric, GNC_DENOM_AUTO,
GNC_HOW_DENOM_LCD);
}
else if (gnc_account_n_children(account) != 0)
{
numeric = gbv_get_accumulated_budget_amount(info->budget, account, info->period_num);
info->total = gnc_numeric_add(info->total, numeric, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
numeric = gbv_get_accumulated_budget_amount(info->budget, account,
info->period_num);
numeric = gnc_pricedb_convert_balance_nearest_price_t64(
info->pdb, numeric, currency, info->total_currency,
gnc_budget_get_period_start_date(info->budget, info->period_num));
info->total = gnc_numeric_add(info->total, numeric, GNC_DENOM_AUTO,
GNC_HOW_DENOM_LCD);
}
}
@ -840,6 +890,8 @@ gbv_get_accumulated_budget_amount(GncBudget* budget, Account* account, guint per
info.total = gnc_numeric_zero();
info.budget = budget;
info.period_num = period_num;
info.pdb = gnc_pricedb_get_db (gnc_account_get_book (account));
info.total_currency = gnc_account_get_currency_or_parent(account);
if (!gnc_budget_is_account_period_value_set(budget, account, period_num))
{
@ -852,6 +904,19 @@ gbv_get_accumulated_budget_amount(GncBudget* budget, Account* account, guint per
return info.total;
}
static gchar*
get_negative_color (void)
{
GdkRGBA color;
GtkWidget *label = gtk_label_new ("Color");
GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(label));
gtk_style_context_add_class (context, "negative-numbers");
gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color);
gtk_widget_destroy(label);
return gdk_rgba_to_string(&color);
}
/** \brief Calculates and displays budget amount for a period in a defined account.
Displays budget amount for a period for an account. If a budget
@ -868,6 +933,7 @@ budget_col_source(Account *account, GtkTreeViewColumn *col,
guint period_num;
gnc_numeric numeric;
gchar amtbuff[100]; //FIXME: overkill, where's the #define?
gboolean red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
budget = GNC_BUDGET(g_object_get_data(G_OBJECT(col), "budget"));
bview = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(col), "budget_view"));
@ -889,10 +955,18 @@ budget_col_source(Account *account, GtkTreeViewColumn *col,
numeric = gbv_get_accumulated_budget_amount(budget, account, period_num);
xaccSPrintAmount(amtbuff, numeric,
gnc_account_print_info(account, FALSE));
if (gnc_is_dark_theme (&color))
g_object_set(cell, "foreground", "darkgray", NULL);
if (gnc_is_dark_theme(&color))
g_object_set(cell, "foreground",
red && gnc_numeric_negative_p(numeric)
? "darkred"
: "darkgray",
NULL);
else
g_object_set(cell, "foreground", "dimgray", NULL);
g_object_set(cell, "foreground",
red && gnc_numeric_negative_p(numeric)
? "PaleVioletRed"
: "dimgray",
NULL);
}
}
else
@ -907,7 +981,11 @@ budget_col_source(Account *account, GtkTreeViewColumn *col,
{
xaccSPrintAmount(amtbuff, numeric,
gnc_account_print_info(account, FALSE));
g_object_set(cell, "foreground", NULL, NULL);
g_object_set(cell, "foreground",
red && gnc_numeric_negative_p(numeric)
? get_negative_color()
: NULL,
NULL);
}
}
return g_strdup(amtbuff);
@ -917,12 +995,20 @@ budget_col_source(Account *account, GtkTreeViewColumn *col,
totals column to the right.
*/
static gnc_numeric
bgv_get_total_for_account(Account* account, GncBudget* budget)
bgv_get_total_for_account(Account* account, GncBudget* budget, gnc_commodity *new_currency)
{
guint num_periods;
int period_num;
gnc_numeric numeric;
gnc_numeric total = gnc_numeric_zero();
GNCPriceDB *pdb;
gnc_commodity *currency;
if (new_currency)
{
pdb = gnc_pricedb_get_db(gnc_get_current_book());
currency = gnc_account_get_currency_or_parent(account);
}
num_periods = gnc_budget_get_num_periods(budget);
for (period_num = 0; period_num < num_periods; ++period_num)
@ -932,6 +1018,13 @@ bgv_get_total_for_account(Account* account, GncBudget* budget)
if (gnc_account_n_children(account) != 0)
{
numeric = gbv_get_accumulated_budget_amount(budget, account, period_num);
if (new_currency)
{
numeric = gnc_pricedb_convert_balance_nearest_price_t64(
pdb, numeric, currency, new_currency,
gnc_budget_get_period_start_date(budget, period_num));
}
total = gnc_numeric_add(total, numeric, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
}
@ -940,6 +1033,12 @@ bgv_get_total_for_account(Account* account, GncBudget* budget)
numeric = gnc_budget_get_account_period_value(budget, account, period_num);
if (!gnc_numeric_check(numeric))
{
if (new_currency)
{
numeric = gnc_pricedb_convert_balance_nearest_price_t64(
pdb, numeric, currency, new_currency,
gnc_budget_get_period_start_date(budget, period_num));
}
total = gnc_numeric_add(total, numeric, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
}
@ -956,11 +1055,14 @@ budget_total_col_source(Account *account, GtkTreeViewColumn *col,
GncBudget *budget;
gnc_numeric total;
gchar amtbuff[100]; //FIXME: overkill, where's the #define?
gboolean red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
budget = GNC_BUDGET(g_object_get_data(G_OBJECT(col), "budget"));
total = bgv_get_total_for_account(account, budget);
total = bgv_get_total_for_account(account, budget, NULL);
xaccSPrintAmount(amtbuff, total,
gnc_account_print_info(account, FALSE));
gnc_account_print_info(account, TRUE));
g_object_set(cell, "foreground",
red && gnc_numeric_negative_p(total) ? get_negative_color () : NULL, NULL);
return g_strdup(amtbuff);
}
@ -1022,107 +1124,92 @@ totals_col_source(GtkTreeViewColumn *col, GtkCellRenderer *cell,
gchar amtbuff[100]; //FIXME: overkill, where's the #define?
gint i;
gint num_top_accounts;
gboolean neg, red;
GNCPriceDB *pdb;
gnc_commodity *total_currency, *currency;
gnc_numeric totalincome = gnc_numeric_zero();
gnc_numeric totalexpenses = gnc_numeric_zero();
gnc_numeric totalassets = gnc_numeric_zero();
gnc_numeric totalliabilities = gnc_numeric_zero();
gnc_numeric total = gnc_numeric_zero();
view = GNC_BUDGET_VIEW(user_data);
priv = GNC_BUDGET_VIEW_GET_PRIVATE(view);
red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
gtk_tree_model_get(s_model, s_iter, 1, &row_type, -1);
budget = GNC_BUDGET(g_object_get_data(G_OBJECT(col), "budget"));
period_num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(col),
"period_num"));
pdb = gnc_pricedb_get_db (gnc_get_current_book());
total_currency = gnc_default_currency();
num_top_accounts = gnc_account_n_children(priv->rootAcct);
// step through each child account of the root, find the total income, expenses, liabilities, and assets.
for (i = 0; i < num_top_accounts; ++i)
{
account = gnc_account_nth_child(priv->rootAcct, i);
account = gnc_account_nth_child(priv->rootAcct, i);
currency = gnc_account_get_currency_or_parent(account);
neg = FALSE;
switch (xaccAccountGetType(account))
{
case ACCT_TYPE_INCOME:
if (row_type != TOTALS_TYPE_INCOME &&
row_type != TOTALS_TYPE_TOTAL)
continue;
break;
case ACCT_TYPE_LIABILITY:
case ACCT_TYPE_EQUITY:
if (row_type != TOTALS_TYPE_TRANSFERS &&
row_type != TOTALS_TYPE_TOTAL)
continue;
break;
case ACCT_TYPE_EXPENSE:
if (row_type == TOTALS_TYPE_TOTAL)
neg = TRUE;
else if (row_type != TOTALS_TYPE_EXPENSES)
continue;
break;
case ACCT_TYPE_ASSET:
if (row_type != TOTALS_TYPE_TRANSFERS &&
row_type != TOTALS_TYPE_TOTAL)
continue;
neg = TRUE;
break;
default:
continue;
}
// find the total for this account
if (period_num < 0)
{
value = bgv_get_total_for_account(account, budget);
value = bgv_get_total_for_account(account, budget, total_currency);
}
else
{
value = gbv_get_accumulated_budget_amount(budget, account, period_num);
}
value =
gbv_get_accumulated_budget_amount(budget, account, period_num);
// test for what account type, and add 'value' to the appopriate total
if (xaccAccountGetType(account) == ACCT_TYPE_INCOME)
{
totalincome = gnc_numeric_add(totalincome, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
else if (xaccAccountGetType(account) == ACCT_TYPE_EXPENSE)
{
totalexpenses = gnc_numeric_add(totalexpenses, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
else if (xaccAccountGetType(account) == ACCT_TYPE_ASSET)
{
totalassets = gnc_numeric_add(totalassets, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
}
else if (xaccAccountGetType(account) == ACCT_TYPE_LIABILITY)
{
totalliabilities = gnc_numeric_add(totalliabilities, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
value = gnc_pricedb_convert_balance_nearest_price_t64(
pdb, value, currency, total_currency,
gnc_budget_get_period_start_date(budget, period_num));
}
if (neg)
total = gnc_numeric_sub(total, value, GNC_DENOM_AUTO,
GNC_HOW_DENOM_LCD);
else
{
// Do nothing because this account is not of interest
}
total = gnc_numeric_add(total, value, GNC_DENOM_AUTO,
GNC_HOW_DENOM_LCD);
}
// at this point we should have variables holding the values for assets, liabilities, expenses and incomes.
// Set the text to display, depending on which of the totals rows we are currently looking at
xaccSPrintAmount(amtbuff, total,
gnc_commodity_print_info(total_currency,
period_num < 0 ? TRUE : FALSE));
g_object_set(cell, "foreground",
red && gnc_numeric_negative_p(total) ? get_negative_color () : NULL, NULL);
if (row_type == TOTALS_TYPE_INCOME)
{
// FIXME: There must be a better way to get the GncAccountPrintInfo object than this. Would prefer to depreciate the tracking of top level accounts.
xaccSPrintAmount(amtbuff, totalincome,
gnc_account_print_info(priv->income, FALSE));
g_object_set(cell, "foreground", NULL, NULL);
}
else if (row_type == TOTALS_TYPE_EXPENSES)
{
xaccSPrintAmount(amtbuff, totalexpenses,
gnc_account_print_info(priv->expenses, FALSE));
g_object_set(cell, "foreground", NULL, NULL);
}
else if (row_type == TOTALS_TYPE_TRANSFERS)
{
xaccSPrintAmount(amtbuff, gnc_numeric_sub(totalassets, totalliabilities, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
gnc_account_print_info(priv->assets, FALSE));
g_object_set(cell, "foreground", NULL, NULL);
}
else if (row_type == TOTALS_TYPE_TOTAL)
{
value = gnc_numeric_sub(totalincome, totalexpenses, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
value = gnc_numeric_sub(value, totalassets, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
value = gnc_numeric_add(value, totalliabilities, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
xaccSPrintAmount(amtbuff, value,
gnc_account_print_info(priv->assets, FALSE));
if (gnc_numeric_negative_p(value))
{
g_object_set(cell, "foreground", "red", NULL);
}
else
{
g_object_set(cell, "foreground", NULL, NULL);
}
}
else
{
// if it reaches here then the row type was not set correctly
g_strlcpy(amtbuff, "error", sizeof(amtbuff));
}
g_object_set(G_OBJECT(cell), "text", amtbuff, "xalign", 1.0, NULL);
}
@ -1218,6 +1305,30 @@ gbv_col_edited_cb(GtkCellRendererText* cell, gchar* path_string, gchar* new_text
gtk_widget_queue_draw(GTK_WIDGET(priv->totals_tree_view));
}
/* The main Start Editing Call back for the budget columns, for key navigation
*/
static void
gdv_editing_started_cb(GtkCellRenderer *cr, GtkCellEditable *editable,
const gchar *path_string, gpointer user_data)
{
GncBudgetViewPrivate *priv = GNC_BUDGET_VIEW_GET_PRIVATE(user_data);
priv->temp_cr = cr;
priv->temp_ce = editable;
g_signal_connect(G_OBJECT(editable), "key-press-event",
G_CALLBACK(gbv_key_press_cb), user_data);
}
static void
gdv_editing_canceled_cb(GtkCellRenderer *cr, gpointer user_data)
{
GncBudgetViewPrivate *priv = GNC_BUDGET_VIEW_GET_PRIVATE(user_data);
priv->temp_cr = NULL;
priv->temp_ce = NULL;
}
/** \brief refreshes the current budget view
The function will step through to only display the columns that are set
@ -1291,7 +1402,10 @@ gnc_budget_view_refresh(GncBudgetView *view)
gbv_renderer_add_padding (renderer);
g_signal_connect(G_OBJECT(renderer), "edited", (GCallback)gbv_col_edited_cb, view);
g_signal_connect(G_OBJECT(renderer), "editing-started",
(GCallback)gdv_editing_started_cb, view);
g_signal_connect(G_OBJECT(renderer), "editing-canceled",
(GCallback)gdv_editing_canceled_cb, view);
col = gbv_create_totals_column(view, num_periods_visible);
if (col != NULL)
{

@ -312,6 +312,13 @@ gnc_budget_gui_select_budget(GtkWindow *parent, QofBook *book)
gtk_container_add(GTK_CONTAINER (gtk_dialog_get_content_area (dlg)), GTK_WIDGET(tv));
gtk_widget_show_all(GTK_WIDGET(dlg));
// Preselect the default budget
bgt = gnc_budget_get_default(book);
if (bgt && gnc_tree_model_budget_get_iter_for_budget(tm, &iter, bgt))
{
gtk_tree_view_set_cursor(tv, gtk_tree_model_get_path(tm, &iter), NULL,
FALSE);
}
bgt = NULL;
response = gtk_dialog_run(dlg);
switch (response)

@ -115,6 +115,8 @@ static void gnc_plugin_page_budget_cmd_view_options(
GtkAction *action, GncPluginPageBudget *page);
static void gnc_plugin_page_budget_cmd_estimate_budget(
GtkAction *action, GncPluginPageBudget *page);
static void gnc_plugin_page_budget_cmd_allperiods_budget(
GtkAction *action, GncPluginPageBudget *page);
static GtkActionEntry gnc_plugin_page_budget_actions [] =
{
@ -151,6 +153,12 @@ static GtkActionEntry gnc_plugin_page_budget_actions [] =
N_("Estimate a budget value for the selected accounts from past transactions"),
G_CALLBACK (gnc_plugin_page_budget_cmd_estimate_budget)
},
{
"AllPeriodsBudgetAction", "system-run", N_("All Periods"),
NULL,
N_("Edit budget for all periods for the selected accounts"),
G_CALLBACK (gnc_plugin_page_budget_cmd_allperiods_budget)
},
/* View menu */
{
@ -179,9 +187,18 @@ static action_toolbar_labels toolbar_labels[] =
{ "DeleteBudgetAction", N_("Delete") },
{ "OptionsBudgetAction", N_("Options") },
{ "EstimateBudgetAction", N_("Estimate") },
{ "AllPeriodsBudgetAction", N_("All Periods") },
{ NULL, NULL },
};
typedef enum allperiods_action
{
REPLACE,
ADD,
MULTIPLY,
UNSET
} allperiods_action;
typedef struct GncPluginPageBudgetPrivate
{
GtkActionGroup *action_group;
@ -204,6 +221,12 @@ typedef struct GncPluginPageBudgetPrivate
/* For the estimation dialog */
Recurrence r;
gint sigFigs;
gboolean useAvg;
/* For the allPeriods value dialog */
gnc_numeric allValue;
allperiods_action action;
} GncPluginPageBudgetPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageBudget, gnc_plugin_page_budget, GNC_TYPE_PLUGIN_PAGE)
@ -309,6 +332,7 @@ gnc_plugin_page_budget_init (GncPluginPageBudget *plugin_page)
priv->fd.filter_override = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->sigFigs = 1;
priv->useAvg = FALSE;
recurrenceSet(&priv->r, 1, PERIOD_MONTH, NULL, WEEKEND_ADJ_NONE);
LEAVE("page %p, priv %p, action group %p",
@ -859,19 +883,40 @@ estimate_budget_helper(GtkTreeModel *model, GtkTreePath *path,
num_periods = gnc_budget_get_num_periods(priv->budget);
for (i = 0; i < num_periods; i++)
if (priv->useAvg && num_periods)
{
num = recurrenceGetAccountPeriodValue(&priv->r, acct, i);
if (!gnc_numeric_check(num))
num = xaccAccountGetBalanceChangeForPeriod(acct,
recurrenceGetPeriodTime(&priv->r, 0, FALSE),
recurrenceGetPeriodTime(&priv->r, num_periods - 1, TRUE), TRUE);
num = gnc_numeric_div(num,
gnc_numeric_create(num_periods, 1),
GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
if (gnc_reverse_balance(acct))
num = gnc_numeric_neg(num);
for (i = 0; i < num_periods; i++)
{
if (gnc_reverse_balance (acct))
num = gnc_numeric_neg (num);
gnc_budget_set_account_period_value(priv->budget, acct, i, num);
}
}
else
{
for (i = 0; i < num_periods; i++)
{
num = recurrenceGetAccountPeriodValue(&priv->r, acct, i);
if (!gnc_numeric_check(num))
{
if (gnc_reverse_balance(acct))
num = gnc_numeric_neg(num);
num = gnc_numeric_convert(num, GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) | GNC_HOW_RND_ROUND_HALF_UP);
gnc_budget_set_account_period_value(
priv->budget, acct, i, num);
num = gnc_numeric_convert(num, GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
gnc_budget_set_account_period_value(priv->budget, acct, i, num);
}
}
}
}
@ -886,7 +931,7 @@ gnc_plugin_page_budget_cmd_estimate_budget(GtkAction *action,
{
GncPluginPageBudgetPrivate *priv;
GtkTreeSelection *sel;
GtkWidget *dialog, *gde, *dtr, *hb;
GtkWidget *dialog, *gde, *dtr, *hb, *avg;
gint result;
GDate date;
const Recurrence *r;
@ -930,6 +975,9 @@ gnc_plugin_page_budget_cmd_estimate_budget(GtkAction *action,
gtk_spin_button_set_value(GTK_SPIN_BUTTON(dtr),
(gdouble)priv->sigFigs);
avg = GTK_WIDGET(gtk_builder_get_object(builder, "UseAverage"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(avg), priv->useAvg);
gtk_widget_show_all (dialog);
result = gtk_dialog_run(GTK_DIALOG(dialog));
switch (result)
@ -944,6 +992,8 @@ gnc_plugin_page_budget_cmd_estimate_budget(GtkAction *action,
priv->sigFigs =
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dtr));
priv->useAvg = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(avg));
gtk_tree_selection_selected_foreach(sel, estimate_budget_helper, page);
break;
default:
@ -953,6 +1003,133 @@ gnc_plugin_page_budget_cmd_estimate_budget(GtkAction *action,
g_object_unref(G_OBJECT(builder));
}
static void
allperiods_budget_helper(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
Account *acct;
guint num_periods, i;
gnc_numeric num;
GncPluginPageBudgetPrivate *priv;
GncPluginPageBudget *page = data;
g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
acct = gnc_budget_view_get_account_from_path(priv->budget_view, path);
num_periods = gnc_budget_get_num_periods(priv->budget);
num = priv->allValue;
for (i = 0; i < num_periods; i++)
{
switch (priv->action)
{
case ADD:
num = gnc_budget_get_account_period_value(priv->budget, acct, i);
num = gnc_numeric_add(num, priv->allValue, GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
gnc_budget_set_account_period_value(priv->budget, acct, i, num);
break;
case MULTIPLY:
num = gnc_budget_get_account_period_value(priv->budget, acct, i);
num = gnc_numeric_mul(num, priv->allValue, GNC_DENOM_AUTO,
GNC_HOW_DENOM_SIGFIGS(priv->sigFigs) |
GNC_HOW_RND_ROUND_HALF_UP);
gnc_budget_set_account_period_value(priv->budget, acct, i, num);
break;
case UNSET:
gnc_budget_unset_account_period_value(priv->budget, acct, i);
break;
default:
gnc_budget_set_account_period_value(priv->budget, acct, i,
priv->allValue);
break;
}
}
}
/*******************************/
/* All Periods Value Dialog */
/*******************************/
static void
gnc_plugin_page_budget_cmd_allperiods_budget(GtkAction *action,
GncPluginPageBudget *page)
{
GncPluginPageBudgetPrivate *priv;
GtkTreeSelection *sel;
GtkWidget *dialog, *gde, *val, *dtr, *add, *mult;
gint result;
GtkBuilder *builder;
const gchar *txt;
g_return_if_fail(GNC_IS_PLUGIN_PAGE_BUDGET(page));
priv = GNC_PLUGIN_PAGE_BUDGET_GET_PRIVATE(page);
sel = gnc_budget_view_get_selection(priv->budget_view);
if (gtk_tree_selection_count_selected_rows(sel) <= 0)
{
dialog = gtk_message_dialog_new(
GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
_("You must select at least one account to edit."));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return;
}
builder = gtk_builder_new();
gnc_builder_add_from_file(builder, "gnc-plugin-page-budget.glade",
"DigitsToRound_Adj");
gnc_builder_add_from_file(builder, "gnc-plugin-page-budget.glade",
"budget_allperiods_dialog");
dialog = GTK_WIDGET(
gtk_builder_get_object(builder, "budget_allperiods_dialog"));
gtk_window_set_transient_for(
GTK_WINDOW(dialog),
GTK_WINDOW(gnc_plugin_page_get_window(GNC_PLUGIN_PAGE(page))));
val = GTK_WIDGET(gtk_builder_get_object(builder, "Value"));
gtk_entry_set_text(GTK_ENTRY(val), "");
dtr = GTK_WIDGET(gtk_builder_get_object(builder, "DigitsToRound1"));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(dtr), (gdouble)priv->sigFigs);
add = GTK_WIDGET(gtk_builder_get_object(builder, "RB_Add"));
mult = GTK_WIDGET(gtk_builder_get_object(builder, "RB_Multiply"));
gtk_widget_show_all(dialog);
result = gtk_dialog_run(GTK_DIALOG(dialog));
switch (result)
{
case GTK_RESPONSE_OK:
priv->sigFigs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(dtr));
priv->action = REPLACE;
txt = gtk_entry_get_text(GTK_ENTRY(val));
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(add)))
priv->action = ADD;
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mult)))
priv->action = MULTIPLY;
if (priv->action == REPLACE &&
!gtk_entry_get_text_length(GTK_ENTRY(val)))
priv->action = UNSET;
if (xaccParseAmount(txt, TRUE, &priv->allValue, NULL) ||
priv->action == UNSET)
gtk_tree_selection_selected_foreach(sel, allperiods_budget_helper,
page);
break;
default:
break;
}
gtk_widget_destroy(dialog);
g_object_unref(G_OBJECT(builder));
}
static void
gnc_plugin_page_budget_cmd_view_filter_by (GtkAction *action,

@ -9,6 +9,244 @@
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkDialog" id="budget_allperiods_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Edit budget for all periods</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancelbutton3">
<property name="label" translatable="yes">_Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="okbutton3">
<property name="label" translatable="yes">_OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">
Use a fixed value or apply transformation for all periods.
</property>
<property name="wrap">True</property>
<property name="width_chars">40</property>
<property name="max_width_chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Value:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="Value">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Action</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="RB_Replace">
<property name="label" translatable="yes">Replace</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">
Replace the budget for all periods with new 'value'. Use empty value to unset budget for the accounts.
</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="RB_Add">
<property name="label" translatable="yes">Add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">
Add 'value' to current budget for each period
</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">RB_Replace</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="RB_Multiply">
<property name="label" translatable="yes">Multiply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">
Multiply current budget for each period by 'value'
</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">RB_Replace</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="DigitsToRound1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The number of leading digits to keep when rounding</property>
<property name="hexpand">True</property>
<property name="text" translatable="yes">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="adjustment">DigitsToRound_Adj</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
<property name="value">1</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Significant Digits:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">cancelbutton3</action-widget>
<action-widget response="-5">okbutton3</action-widget>
</action-widgets>
</object>
<object class="GtkDialog" id="budget_estimate_dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
@ -151,6 +389,22 @@
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="UseAverage">
<property name="label" translatable="yes">Use Average</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">
Use the average value over all actual periods for all projected periods
</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>

@ -3,6 +3,7 @@
<menu name="Edit" action="EditAction">
<placeholder name="EditSelectedPlaceholder">
<menuitem name="Estimate" action="EstimateBudgetAction"/>
<menuitem name="AllPeriods" action="AllPeriodsBudgetAction"/>
<menuitem name="Delete" action="DeleteBudgetAction"/>
</placeholder>
<menuitem name="Options" action="OptionsBudgetAction"/>
@ -22,6 +23,7 @@
<toolitem name="Options" action="OptionsBudgetAction"/>
<separator name="ToolbarSep4"/>
<toolitem name="Estimate" action="EstimateBudgetAction"/>
<toolitem name="AllPeriods" action="AllPeriodsBudgetAction"/>
<toolitem name="Delete" action="DeleteBudgetAction"/>
</placeholder>
</toolbar>

@ -163,6 +163,8 @@ qof_book_init (QofBook *book)
static const std::string str_KVP_OPTION_PATH(KVP_OPTION_PATH);
static const std::string str_OPTION_SECTION_ACCOUNTS(OPTION_SECTION_ACCOUNTS);
static const std::string str_OPTION_SECTION_BUDGETING(OPTION_SECTION_BUDGETING);
static const std::string str_OPTION_NAME_DEFAULT_BUDGET(OPTION_NAME_DEFAULT_BUDGET);
static const std::string str_OPTION_NAME_TRADING_ACCOUNTS(OPTION_NAME_TRADING_ACCOUNTS);
static const std::string str_OPTION_NAME_AUTO_READONLY_DAYS(OPTION_NAME_AUTO_READONLY_DAYS);
static const std::string str_OPTION_NAME_NUM_FIELD_SOURCE(OPTION_NAME_NUM_FIELD_SOURCE);
@ -206,7 +208,7 @@ qof_book_get_property (GObject* object,
break;
case PROP_OPT_DEFAULT_BUDGET:
qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
str_OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_BUDGET});
str_OPTION_SECTION_BUDGETING, str_OPTION_NAME_DEFAULT_BUDGET});
break;
case PROP_OPT_FY_END:
qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});
@ -261,7 +263,7 @@ qof_book_set_property (GObject *object,
break;
case PROP_OPT_DEFAULT_BUDGET:
qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
str_OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_BUDGET});
str_OPTION_SECTION_BUDGETING, OPTION_NAME_DEFAULT_BUDGET});
break;
case PROP_OPT_FY_END:
qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});

Loading…
Cancel
Save