1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
4 * This file is part of HomeBank.
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "dsp-mainwindow.h"
24 #include "hub-spending.h"
25 #include "gtk-chart.h"
28 /****************************************************************************/
30 /****************************************************************************/
39 /* our global datas */
40 extern struct HomeBank
*GLOBALS
;
41 extern struct Preferences
*PREFS
;
44 extern gchar
*CYA_CATSUBCAT
[];
47 static GtkWidget
*create_list_topspending(void)
52 /* create list store */
53 store
= gtk_list_store_new(
57 G_TYPE_STRING
, //category
58 G_TYPE_DOUBLE
, //amount
63 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
64 g_object_unref(store
);
72 static gint
tmptop_compare_func(struct tmptop
*tt1
, struct tmptop
*tt2
)
74 return tt1
->value
> tt2
->value
? 1 : -1;
78 void ui_hub_spending_update(GtkWidget
*widget
, gpointer user_data
)
80 struct hbfile_data
*data
;
83 gchar strbuffer
[G_ASCII_DTOSTR_BUF_SIZE
];
85 DB( g_print("\n[hub-spendings] update\n") );
87 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
89 hb_strfmon(strbuffer
, G_ASCII_DTOSTR_BUF_SIZE
-1, data
->toptotal
, GLOBALS
->kcur
, GLOBALS
->minor
);
90 //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor);
91 title
= g_strdup_printf("%s %s", _("Top spending"), strbuffer
);
93 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_top
));
95 gtk_chart_set_color_scheme(GTK_CHART(data
->RE_pie
), PREFS
->report_color_scheme
);
96 gtk_chart_set_currency(GTK_CHART(data
->RE_pie
), GLOBALS
->kcur
);
97 gtk_chart_set_datas(GTK_CHART(data
->RE_pie
), model
, LST_TOPSPEND_AMOUNT
, title
, NULL
);
102 gchar
*fu
= _("Top %d spending"); title
= fu
;
106 void ui_hub_spending_populate(GtkWidget
*widget
, gpointer user_data
)
108 struct hbfile_data
*data
;
113 guint n_result
, i
, n_items
;
115 gdouble total
, other
;
118 DB( g_print("\n[hub-spendings] populate\n") );
120 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
122 type
= hbtk_radio_button_get_active(GTK_CONTAINER(data
->RA_type
));
123 range
= hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
));
125 DB( g_print(" - type=%d, range=%d\n", type
, range
) );
126 DB( g_print(" - pref range=%d\n", PREFS
->date_range_wal
) );
128 if(range
== FLT_RANGE_OTHER
)
131 filter_preset_daterange_set(data
->filter
, range
, 0);
134 n_result
= da_cat_get_max_key() + 1;
137 DB( g_print(" - max key is %d\n", n_result
) );
139 /* allocate some memory */
140 garray
= g_array_sized_new(FALSE
, FALSE
, sizeof(struct tmptop
), n_result
);
144 struct tmptop zero
= { .key
=0, .value
=0.0 };
147 //DB( g_print(" - array length=%d\n", garray->len) );
149 for(i
=0 ; i
<n_result
; i
++)
151 g_array_append_vals(garray
, &zero
, 1);
152 //g_array_insert_vals(garray, i, &zero, 1);
154 //struct tmptop *tt = &g_array_index (garray, struct tmptop, i);
155 //DB( g_print("%4d, %4d %f\n", i, tt->key, tt->value) );
158 //DB( g_print("\n - end array length=%d\n", garray->len) );
160 //todo: not ideal, has ot force to get_acc for each txn below
161 txn_queue
= hbfile_transaction_get_partial(data
->filter
->mindate
, data
->filter
->maxdate
);
163 /* compute the results */
164 list
= g_queue_peek_head_link(txn_queue
);
167 Transaction
*ope
= list
->data
;
169 //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->memo, ope->kcat, filter_txn_match(data->filter, ope)) );
171 if( !(ope
->paymode
== PAYMODE_INTXFER
) )
176 //todo: optimize here
177 trn_amount
= ope
->amount
;
178 acc
= da_acc_get(ope
->kacc
);
180 trn_amount
= hb_amount_base(ope
->amount
, acc
->kcur
);
182 if( ope
->flags
& OF_SPLIT
)
184 guint nbsplit
= da_splits_length(ope
->splits
);
188 for(i
=0;i
<nbsplit
;i
++)
190 split
= da_splits_get(ope
->splits
, i
);
191 pos
= category_report_id(split
->kcat
, type
);
192 if( pos
<= garray
->len
)
194 trn_amount
= hb_amount_base(split
->amount
, acc
->kcur
);
195 //trn_amount = split->amount;
196 //#1297054 if( trn_amount < 0 ) {
197 item
= &g_array_index (garray
, struct tmptop
, pos
);
199 item
->value
+= trn_amount
;
200 //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) );
209 pos
= category_report_id(ope
->kcat
, type
);
210 if( pos
<= garray
->len
)
212 //#1297054 if( trn_amount < 0 ) {
213 item
= &g_array_index (garray
, struct tmptop
, pos
);
215 item
->value
+= trn_amount
;
216 //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) );
223 list
= g_list_next(list
);
226 g_queue_free (txn_queue
);
228 // we need to sort this and limit before
229 g_array_sort(garray
, (GCompareFunc
)tmptop_compare_func
);
231 n_items
= MIN(garray
->len
,MAX_TOPSPENDING
);
233 for(i
=0 ; i
<garray
->len
; i
++)
237 item
= &g_array_index (garray
, struct tmptop
, i
);
240 total
+= item
->value
;
243 other
+= item
->value
;
245 DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i
, item
->key
, item
->value
, total
) );
250 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_top
));
251 gtk_list_store_clear (GTK_LIST_STORE(model
));
252 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
253 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_top
), NULL
); /* Detach model from view */
255 /* insert into the treeview */
256 for(i
=0 ; i
<MIN(garray
->len
,MAX_TOPSPENDING
) ; i
++)
263 item
= &g_array_index (garray
, struct tmptop
, i
);
265 if(!item
->value
) continue;
266 //#1767659 top spending should restrict to... spending
269 value
= hb_amount_round(item
->value
, 2);
270 entry
= da_cat_get(item
->key
);
271 if(entry
== NULL
) continue;
273 name
= da_cat_get_name (entry
);
276 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
277 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
280 LST_TOPSPEND_NAME
, name
,
281 LST_TOPSPEND_AMOUNT
, value
,
282 //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5),
290 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
291 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
292 LST_TOPSPEND_ID
, n_items
,
294 LST_TOPSPEND_NAME
, _("Other"),
295 LST_TOPSPEND_AMOUNT
, other
,
296 //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5),
300 /* Re-attach model to view */
301 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_top
), model
);
302 g_object_unref(model
);
305 // update chart and widgets
309 data
->toptotal
= total
;
310 ui_hub_spending_update(widget
, data
);
312 daterange
= filter_daterange_text_get(data
->filter
);
313 gtk_widget_set_tooltip_markup(GTK_WIDGET(data
->CY_range
), daterange
);
318 /* free our memory */
319 g_array_free (garray
, TRUE
);
325 GtkWidget
*ui_hub_spending_create(struct hbfile_data
*data
)
327 GtkWidget
*hub
, *hbox
, *tbar
;
328 GtkWidget
*label
, *widget
;
329 GtkToolItem
*toolitem
;
331 DB( g_print("\n[hub-spendings] create\n") );
333 widget
= (GtkWidget
*)create_list_topspending();
334 data
->LV_top
= widget
;
336 hub
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
337 gtk_container_set_border_width(GTK_CONTAINER(hub
), SPACING_SMALL
);
340 /* chart + listview */
341 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
342 gtk_box_pack_start (GTK_BOX (hub
), hbox
, TRUE
, TRUE
, 0);
344 widget
= gtk_chart_new(CHART_TYPE_PIE
);
345 data
->RE_pie
= widget
;
346 gtk_chart_set_minor_prefs(GTK_CHART(widget
), PREFS
->euro_value
, PREFS
->minor_cur
.symbol
);
347 gtk_chart_show_legend(GTK_CHART(data
->RE_pie
), TRUE
, TRUE
);
348 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
351 tbar
= gtk_toolbar_new();
352 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar
), GTK_ICON_SIZE_MENU
);
353 gtk_toolbar_set_style(GTK_TOOLBAR(tbar
), GTK_TOOLBAR_ICONS
);
354 gtk_style_context_add_class (gtk_widget_get_style_context (tbar
), GTK_STYLE_CLASS_INLINE_TOOLBAR
);
355 gtk_box_pack_start (GTK_BOX (hub
), tbar
, FALSE
, FALSE
, 0);
357 label
= make_label_group(_("Where your money goes"));
358 toolitem
= gtk_tool_item_new();
359 gtk_container_add (GTK_CONTAINER(toolitem
), label
);
360 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
362 toolitem
= gtk_separator_tool_item_new ();
363 gtk_tool_item_set_expand (toolitem
, TRUE
);
364 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem
), FALSE
);
365 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
367 /* total + date range */
368 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, SPACING_SMALL
);
369 toolitem
= gtk_tool_item_new();
370 gtk_container_add (GTK_CONTAINER(toolitem
), hbox
);
371 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
373 data
->CY_range
= make_daterange(label
, DATE_RANGE_CUSTOM_HIDE
);
374 gtk_box_pack_end (GTK_BOX (hbox
), data
->CY_range
, FALSE
, FALSE
, 0);
376 widget
= hbtk_radio_button_new(CYA_CATSUBCAT
, TRUE
);
377 data
->RA_type
= widget
;
378 gtk_box_pack_end (GTK_BOX (hbox
), widget
, FALSE
, FALSE
, 0);
380 hbtk_radio_button_connect (GTK_CONTAINER(data
->RA_type
), "toggled", G_CALLBACK (ui_hub_spending_populate
), &data
);
382 g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (ui_hub_spending_populate
), NULL
);