X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Frep-budget.c;fp=src%2Frep_budget.c;h=60984e12ed28383124a02baf65b346f54ae24b81;hp=47048deefe45d42cafcc158a8d5284cdf06e74d6;hb=236cb5e47660876f46488ea8f76ecd5bebfa1fac;hpb=8892e90b335f94c296462a91534334b674226cd9 diff --git a/src/rep_budget.c b/src/rep-budget.c similarity index 91% rename from src/rep_budget.c rename to src/rep-budget.c index 47048de..60984e1 100644 --- a/src/rep_budget.c +++ b/src/rep-budget.c @@ -1,5 +1,5 @@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2018 Maxime DOYEN + * Copyright (C) 1995-2019 Maxime DOYEN * * This file is part of HomeBank. * @@ -20,13 +20,13 @@ #include "homebank.h" -#include "rep_budget.h" +#include "rep-budget.h" -#include "list_operation.h" -#include "gtk-chart-stack.h" +#include "list-operation.h" +#include "gtk-chart-progress.h" #include "gtk-dateentry.h" -#include "dsp_mainwindow.h" +#include "dsp-mainwindow.h" #include "ui-transaction.h" @@ -67,14 +67,9 @@ static void repbudget_update_daterange(GtkWidget *widget, gpointer user_data); static GString *ui_list_repbudget_to_string(GtkTreeView *treeview, gboolean clipboard); -gchar *CYA_BUDGSELECT[] = { N_("Category"), N_("Subcategory"), NULL }; -gchar *CYA_KIND[] = { N_("Exp. & Inc."), N_("Expense"), N_("Income"), NULL }; - -gchar *CYA_BUDGETSELECT[] = { N_("Spent & Budget"), N_("Spent"), N_("Budget"), N_("Result"), NULL }; - - -//extern gchar *CYA_FLT_SELECT[]; +extern gchar *CYA_CATSUBCAT[]; +extern gchar *CYA_KIND[]; static GtkRadioActionEntry radio_entries[] = { @@ -85,7 +80,7 @@ static guint n_radio_entries = G_N_ELEMENTS (radio_entries); static GtkActionEntry entries[] = { - { "Refresh" , ICONNAME_REFRESH, N_("Refresh"), NULL, N_("Refresh results"), G_CALLBACK (repbudget_action_refresh) }, + { "Refresh" , ICONNAME_HB_REFRESH, N_("Refresh"), NULL, N_("Refresh results"), G_CALLBACK (repbudget_action_refresh) }, // { "Export" , ICONNAME_HB_FILE_EXPORT , N_("Export") , NULL, N_("Export as CSV"), G_CALLBACK (repbudget_action_export) }, }; @@ -432,7 +427,7 @@ gint tmpfor; //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); tmpfor = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_for)); - name = g_strdup_printf("hb-repbudget_%s.csv", CYA_BUDGSELECT[tmpfor]); + name = g_strdup_printf("hb-repbudget_%s.csv", CYA_CATSUBCAT[tmpfor]); if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, name) == TRUE ) { @@ -486,7 +481,7 @@ gint tmpfor; //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); tmpfor = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_for)); - name = g_strdup_printf("hb-repstat-detail_%s.csv", CYA_BUDGSELECT[tmpfor]); + name = g_strdup_printf("hb-repstat-detail_%s.csv", CYA_CATSUBCAT[tmpfor]); if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, name) == TRUE ) { @@ -554,13 +549,13 @@ GtkTreeIter iter; //filter here if( ope->flags & OF_SPLIT ) { - guint nbsplit = da_splits_count(ope->splits); + guint nbsplit = da_splits_length(ope->splits); Split *split; guint i; for(i=0;isplits[i]; + split = da_splits_get(ope->splits, i); switch(tmpfor) { case BUDG_CATEGORY: @@ -625,6 +620,27 @@ next1: } +static void repbudget_compute_cat_spent(guint32 key, gdouble amount, gdouble *tmp_spent, gdouble *tmp_budget) +{ +Category *cat; + + cat = da_cat_get(key); + if(cat) + { + DB( g_print(" -> affecting %.2f to cat %d sub=%d, bud=%.2f\n", amount, cat->key, (cat->flags & GF_SUB), tmp_budget[cat->key]) ); + if( (cat->flags & GF_FORCED) || (cat->flags & GF_BUDGET) ) + tmp_spent[cat->key] += amount; + //#1814213 only count subcat with budget + //if( (cat->flags & GF_SUB) ) + if( (cat->flags & GF_FORCED) || ((cat->flags & GF_SUB) && (cat->flags & GF_BUDGET)) ) + { + DB( g_print(" -> affecting %.2f to parent %d, bud=%.2f\n", amount, cat->parent, tmp_budget[cat->parent]) ); + tmp_spent[cat->parent] += amount; + } + } +} + + static void repbudget_compute(GtkWidget *widget, gpointer user_data) { struct repbudget_data *data; @@ -637,6 +653,7 @@ GtkTreeIter iter; GList *list; guint n_result, id; gdouble *tmp_spent, *tmp_budget; +gboolean *tmp_hassub; gint nbmonth = 1; gchar *title; @@ -655,7 +672,6 @@ gchar *title; g_queue_free (data->txn_queue); data->txn_queue = hbfile_transaction_get_partial_budget(data->filter->mindate, data->filter->maxdate); - DB( g_print(" for=%d, kind=%d\n", tmpfor, tmpkind) ); nbmonth = countmonth(mindate, maxdate); @@ -667,8 +683,9 @@ gchar *title; /* allocate some memory */ tmp_spent = g_malloc0((n_result+1) * sizeof(gdouble)); tmp_budget = g_malloc0((n_result+1) * sizeof(gdouble)); + tmp_hassub = g_malloc0((n_result+1) * sizeof(gboolean)); - if(tmp_spent && tmp_budget) + if(tmp_spent && tmp_budget && tmp_hassub) { guint i = 0; /* compute the results */ @@ -682,8 +699,6 @@ gchar *title; for(i=1; i<=n_result; i++) { Category *entry; - //gchar buffer[128]; - gint pos; entry = da_cat_get(i); if( entry == NULL) @@ -693,34 +708,24 @@ gchar *title; entry->key, entry->name, (entry->flags & GF_SUB), (entry->flags & GF_BUDGET), (entry->flags & GF_CUSTOM)) ); //debug - #if MYDEBUG == 1 + /*#if MYDEBUG == 1 gint k; g_print(" budget vector: "); for(k=0;k<13;k++) g_print( " %d:[%.2f]", k, entry->budget[k]); g_print("\n"); - #endif - - pos = 0; - switch(tmpfor) - { - case BUDG_CATEGORY: - { - Category *catentry = da_cat_get(i); - if(catentry) - pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key; - } - break; - case BUDG_SUBCATEGORY: - pos = i; - break; - } + #endif*/ // same value each month ? if(!(entry->flags & GF_CUSTOM)) { DB( g_print(" - monthly %.2f\n", entry->budget[0]) ); - tmp_budget[pos] += entry->budget[0]*nbmonth; + tmp_budget[entry->key] += entry->budget[0]*nbmonth; + if( entry->flags & GF_SUB ) + { + tmp_budget[entry->parent] += entry->budget[0]*nbmonth; + tmp_hassub[entry->parent] = TRUE; + } } //otherwise sum each month from mindate month else @@ -731,88 +736,43 @@ gchar *title; DB( g_print(" - custom each month for %d months\n", nbmonth) ); for(j=0;jbudget[month]) ); - tmp_budget[pos] += entry->budget[month]; - month++; - if(month > 12) { - month = 1; + tmp_budget[entry->key] += entry->budget[month]; + if( entry->flags & GF_SUB ) + { + tmp_budget[entry->parent] += entry->budget[month]; + tmp_hassub[entry->parent] = TRUE; } + month++; + if(month > 12) { month = 1; } } } - - //debug - #if MYDEBUG == 1 - g_print(" final budget: %d:'%s' : budg[%d]=%.2f\n", entry->key, entry->name, pos, tmp_budget[pos] ); - #endif } // compute spent for each transaction */ DB( g_print("\n+ compute spent from transactions\n") ); - list = g_queue_peek_head_link(data->txn_queue); while (list != NULL) { Transaction *ope = list->data; - gint pos = 0; - gdouble trn_amount; - //DB( g_print("%d, get ope: %s :: acc=%d, cat=%d, mnt=%.2f\n", i, ope->memo, ope->account, ope->category, ope->amount) ); + DB( g_print("%d, get ope: %s :: acc=%d, cat=%d, mnt=%.2f\n", i, ope->memo, ope->kacc, ope->kcat, ope->amount) ); if( ope->flags & OF_SPLIT ) { - guint nbsplit = da_splits_count(ope->splits); + guint nbsplit = da_splits_length(ope->splits); Split *split; for(i=0;isplits[i]; - switch(tmpfor) - { - case BUDG_CATEGORY: - { - Category *catentry = da_cat_get(split->kcat); - if(catentry) - pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key; - } - break; - case BUDG_SUBCATEGORY: - pos = split->kcat; - break; - } - - //trn_amount = split->amount; - trn_amount = hb_amount_base(split->amount, ope->kcur); - - DB( g_print(" -> affecting split %.2f to cat pos %d\n", trn_amount, pos) ); - - tmp_spent[pos] += trn_amount; - + split = da_splits_get(ope->splits, i); + repbudget_compute_cat_spent(split->kcat, hb_amount_base(split->amount, ope->kcur), tmp_spent, tmp_budget); } } else { - switch(tmpfor) - { - case BUDG_CATEGORY: - { - Category *catentry = da_cat_get(ope->kcat); - if(catentry) - pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key; - } - break; - case BUDG_SUBCATEGORY: - pos = ope->kcat; - break; - } - - //trn_amount = ope->amount; - trn_amount = hb_amount_base(ope->amount, ope->kcur); - - DB( g_print(" -> affecting %.2f to cat pos %d\n", trn_amount, pos) ); - - tmp_spent[pos] += trn_amount; - + repbudget_compute_cat_spent(ope->kcat, hb_amount_base(ope->amount, ope->kcur), tmp_spent, tmp_budget); } list = g_list_next(list); @@ -827,36 +787,22 @@ gchar *title; g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */ gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_report), NULL); /* Detach model from view */ - DB( g_print("\n+ insert into treeview\n") ); - - /* insert into the treeview */ for(i=1, id=0; i<=n_result; i++) { - gchar *name, *fullcatname; + gchar *name; gboolean outofbudget; Category *entry; - fullcatname = NULL; - entry = da_cat_get(i); if( entry == NULL) continue; - if(entry->flags & GF_SUB) - { - Category *parent = da_cat_get( entry->parent); - - fullcatname = g_strdup_printf("%s:%s", parent->name, entry->name); - name = fullcatname; - } - else - name = entry->name; - - if(name == NULL) name = "(None)"; + name = entry->key == 0 ? "(None)" : entry->fullname; //#1553862 //if( (tmpfor == BUDG_CATEGORY && !(entry->flags & GF_SUB)) || (tmpfor == BUDG_SUBCATEGORY) ) - if( (tmpfor == BUDG_CATEGORY && !(entry->flags & GF_SUB)) || (tmpfor == BUDG_SUBCATEGORY && (entry->flags & GF_SUB)) ) + if( (tmpfor == BUDG_CATEGORY && !(entry->flags & GF_SUB)) || + (tmpfor == BUDG_SUBCATEGORY && ((entry->flags & GF_SUB) || !tmp_hassub[i]) ) ) { guint pos; @@ -876,7 +822,6 @@ gchar *title; } // display expense or income (filter on amount and not category hypothetical flag - //if( tmpkind != (entry->flags & GF_INCOME)) continue; if( tmpkind == 1 && tmp_budget[pos] > 0) continue; @@ -901,26 +846,29 @@ gchar *title; status = ""; outofbudget = FALSE; - if(rawrate > 1.0) - { - status = _(" over"); - outofbudget = TRUE; - } - else + if( result ) { - if(tmp_budget[pos] < 0.0) - status = _(" left"); - else if(tmp_budget[pos] > 0.0) + if(rawrate > 1.0) { - status = _(" under"); + status = _(" over"); outofbudget = TRUE; } + else + { + if(tmp_budget[pos] < 0.0) + status = _(" left"); + else if(tmp_budget[pos] > 0.0) + { + status = _(" under"); + outofbudget = TRUE; + } + } } if(tmponlyout == TRUE && outofbudget == FALSE) goto nextins; - DB( g_print(" => insert %.2f | %.2f = %.2f (%.2f) '%s'\n\n", tmp_spent[pos], tmp_budget[pos], result, rawrate, status ) ); + DB( g_print(" => insert '%s' s:%.2f b:%.2f r:%.2f (%%%.2f) '%s' '%d'\n\n", name, tmp_spent[pos], tmp_budget[pos], result, rawrate, status, outofbudget ) ); gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, @@ -938,14 +886,11 @@ gchar *title; data->total_budget += tmp_budget[pos]; } } - - g_free(fullcatname); - } /* update column 0 title */ GtkTreeViewColumn *column = gtk_tree_view_get_column( GTK_TREE_VIEW(data->LV_report), 0); - gtk_tree_view_column_set_title(column, _(CYA_BUDGSELECT[tmpfor])); + gtk_tree_view_column_set_title(column, _(CYA_CATSUBCAT[tmpfor])); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_report)); @@ -957,13 +902,13 @@ gchar *title; repbudget_update_total(widget, NULL); /* update stack chart */ - title = g_strdup_printf(_("Budget for %s"), _(CYA_BUDGSELECT[tmpfor]) ); + title = g_strdup_printf(_("Budget for %s"), _(CYA_CATSUBCAT[tmpfor]) ); - ui_chart_stack_set_currency(GTK_CHARTSTACK(data->RE_stack), GLOBALS->kcur); + ui_chart_progress_set_currency(GTK_CHARTPROGRESS(data->RE_stack), GLOBALS->kcur); /* set chart color scheme */ - ui_chart_stack_set_color_scheme(GTK_CHARTSTACK(data->RE_stack), PREFS->report_color_scheme); - ui_chart_stack_set_dualdatas(GTK_CHARTSTACK(data->RE_stack), model, _("Budget"), _("Result"), title, NULL); + ui_chart_progress_set_color_scheme(GTK_CHARTPROGRESS(data->RE_stack), PREFS->report_color_scheme); + ui_chart_progress_set_dualdatas(GTK_CHARTPROGRESS(data->RE_stack), model, _("Budget"), _("Result"), title, NULL); g_free(title); } @@ -971,6 +916,7 @@ gchar *title; //DB( g_print(" inserting %i, %f %f\n", i, total_expense, total_income) ); /* free our memory */ + g_free(tmp_hassub); g_free(tmp_spent); g_free(tmp_budget); @@ -1042,7 +988,7 @@ gboolean minor; gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_report)); minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor)); - ui_chart_stack_show_minor(GTK_CHARTSTACK(data->RE_stack), minor); + ui_chart_progress_show_minor(GTK_CHARTPROGRESS(data->RE_stack), minor); } @@ -1052,8 +998,8 @@ static void repbudget_setup(struct repbudget_data *data) data->txn_queue = g_queue_new (); - data->filter = da_filter_malloc(); - filter_default_all_set(data->filter); + data->filter = da_flt_malloc(); + filter_reset(data->filter); data->detail = PREFS->budg_showdetail; data->legend = 1; @@ -1108,7 +1054,7 @@ struct WinGeometry *wg; g_queue_free (data->txn_queue); - da_filter_free(data->filter); + da_flt_free(data->filter); g_free(data); @@ -1188,15 +1134,15 @@ GError *error = NULL; gtk_grid_attach (GTK_GRID (table), label, 0, row, 3, 1); row++; - label = make_label_widget(_("_For:")); + label = make_label_widget(_("_View by:")); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); - widget = make_cycle(label, CYA_BUDGSELECT); + widget = make_cycle(label, CYA_CATSUBCAT); data->CY_for = widget; gtk_grid_attach (GTK_GRID (table), data->CY_for, 2, row, 1, 1); row++; - label = make_label_widget(_("_Kind:")); + label = make_label_widget(_("_Type:")); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); widget = make_cycle(label, CYA_KIND); data->CY_kind = widget; @@ -1394,7 +1340,7 @@ GError *error = NULL; //page: 2d bar //widget = gtk_chart_new(CHART_TYPE_COL); - widget = ui_chart_stack_new(); + widget = ui_chart_progress_new(); data->RE_stack = widget; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL); @@ -1569,12 +1515,8 @@ gchar *entry1, *entry2; gtk_tree_model_get(model, b, LST_BUDGET_NAME, &entry2, -1); retval = hb_string_utf8_compare(entry1, entry2); - //retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME); - //if(!retval) - //{ - // retval = hb_string_utf8_compare(entry1->name, entry2->name); - //} - //leak + + g_free(entry2); g_free(entry1);