1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2017 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/>.
23 #include "rep_stats.h"
25 #include "list_operation.h"
26 #include "gtk-chart.h"
27 #include "gtk-dateentry.h"
29 #include "dsp_mainwindow.h"
30 #include "ui-account.h"
32 #include "ui-category.h"
33 #include "ui-filter.h"
34 #include "ui-transaction.h"
36 /****************************************************************************/
38 /****************************************************************************/
47 /* our global datas */
48 extern struct HomeBank
*GLOBALS
;
49 extern struct Preferences
*PREFS
;
53 static void ui_repdist_action_viewlist(GtkAction
*action
, gpointer user_data
);
54 static void ui_repdist_action_viewbar(GtkAction
*action
, gpointer user_data
);
55 static void ui_repdist_action_viewpie(GtkAction
*action
, gpointer user_data
);
56 static void ui_repdist_action_detail(GtkAction
*action
, gpointer user_data
);
57 static void ui_repdist_action_legend(GtkAction
*action
, gpointer user_data
);
58 static void ui_repdist_action_rate(GtkAction
*action
, gpointer user_data
);
59 static void ui_repdist_action_filter(GtkAction
*action
, gpointer user_data
);
60 static void ui_repdist_action_refresh(GtkAction
*action
, gpointer user_data
);
61 static void ui_repdist_action_export(GtkAction
*action
, gpointer user_data
);
64 static GtkActionEntry entries
[] = {
65 { "List" , ICONNAME_HB_VIEW_LIST
, N_("List") , NULL
, N_("View results as list"), G_CALLBACK (ui_repdist_action_viewlist
) },
66 { "Column" , ICONNAME_HB_VIEW_COLUMN
, N_("Column") , NULL
, N_("View results as column"), G_CALLBACK (ui_repdist_action_viewbar
) },
67 { "Donut" , ICONNAME_HB_VIEW_DONUT
, N_("Donut") , NULL
, N_("View results as donut"), G_CALLBACK (ui_repdist_action_viewpie
) },
69 { "Filter" , ICONNAME_HB_FILTER
, N_("Filter") , NULL
, N_("Edit filter"), G_CALLBACK (ui_repdist_action_filter
) },
70 { "Refresh" , ICONNAME_REFRESH
, N_("Refresh"), NULL
, N_("Refresh results"), G_CALLBACK (ui_repdist_action_refresh
) },
72 { "Export" , ICONNAME_HB_FILE_EXPORT
, N_("Export") , NULL
, N_("Export as CSV"), G_CALLBACK (ui_repdist_action_export
) },
74 static guint n_entries
= G_N_ELEMENTS (entries
);
77 static GtkToggleActionEntry toggle_entries
[] = {
78 { "Detail", ICONNAME_HB_OPE_SHOW
, /* name, icon-name */
79 N_("Detail"), NULL
, /* label, accelerator */
80 N_("Toggle detail"), /* tooltip */
81 G_CALLBACK (ui_repdist_action_detail
),
82 FALSE
}, /* is_active */
84 { "Legend", ICONNAME_HB_SHOW_LEGEND
, /* name, icon-name */
85 N_("Legend"), NULL
, /* label, accelerator */
86 N_("Toggle legend"), /* tooltip */
87 G_CALLBACK (ui_repdist_action_legend
),
88 TRUE
}, /* is_active */
90 { "Rate", ICONNAME_HB_SHOW_RATE
, /* name, icon-name */
91 N_("Rate"), NULL
, /* label, accelerator */
92 N_("Toggle rate"), /* tooltip */
93 G_CALLBACK (ui_repdist_action_rate
),
94 FALSE
}, /* is_active */
97 static guint n_toggle_entries
= G_N_ELEMENTS (toggle_entries
);
101 static const gchar
*ui_info
=
103 " <toolbar name='ToolBar'>"
104 " <toolitem action='List'/>"
105 " <toolitem action='Column'/>"
106 " <toolitem action='Donut'/>"
108 " <toolitem action='Detail'/>"
109 " <toolitem action='Legend'/>"
110 " <toolitem action='Rate'/>"
112 " <toolitem action='Filter'/>"
113 " <toolitem action='Refresh'/>"
115 " <toolitem action='Export'/>"
121 static void ui_repdist_date_change(GtkWidget
*widget
, gpointer user_data
);
122 static void ui_repdist_range_change(GtkWidget
*widget
, gpointer user_data
);
123 static void ui_repdist_detail(GtkWidget
*widget
, gpointer user_data
);
124 static void ui_repdist_update(GtkWidget
*widget
, gpointer user_data
);
125 static void ui_repdist_update_total(GtkWidget
*widget
, gpointer user_data
);
126 static void ui_repdist_export_csv(GtkWidget
*widget
, gpointer user_data
);
127 static void ui_repdist_compute(GtkWidget
*widget
, gpointer user_data
);
128 static void ui_repdist_sensitive(GtkWidget
*widget
, gpointer user_data
);
129 static void ui_repdist_toggle_detail(GtkWidget
*widget
, gpointer user_data
);
130 static void ui_repdist_toggle_legend(GtkWidget
*widget
, gpointer user_data
);
131 static void ui_repdist_toggle_minor(GtkWidget
*widget
, gpointer user_data
);
132 static void ui_repdist_toggle_rate(GtkWidget
*widget
, gpointer user_data
);
133 static GtkWidget
*ui_list_repdist_create(void);
134 static void ui_repdist_update_daterange(GtkWidget
*widget
, gpointer user_data
);
136 static gint
ui_list_repdist_compare_func (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
);
140 gchar
*CYA_STATSELECT
[] = {
150 gchar
*CYA_KIND2
[] = {
159 //extern gchar *CYA_FLT_SELECT[];
161 gchar
*CYA_MONTHS
[] =
178 /* action functions -------------------- */
180 static void ui_repdist_action_viewlist(GtkAction
*action
, gpointer user_data
)
182 struct ui_repdist_data
*data
= user_data
;
184 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 0);
185 ui_repdist_sensitive(data
->window
, NULL
);
188 static void ui_repdist_action_viewbar(GtkAction
*action
, gpointer user_data
)
190 struct ui_repdist_data
*data
= user_data
;
192 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
193 gtk_chart_set_type (GTK_CHART(data
->RE_chart
), CHART_TYPE_COL
);
194 ui_repdist_sensitive(data
->window
, NULL
);
197 static void ui_repdist_action_viewpie(GtkAction
*action
, gpointer user_data
)
199 struct ui_repdist_data
*data
= user_data
;
202 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
204 gtk_chart_set_type (GTK_CHART(data
->RE_chart
), CHART_TYPE_PIE
);
205 ui_repdist_sensitive(data
->window
, NULL
);
207 tmpview
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
209 // ensure not exp & inc for piechart
212 //g_signal_handler_block(data->CY_view, data->handler_id[HID_REPDIST_VIEW]);
213 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
214 //g_signal_handler_unblock(data->CY_view, data->handler_id[HID_REPDIST_VIEW]);
219 static void ui_repdist_action_detail(GtkAction
*action
, gpointer user_data
)
221 struct ui_repdist_data
*data
= user_data
;
223 ui_repdist_toggle_detail(data
->window
, NULL
);
226 static void ui_repdist_action_legend(GtkAction
*action
, gpointer user_data
)
228 struct ui_repdist_data
*data
= user_data
;
230 ui_repdist_toggle_legend(data
->window
, NULL
);
233 static void ui_repdist_action_rate(GtkAction
*action
, gpointer user_data
)
235 struct ui_repdist_data
*data
= user_data
;
237 ui_repdist_toggle_rate(data
->window
, NULL
);
240 static void ui_repdist_action_filter(GtkAction
*action
, gpointer user_data
)
242 struct ui_repdist_data
*data
= user_data
;
245 //create_deffilter_window(data->filter, TRUE);
247 if(ui_flt_manage_dialog_new(data
->window
, data
->filter
, TRUE
) != GTK_RESPONSE_REJECT
)
249 ui_repdist_compute(data
->window
, NULL
);
250 ui_repdist_update_daterange(data
->window
, NULL
);
254 static void ui_repdist_action_refresh(GtkAction
*action
, gpointer user_data
)
256 struct ui_repdist_data
*data
= user_data
;
258 ui_repdist_compute(data
->window
, NULL
);
261 static void ui_repdist_action_export(GtkAction
*action
, gpointer user_data
)
263 struct ui_repdist_data
*data
= user_data
;
265 ui_repdist_export_csv(data
->window
, NULL
);
270 /* ======================== */
275 ** ============================================================================
282 ** return the month list position correponding to the passed date
284 static gint
DateInPer(guint32 from
, guint32 opedate
)
286 GDate
*date1
, *date2
;
290 // this return sometimes -1, -2 which is wrong
292 date1
= g_date_new_julian(from
);
293 date2
= g_date_new_julian(opedate
);
295 pos
= ((g_date_get_year(date2
) - g_date_get_year(date1
)) * 12) + g_date_get_month(date2
) - g_date_get_month(date1
);
297 //g_print(" from=%d-%d ope=%d-%d => %d\n", g_date_get_month(date1), g_date_get_year(date1), g_date_get_month(date2), g_date_get_year(date2), pos);
306 ** return the year list position correponding to the passed date
308 static gint
DateInYear(guint32 from
, guint32 opedate
)
311 gint year_from
, year_ope
, pos
;
313 date
= g_date_new_julian(from
);
314 year_from
= g_date_get_year(date
);
315 g_date_set_julian(date
, opedate
);
316 year_ope
= g_date_get_year(date
);
319 pos
= year_ope
- year_from
;
321 //g_print(" from=%d ope=%d => %d\n", year_from, year_ope, pos);
326 static void ui_repdist_date_change(GtkWidget
*widget
, gpointer user_data
)
328 struct ui_repdist_data
*data
;
330 DB( g_print("\n[repdist] date change\n") );
332 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
334 data
->filter
->mindate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_mindate
));
335 data
->filter
->maxdate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_maxdate
));
337 // set min/max date for both widget
338 gtk_date_entry_set_maxdate(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->maxdate
);
339 gtk_date_entry_set_mindate(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->mindate
);
341 g_signal_handler_block(data
->CY_range
, data
->handler_id
[HID_REPDIST_RANGE
]);
342 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), FLT_RANGE_OTHER
);
343 g_signal_handler_unblock(data
->CY_range
, data
->handler_id
[HID_REPDIST_RANGE
]);
346 ui_repdist_compute(widget
, NULL
);
347 ui_repdist_update_daterange(widget
, NULL
);
353 static void ui_repdist_range_change(GtkWidget
*widget
, gpointer user_data
)
355 struct ui_repdist_data
*data
;
358 DB( g_print("\n[repdist] range change\n") );
360 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
362 range
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_range
));
364 if(range
!= FLT_RANGE_OTHER
)
366 filter_preset_daterange_set(data
->filter
, range
, 0);
368 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
369 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
371 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
372 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
374 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
375 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
377 ui_repdist_compute(widget
, NULL
);
378 ui_repdist_update_daterange(widget
, NULL
);
382 if(ui_flt_manage_dialog_new(data
->window
, data
->filter
, TRUE
) != GTK_RESPONSE_REJECT
)
384 ui_repdist_compute(data
->window
, NULL
);
385 ui_repdist_update_daterange(widget
, NULL
);
392 static gint
ui_repdist_result_get_pos(gint tmpfor
, guint from
, Transaction
*ope
)
398 case BY_REPDIST_CATEGORY
:
400 Category
*catentry
= da_cat_get(ope
->kcat
);
402 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
405 case BY_REPDIST_SUBCATEGORY
:
408 case BY_REPDIST_PAYEE
:
411 case BY_REPDIST_MONTH
:
412 pos
= DateInPer(from
, ope
->date
);
414 case BY_REPDIST_YEAR
:
415 pos
= DateInYear(from
, ope
->date
);
424 static void ui_repdist_detail(GtkWidget
*widget
, gpointer user_data
)
426 struct ui_repdist_data
*data
;
427 guint active
= GPOINTER_TO_INT(user_data
);
433 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
435 DB( g_print("\n[repdist] detail\n") );
437 /* clear and detach our model */
438 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
));
439 gtk_list_store_clear (GTK_LIST_STORE(model
));
443 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
445 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
446 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), NULL
); /* Detach model from view */
448 /* fill in the model */
449 list
= g_queue_peek_head_link(data
->txn_queue
);
452 Transaction
*ope
= list
->data
;
454 if(filter_test(data
->filter
, ope
) == 1)
458 if( tmpfor
!= BY_REPDIST_TAG
)
460 if( (tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
) && ope
->flags
& OF_SPLIT
)
462 guint nbsplit
= da_splits_count(ope
->splits
);
465 for(i
=0;i
<nbsplit
;i
++)
467 split
= ope
->splits
[i
];
470 case BY_REPDIST_CATEGORY
:
472 Category
*catentry
= da_cat_get(split
->kcat
);
474 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
477 case BY_REPDIST_SUBCATEGORY
:
485 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
486 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
487 LST_DSPOPE_DATAS
, ope
,
497 pos
= ui_repdist_result_get_pos(tmpfor
, data
->filter
->mindate
, ope
);
501 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
502 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
503 LST_DSPOPE_DATAS
, ope
,
511 /* the TAG process is particular */
513 if(ope
->tags
!= NULL
)
515 guint32
*tptr
= ope
->tags
;
521 DB( g_print(" -> storing tag %d %.2f\n", pos
, ope
->amount
) );
525 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
526 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
527 LST_DSPOPE_DATAS
, ope
,
542 list
= g_list_next(list
);
545 /* Re-attach model to view */
546 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), model
);
547 g_object_unref(model
);
549 gtk_tree_view_columns_autosize( GTK_TREE_VIEW(data
->LV_detail
) );
556 static void ui_repdist_update(GtkWidget
*widget
, gpointer user_data
)
558 struct ui_repdist_data
*data
;
561 gint page
, tmpfor
, tmpkind
, column
;
565 DB( g_print("\n[repdist] update\n") );
567 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
570 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
571 byamount
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_byamount
));
572 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
573 tmpkind
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
575 // ensure not exp & inc for piechart
576 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
578 if( page
== 2 && tmpkind
== 0 )
580 g_signal_handler_block(data
->CY_view
, data
->handler_id
[HID_REPDIST_VIEW
]);
581 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
582 g_signal_handler_unblock(data
->CY_view
, data
->handler_id
[HID_REPDIST_VIEW
]);
587 DB( g_print(" tmpkind %d\n\n", tmpkind
) );
590 column
= byamount
? LST_REPDIST_EXPENSE
+(tmpkind
-1)*2 : LST_REPDIST_POS
;
592 //#833614 sort category/payee by name
593 //if(!byamount && tmpkind <= BY_REPDIST_PAYEE)
594 // column = LST_REPDIST_NAME;
596 DB( g_print(" sort on column %d\n\n", column
) );
598 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model
), column
, GTK_SORT_DESCENDING
);
600 column
= LST_REPDIST_EXPENSE
+(tmpkind
-1)*2;
602 /* set chart color scheme */
603 gtk_chart_set_color_scheme(GTK_CHART(data
->RE_chart
), PREFS
->report_color_scheme
);
605 /* set chart title */
606 ////TRANSLATORS: example 'Expense by Category'
607 title
= g_strdup_printf(_("%s by %s"), _(CYA_KIND2
[tmpkind
]), _(CYA_STATSELECT
[tmpfor
]) );
609 /* update absolute or not */
610 gboolean abs
= (tmpkind
== 1 || tmpkind
== 2) ? TRUE
: FALSE
;
611 gtk_chart_set_absolute(GTK_CHART(data
->RE_chart
), abs
);
614 /* update bar chart */
615 DB( g_print(" set bar to %d %s\n\n", column
, _(CYA_KIND2
[tmpkind
])) );
617 gtk_chart_set_dualdatas(GTK_CHART(data
->RE_chart
), model
, LST_REPDIST_EXPENSE
, LST_REPDIST_INCOME
, title
, NULL
);
619 gtk_chart_set_datas(GTK_CHART(data
->RE_chart
), model
, column
, title
, NULL
);
622 /* show xval for month/year and no by amount display */
626 if( !byamount
&& (tmpfor
== BY_REPDIST_MONTH
|| tmpfor
== BY_REPDIST_YEAR
) )
631 case BY_REPDIST_MONTH
:
632 gtk_chart_set_every_xval(GTK_CHART(data
->RE_chart
), 4);
634 case BY_REPDIST_YEAR
:
635 gtk_chart_set_every_xval(GTK_CHART(data
->RE_chart
), 2);
640 gtk_chart_show_xval(GTK_CHART(data
->RE_chart
), xval
);
646 static void ui_repdist_update_daterange(GtkWidget
*widget
, gpointer user_data
)
648 struct ui_repdist_data
*data
;
651 DB( g_print("\n[repdist] update daterange\n") );
653 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
655 daterange
= filter_daterange_text_get(data
->filter
);
656 gtk_label_set_markup(GTK_LABEL(data
->TX_daterange
), daterange
);
660 static void ui_repdist_update_total(GtkWidget
*widget
, gpointer user_data
)
662 struct ui_repdist_data
*data
;
665 DB( g_print("\n[repdist] update total\n") );
667 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
669 //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
671 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[0]), data
->total_expense
, GLOBALS
->kcur
, GLOBALS
->minor
);
672 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[1]), data
->total_income
, GLOBALS
->kcur
, GLOBALS
->minor
);
673 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[2]), data
->total_expense
+ data
->total_income
, GLOBALS
->kcur
, GLOBALS
->minor
);
678 static void ui_repdist_export_csv(GtkWidget
*widget
, gpointer user_data
)
680 struct ui_repdist_data
*data
;
684 gchar
*filename
= NULL
;
686 gchar
*outstr
, *name
;
689 DB( g_print("\n[repdist] export csv\n") );
691 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
693 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
695 name
= g_strdup_printf("hb-stat_%s.csv", CYA_STATSELECT
[tmpfor
]);
697 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, name
) == TRUE
)
699 DB( g_print(" + filename is %s\n", filename
) );
701 io
= g_io_channel_new_file(filename
, "w", NULL
);
705 outstr
= g_strdup_printf("%s;%s;%s;%s\n", _("Result"), _("expense"), _("Income"), _("Balance"));
706 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
708 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
709 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
713 gdouble exp
, inc
, bal
;
715 gtk_tree_model_get (model
, &iter
,
716 //LST_REPDIST_KEY, i,
717 LST_REPDIST_NAME
, &name
,
718 LST_REPDIST_EXPENSE
, &exp
,
719 LST_REPDIST_INCOME
, &inc
,
720 LST_REPDIST_BALANCE
, &bal
,
723 outstr
= g_strdup_printf("%s;%.2f;%.2f;%.2f\n", name
, exp
, inc
, bal
);
724 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
726 DB( g_print("%s", outstr
) );
730 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
733 g_io_channel_unref (io
);
745 static void ui_repdist_compute(GtkWidget
*widget
, gpointer user_data
)
747 struct ui_repdist_data
*data
;
748 gint tmpfor
, tmpkind
;
752 GList
*list
, *tmplist
= NULL
;
753 guint n_result
, sortid
;
755 GDate
*date1
, *date2
;
756 gdouble
*tmp_income
, *tmp_expense
;
757 gdouble exprate
, incrate
, balrate
;
759 DB( g_print("\n[repdist] compute\n") );
761 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
763 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
764 tmpkind
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
767 DB( g_print(" for=%d,kind=%d\n", tmpfor
, tmpkind
) );
769 //get our min max date
770 from
= data
->filter
->mindate
;
771 to
= data
->filter
->maxdate
;
772 if(to
< from
) return;
775 g_queue_free (data
->txn_queue
);
776 data
->txn_queue
= hbfile_transaction_get_partial(data
->filter
->mindate
, data
->filter
->maxdate
);
778 DB( g_print(" nb-txn=%d\n", g_queue_get_length (data
->txn_queue
) ) );
780 /* count number or results */
783 case BY_REPDIST_CATEGORY
:
784 case BY_REPDIST_SUBCATEGORY
:
785 n_result
= da_cat_get_max_key() + 1;
786 tmplist
= category_glist_sorted(1);
788 case BY_REPDIST_PAYEE
:
789 n_result
= da_pay_get_max_key() + 1;
790 tmplist
= payee_glist_sorted(1);
793 n_result
= da_tag_length();
794 tmplist
= tag_glist_sorted(1);
796 case BY_REPDIST_MONTH
:
797 date1
= g_date_new_julian(from
);
798 date2
= g_date_new_julian(to
);
799 n_result
= ((g_date_get_year(date2
) - g_date_get_year(date1
)) * 12) + g_date_get_month(date2
) - g_date_get_month(date1
) + 1;
803 case BY_REPDIST_YEAR
:
804 date1
= g_date_new_julian(from
);
805 date2
= g_date_new_julian(to
);
806 n_result
= g_date_get_year(date2
) - g_date_get_year(date1
) + 1;
814 DB( g_print(" %s :: n_result=%d\n", CYA_STATSELECT
[tmpfor
], n_result
) );
816 /* allocate some memory */
817 tmp_expense
= g_malloc0((n_result
+2) * sizeof(gdouble
));
818 tmp_income
= g_malloc0((n_result
+2) * sizeof(gdouble
));
820 data
->total_expense
= 0.0;
821 data
->total_income
= 0.0;
823 if(tmp_expense
&& tmp_income
)
826 DB( g_print(" - ok memory\n") );
828 /* compute the results */
829 list
= g_queue_peek_head_link(data
->txn_queue
);
832 Transaction
*ope
= list
->data
;
834 DB( g_print("** testing '%s', cat=%d==> %d\n", ope
->wording
, ope
->kcat
, filter_test(data
->filter
, ope
)) );
836 if( (filter_test(data
->filter
, ope
) == 1) )
841 DB( g_print(" - should insert\n") );
843 //trn_amount = ope->amount;
844 trn_amount
= hb_amount_base(ope
->amount
, ope
->kcur
);
846 //#1562372 in case of a split we need to take amount for filter categories only
847 if( ope
->flags
& OF_SPLIT
)
849 guint nbsplit
= da_splits_count(ope
->splits
);
856 for(i
=0;i
<nbsplit
;i
++)
858 split
= ope
->splits
[i
];
859 catentry
= da_cat_get(split
->kcat
);
860 if(catentry
== NULL
) continue;
861 sinsert
= ( catentry
->filter
== TRUE
) ? 1 : 0;
862 if(data
->filter
->option
[FILTER_CATEGORY
] == 2) sinsert
^= 1;
864 DB( g_print(" split '%s' insert=%d\n",catentry
->name
, sinsert
) );
866 if( (data
->filter
->option
[FILTER_CATEGORY
] == 0) || sinsert
)
868 trn_amount
+= hb_amount_base(split
->amount
, ope
->kcur
);
875 if( tmpfor
!= BY_REPDIST_TAG
)
877 if( (tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
) && ope
->flags
& OF_SPLIT
)
879 guint nbsplit
= da_splits_count(ope
->splits
);
884 for(i
=0;i
<nbsplit
;i
++)
886 split
= ope
->splits
[i
];
887 catentry
= da_cat_get(split
->kcat
);
888 if(catentry
== NULL
) continue;
889 sinsert
= ( catentry
->filter
== TRUE
) ? 1 : 0;
890 if(data
->filter
->option
[FILTER_CATEGORY
] == 2) sinsert
^= 1;
892 DB( g_print(" split '%s' insert=%d\n",catentry
->name
, sinsert
) );
894 if( (data
->filter
->option
[FILTER_CATEGORY
] == 0) || sinsert
)
898 case BY_REPDIST_CATEGORY
:
900 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
903 case BY_REPDIST_SUBCATEGORY
:
908 trn_amount
= hb_amount_base(split
->amount
, ope
->kcur
);
909 //trn_amount = split->amount;
913 tmp_income
[pos
] += trn_amount
;
914 data
->total_income
+= trn_amount
;
918 tmp_expense
[pos
] += trn_amount
;
919 data
->total_expense
+= trn_amount
;
929 pos
= ui_repdist_result_get_pos(tmpfor
, from
, ope
);
932 tmp_income
[pos
] += trn_amount
;
933 data
->total_income
+= trn_amount
;
937 tmp_expense
[pos
] += trn_amount
;
938 data
->total_expense
+= trn_amount
;
943 /* the TAG process is particularly */
945 if(ope
->tags
!= NULL
)
947 guint32
*tptr
= ope
->tags
;
953 DB( g_print(" -> storing tag %d %s %.2f\n", pos
, da_tag_get(*tptr
)->name
, trn_amount
) );
957 tmp_income
[pos
] += trn_amount
;
961 tmp_expense
[pos
] += trn_amount
;
969 data
->total_income
+= trn_amount
;
973 data
->total_expense
+= trn_amount
;
979 // fix total according to selection
980 //if(tmpkind==0 && !tmp_expense[pos]) { data->total_income -= ope->amount; }
981 //if(tmpkind==1 && !tmp_income[pos] ) { data->total_expense -= ope->amount; }
986 list
= g_list_next(list
);
989 /* clear and detach our model */
990 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
991 gtk_list_store_clear (GTK_LIST_STORE(model
));
992 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
993 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), NULL
); /* Detach model from view */
995 /* insert into the treeview */
996 for(i
=0, sortid
=0; i
<n_result
; i
++)
998 gchar
*name
, *fullcatname
;
1005 DB( g_print("try to insert item %d - %.2f %.2f\n", i
, tmp_expense
[i
], tmp_income
[i
]) );
1008 /* filter empty results */
1009 if(tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
|| tmpfor
== BY_REPDIST_PAYEE
|| tmpfor
== BY_REPDIST_TAG
)
1011 if( tmpkind
== 1 && !tmp_expense
[i
] ) continue;
1012 if( tmpkind
== 2 && !tmp_income
[i
] ) continue;
1013 if( !tmp_expense
[i
] && !tmp_income
[i
] ) continue;
1016 /* get the result name */
1019 case BY_REPDIST_CATEGORY
:
1021 Category
*entry
= da_cat_get(i
);
1025 name
= entry
->key
== 0 ? _("(no category)") : entry
->name
;
1027 sortid
= g_list_index(tmplist
, entry
);
1032 case BY_REPDIST_SUBCATEGORY
:
1034 Category
*entry
= da_cat_get(i
);
1037 if(entry
->flags
& GF_SUB
)
1039 Category
*parent
= da_cat_get(entry
->parent
);
1041 fullcatname
= g_strdup_printf("%s : %s", parent
->name
, entry
->name
);
1045 name
= entry
->key
== 0 ? _("(no category)") : entry
->name
;
1047 sortid
= g_list_index(tmplist
, entry
);
1052 case BY_REPDIST_PAYEE
:
1054 Payee
*entry
= da_pay_get(i
);
1057 name
= entry
->key
== 0 ? _("(no payee)") : entry
->name
;
1058 sortid
= g_list_index(tmplist
, entry
);
1063 case BY_REPDIST_TAG
:
1065 Tag
*entry
= da_tag_get(i
+1);
1067 sortid
= g_list_index(tmplist
, entry
);
1071 case BY_REPDIST_MONTH
:
1072 date
= g_date_new_julian(from
);
1073 g_date_add_months(date
, i
);
1074 //g_snprintf(buffer, 63, "%d-%02d", g_date_get_year(date), g_date_get_month(date));
1075 g_snprintf(buffer
, 63, "%d-%s", g_date_get_year(date
), _(CYA_MONTHS
[g_date_get_month(date
)-1]));
1080 case BY_REPDIST_YEAR
:
1081 date
= g_date_new_julian(from
);
1082 g_date_add_years(date
, i
);
1083 g_snprintf(buffer
, 63, "%d", g_date_get_year(date
));
1089 DB( g_print(" inserting %2d, '%s', %9.2f %9.2f %9.2f\n", i
, name
, tmp_expense
[i
], tmp_income
[i
], tmp_expense
[i
] + tmp_income
[i
]) );
1096 if( data
->total_expense
)
1097 exprate
= ABS((tmp_expense
[i
] * 100 / data
->total_expense
));
1099 if( data
->total_income
)
1100 incrate
= (tmp_income
[i
] * 100 / data
->total_income
);
1102 data
->total_balance
= ABS(data
->total_expense
) + data
->total_income
;
1103 if( data
->total_balance
)
1104 balrate
= (ABS(tmp_expense
[i
]) + tmp_income
[i
]) * 100 / data
->total_balance
;
1106 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
1107 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
1108 LST_REPDIST_POS
, sortid
++,
1110 LST_REPDIST_NAME
, name
,
1111 LST_REPDIST_EXPENSE
, tmp_expense
[i
],
1112 LST_REPDIST_INCOME
, tmp_income
[i
],
1113 LST_REPDIST_BALANCE
, tmp_expense
[i
] + tmp_income
[i
],
1114 LST_REPDIST_EXPRATE
, exprate
,
1115 LST_REPDIST_INCRATE
, incrate
,
1116 LST_REPDIST_BALRATE
, balrate
,
1119 g_free(fullcatname
);
1122 /* update column 0 title */
1123 GtkTreeViewColumn
*column
= gtk_tree_view_get_column( GTK_TREE_VIEW(data
->LV_report
), 0);
1124 gtk_tree_view_column_set_title(column
, _(CYA_STATSELECT
[tmpfor
]));
1126 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
1128 /* Re-attach model to view */
1129 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), model
);
1130 g_object_unref(model
);
1133 /* free our memory */
1134 g_free(tmp_expense
);
1137 /* free tmplist (sort cat/pay) */
1138 g_list_free(tmplist
);
1140 ui_repdist_update_total(widget
,NULL
);
1142 ui_repdist_update(widget
, user_data
);
1151 ** update sensitivity
1153 static void ui_repdist_sensitive(GtkWidget
*widget
, gpointer user_data
)
1155 struct ui_repdist_data
*data
;
1160 DB( g_print("\n[repdist] sensitive\n") );
1162 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1164 active
= gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), NULL
, NULL
);
1166 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
1168 sensitive
= page
== 0 ? active
: FALSE
;
1169 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_DETAIL], sensitive);
1170 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Detail"), sensitive
);
1172 //view = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_view));
1174 sensitive
= page
== 0 ? FALSE
: TRUE
;
1175 gtk_widget_set_sensitive(data
->LB_zoomx
, sensitive
);
1176 gtk_widget_set_sensitive(data
->RG_zoomx
, sensitive
);
1177 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Legend"), sensitive
);
1179 sensitive
= page
== 0 ? TRUE
: FALSE
;
1180 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Rate"), sensitive
);
1185 static void ui_repdist_detail_onRowActivated (GtkTreeView
*treeview
,
1187 GtkTreeViewColumn
*col
,
1190 struct ui_repdist_data
*data
;
1191 Transaction
*active_txn
;
1194 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
1196 DB( g_print ("\n[repdist] A detail row has been double-clicked!\n") );
1198 active_txn
= list_txn_get_active_transaction(GTK_TREE_VIEW(data
->LV_detail
));
1201 Transaction
*old_txn
, *new_txn
;
1203 old_txn
= da_transaction_clone (active_txn
);
1204 new_txn
= active_txn
;
1205 result
= deftransaction_external_edit(GTK_WINDOW(data
->window
), old_txn
, new_txn
);
1207 if(result
== GTK_RESPONSE_ACCEPT
)
1210 GLOBALS
->changes_count
++;
1211 ui_repdist_compute(data
->window
, NULL
);
1214 da_transaction_free (old_txn
);
1219 static void ui_repdist_update_detail(GtkWidget
*widget
, gpointer user_data
)
1221 struct ui_repdist_data
*data
;
1223 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1225 if(GTK_IS_TREE_VIEW(data
->LV_report
))
1229 GtkTreeSelection
*treeselection
;
1230 GtkTreeModel
*model
;
1234 treeselection
= gtk_tree_view_get_selection (GTK_TREE_VIEW(data
->LV_report
));
1236 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
1238 gtk_tree_model_get(model
, &iter
, LST_REPDIST_KEY
, &key
, -1);
1240 DB( g_print(" - active is %d\n", key
) );
1242 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
1247 gtk_widget_show(data
->GR_detail
);
1250 gtk_widget_hide(data
->GR_detail
);
1258 static void ui_repdist_toggle_detail(GtkWidget
*widget
, gpointer user_data
)
1260 struct ui_repdist_data
*data
;
1262 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1266 DB( g_print("\n[repdist] toggledetail to %d\n", data
->detail
) );
1268 ui_repdist_update_detail(widget
, user_data
);
1273 ** change the chart legend visibility
1275 static void ui_repdist_toggle_legend(GtkWidget
*widget
, gpointer user_data
)
1277 struct ui_repdist_data
*data
;
1280 DB( g_print("\n[repdist] toggle legend\n") );
1282 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1286 gtk_chart_show_legend(GTK_CHART(data
->RE_chart
), data
->legend
, FALSE
);
1290 static void ui_repdist_zoomx_callback(GtkWidget
*widget
, gpointer user_data
)
1292 struct ui_repdist_data
*data
;
1295 DB( g_print("\n[repdist] zoomx\n") );
1297 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1299 value
= gtk_range_get_value(GTK_RANGE(data
->RG_zoomx
));
1301 DB( g_print(" + scale is %.2f\n", value
) );
1303 gtk_chart_set_barw(GTK_CHART(data
->RE_chart
), value
);
1309 ** change the chart rate columns visibility
1311 static void ui_repdist_toggle_rate(GtkWidget
*widget
, gpointer user_data
)
1313 struct ui_repdist_data
*data
;
1314 GtkTreeViewColumn
*column
;
1316 DB( g_print("\n[repdist] toggle rate\n") );
1318 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1322 if(GTK_IS_TREE_VIEW(data
->LV_report
))
1325 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 2);
1326 gtk_tree_view_column_set_visible(column
, data
->rate
);
1328 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 4);
1329 gtk_tree_view_column_set_visible(column
, data
->rate
);
1331 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 6);
1332 gtk_tree_view_column_set_visible(column
, data
->rate
);
1337 static void ui_repdist_toggle_minor(GtkWidget
*widget
, gpointer user_data
)
1339 struct ui_repdist_data
*data
;
1341 DB( g_print("\n[repdist] toggle minor\n") );
1343 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1345 GLOBALS
->minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
1347 ui_repdist_update_total(widget
,NULL
);
1349 //hbfile_update(data->LV_acc, (gpointer)4);
1350 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
1351 gtk_chart_show_minor(GTK_CHART(data
->RE_chart
), GLOBALS
->minor
);
1359 static void ui_repdist_setup(struct ui_repdist_data
*data
)
1361 DB( g_print("\n[repdist] setup\n") );
1363 data
->txn_queue
= g_queue_new ();
1365 data
->filter
= da_filter_malloc();
1366 filter_default_all_set(data
->filter
);
1369 data
->detail
= PREFS
->stat_showdetail
;
1371 data
->rate
= PREFS
->stat_showrate
^1;
1374 ui_repdist_toggle_rate(data
->window
, NULL
);
1378 /* 3.4 : make int transfer out of stats */
1379 data
->filter
->option
[FILTER_PAYMODE
] = 1;
1380 data
->filter
->paymode
[PAYMODE_INTXFER
] = FALSE
;
1382 filter_preset_daterange_set(data
->filter
, PREFS
->date_range_rep
, 0);
1384 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
1385 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
1387 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
1388 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
1390 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
1391 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
1397 static void ui_repdist_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
1399 GtkTreeModel
*model
;
1403 DB( g_print("\n[repdist] selection\n") );
1405 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
1407 gtk_tree_model_get(model
, &iter
, LST_REPDIST_KEY
, &key
, -1);
1411 DB( g_print(" - active is %d\n", key
) );
1413 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
1414 ui_repdist_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
1421 static gboolean
ui_repdist_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1423 struct ui_repdist_data
*data
= user_data
;
1424 struct WinGeometry
*wg
;
1426 DB( g_print("\n[repdist] dispose\n") );
1428 g_queue_free (data
->txn_queue
);
1430 da_filter_free(data
->filter
);
1434 //store position and size
1435 wg
= &PREFS
->sta_wg
;
1436 gtk_window_get_position(GTK_WINDOW(widget
), &wg
->l
, &wg
->t
);
1437 gtk_window_get_size(GTK_WINDOW(widget
), &wg
->w
, &wg
->h
);
1439 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg
->l
, wg
->t
, wg
->w
, wg
->h
) );
1443 //enable define windows
1444 GLOBALS
->define_off
--;
1445 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
1450 // the window creation
1451 GtkWidget
*ui_repdist_window_new(void)
1453 struct ui_repdist_data
*data
;
1454 struct WinGeometry
*wg
;
1455 GtkWidget
*window
, *mainvbox
, *hbox
, *vbox
, *notebook
, *treeview
, *vpaned
, *sw
;
1456 GtkWidget
*label
, *widget
, *table
, *entry
;
1459 GtkActionGroup
*actions
;
1461 GError
*error
= NULL
;
1463 DB( g_print("\n[repdist] new\n") );
1466 data
= g_malloc0(sizeof(struct ui_repdist_data
));
1467 if(!data
) return NULL
;
1469 //disable define windows
1470 GLOBALS
->define_off
++;
1471 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(2));
1473 /* create window, etc */
1474 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1475 data
->window
= window
;
1477 //store our window private data
1478 g_object_set_data(G_OBJECT(window
), "inst_data", (gpointer
)data
);
1480 gtk_window_set_title (GTK_WINDOW (window
), _("Statistics Report"));
1482 //set the window icon
1483 gtk_window_set_icon_name(GTK_WINDOW (window
), ICONNAME_HB_REP_STATS
);
1487 mainvbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1488 gtk_container_add (GTK_CONTAINER (window
), mainvbox
);
1490 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
1491 gtk_box_pack_start (GTK_BOX (mainvbox
), hbox
, TRUE
, TRUE
, 0);
1494 table
= gtk_grid_new ();
1495 gtk_widget_set_hexpand (GTK_WIDGET(table
), FALSE
);
1496 gtk_box_pack_start (GTK_BOX (hbox
), table
, FALSE
, FALSE
, 0);
1498 gtk_container_set_border_width (GTK_CONTAINER (table
), SPACING_SMALL
);
1499 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_SMALL
);
1500 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1503 label
= make_label_group(_("Display"));
1504 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
1507 label
= make_label_widget(_("_View:"));
1508 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1509 widget
= make_cycle(label
, CYA_KIND2
);
1510 data
->CY_view
= widget
;
1511 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1514 label
= make_label_widget(_("_By:"));
1515 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1516 widget
= make_cycle(label
, CYA_STATSELECT
);
1517 data
->CY_by
= widget
;
1518 gtk_grid_attach (GTK_GRID (table
), data
->CY_by
, 2, row
, 1, 1);
1521 widget
= gtk_check_button_new_with_mnemonic (_("By _amount"));
1522 data
->CM_byamount
= widget
;
1523 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1526 widget
= gtk_check_button_new_with_mnemonic (_("Euro _minor"));
1527 data
->CM_minor
= widget
;
1528 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1532 label
= make_label_widget(_("_Zoom X:"));
1533 data
->LB_zoomx
= label
;
1534 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1535 widget
= make_scale(label
);
1536 data
->RG_zoomx
= widget
;
1537 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1542 widget = gtk_check_button_new_with_mnemonic ("Legend");
1543 data->CM_legend = widget;
1544 gtk_grid_attach (GTK_GRID (table), widget, 1, 2, row, row+1);
1547 widget
= gtk_separator_new(GTK_ORIENTATION_HORIZONTAL
);
1548 gtk_grid_attach (GTK_GRID (table
), widget
, 0, row
, 3, 1);
1551 label
= make_label_group(_("Date filter"));
1552 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
1555 label
= make_label_widget(_("_Range:"));
1556 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1557 data
->CY_range
= make_daterange(label
, TRUE
);
1558 gtk_grid_attach (GTK_GRID (table
), data
->CY_range
, 2, row
, 1, 1);
1561 label
= make_label_widget(_("_From:"));
1562 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1563 data
->PO_mindate
= gtk_date_entry_new();
1564 gtk_grid_attach (GTK_GRID (table
), data
->PO_mindate
, 2, row
, 1, 1);
1567 label
= make_label_widget(_("_To:"));
1568 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1569 data
->PO_maxdate
= gtk_date_entry_new();
1570 gtk_grid_attach (GTK_GRID (table
), data
->PO_maxdate
, 2, row
, 1, 1);
1572 //part: info + report
1573 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1574 gtk_box_pack_start (GTK_BOX (hbox
), vbox
, TRUE
, TRUE
, 0);
1577 actions
= gtk_action_group_new ("Account");
1580 gtk_action_group_set_translation_domain(actions
, GETTEXT_PACKAGE
);
1582 // data to action callbacks is set here (data)
1583 gtk_action_group_add_actions (actions
, entries
, n_entries
, data
);
1585 gtk_action_group_add_toggle_actions (actions
,
1586 toggle_entries
, n_toggle_entries
,
1590 /* set which action should have priority in the toolbar */
1591 action
= gtk_action_group_get_action(actions
, "List");
1592 g_object_set(action
, "is_important", TRUE
, NULL
);
1594 action
= gtk_action_group_get_action(actions
, "Column");
1595 g_object_set(action
, "is_important", TRUE
, NULL
);
1597 action
= gtk_action_group_get_action(actions
, "Donut");
1598 g_object_set(action
, "is_important", TRUE
, NULL
);
1600 action
= gtk_action_group_get_action(actions
, "Detail");
1601 g_object_set(action
, "is_important", TRUE
, NULL
);
1602 g_object_set(action
, "active", PREFS
->stat_showdetail
, NULL
);
1604 action
= gtk_action_group_get_action(actions
, "Rate");
1605 g_object_set(action
, "active", PREFS
->stat_showrate
, NULL
);
1607 action
= gtk_action_group_get_action(actions
, "Filter");
1608 g_object_set(action
, "is_important", TRUE
, NULL
);
1610 action
= gtk_action_group_get_action(actions
, "Refresh");
1611 g_object_set(action
, "is_important", TRUE
, NULL
);
1614 ui
= gtk_ui_manager_new ();
1615 gtk_ui_manager_insert_action_group (ui
, actions
, 0);
1616 gtk_window_add_accel_group (GTK_WINDOW (window
), gtk_ui_manager_get_accel_group (ui
));
1618 if (!gtk_ui_manager_add_ui_from_string (ui
, ui_info
, -1, &error
))
1620 g_message ("building UI failed: %s", error
->message
);
1621 g_error_free (error
);
1625 data
->actions
= actions
;
1628 data
->TB_bar
= gtk_ui_manager_get_widget (ui
, "/ToolBar");
1629 gtk_box_pack_start (GTK_BOX (vbox
), data
->TB_bar
, FALSE
, FALSE
, 0);
1632 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, SPACING_SMALL
);
1633 gtk_container_set_border_width (GTK_CONTAINER(hbox
), SPACING_SMALL
);
1634 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1636 widget
= make_label(NULL
, 0.5, 0.5);
1637 gimp_label_set_attributes (GTK_LABEL (widget
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
1638 data
->TX_daterange
= widget
;
1639 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1641 entry
= gtk_label_new(NULL
);
1642 data
->TX_total
[2] = entry
;
1643 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1644 label
= gtk_label_new(_("Balance:"));
1645 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1647 entry
= gtk_label_new(NULL
);
1648 data
->TX_total
[1] = entry
;
1649 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1650 label
= gtk_label_new(_("Income:"));
1651 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1654 entry
= gtk_label_new(NULL
);
1655 data
->TX_total
[0] = entry
;
1656 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1657 label
= gtk_label_new(_("Expense:"));
1658 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1662 notebook
= gtk_notebook_new();
1663 data
->GR_result
= notebook
;
1664 gtk_widget_show(notebook
);
1665 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
1666 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
1667 gtk_box_pack_start (GTK_BOX (vbox
), notebook
, TRUE
, TRUE
, 0);
1670 vpaned
= gtk_paned_new(GTK_ORIENTATION_VERTICAL
);
1671 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vpaned
, NULL
);
1674 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1675 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw
), GTK_SHADOW_ETCHED_IN
);
1676 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1677 treeview
= ui_list_repdist_create();
1678 data
->LV_report
= treeview
;
1679 gtk_container_add (GTK_CONTAINER(sw
), treeview
);
1680 gtk_paned_pack1 (GTK_PANED(vpaned
), sw
, TRUE
, TRUE
);
1683 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1684 data
->GR_detail
= sw
;
1685 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (sw), GTK_CORNER_TOP_RIGHT);
1686 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw
), GTK_SHADOW_ETCHED_IN
);
1687 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1688 treeview
= create_list_transaction(LIST_TXN_TYPE_DETAIL
, PREFS
->lst_ope_columns
);
1689 data
->LV_detail
= treeview
;
1690 gtk_container_add (GTK_CONTAINER(sw
), treeview
);
1691 gtk_paned_pack2 (GTK_PANED(vpaned
), sw
, TRUE
, TRUE
);
1694 widget
= gtk_chart_new(CHART_TYPE_COL
);
1695 data
->RE_chart
= widget
;
1696 gtk_chart_set_minor_prefs(GTK_CHART(widget
), PREFS
->euro_value
, PREFS
->minor_cur
.symbol
);
1697 gtk_chart_set_currency(GTK_CHART(widget
), GLOBALS
->kcur
);
1698 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), widget
, NULL
);
1700 //todo: setup should move this
1701 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_minor
), GLOBALS
->minor
);
1702 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_byamount
), PREFS
->stat_byamount
);
1704 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
1706 /* attach our minor to treeview */
1707 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
))), "minor", (gpointer
)data
->CM_minor
);
1708 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
))), "minor", (gpointer
)data
->CM_minor
);
1710 /* signal connect */
1711 g_signal_connect (window
, "delete-event", G_CALLBACK (ui_repdist_dispose
), (gpointer
)data
);
1713 g_signal_connect (data
->CM_minor
, "toggled", G_CALLBACK (ui_repdist_toggle_minor
), NULL
);
1715 data
->handler_id
[HID_REPDIST_MINDATE
] = g_signal_connect (data
->PO_mindate
, "changed", G_CALLBACK (ui_repdist_date_change
), (gpointer
)data
);
1716 data
->handler_id
[HID_REPDIST_MAXDATE
] = g_signal_connect (data
->PO_maxdate
, "changed", G_CALLBACK (ui_repdist_date_change
), (gpointer
)data
);
1718 data
->handler_id
[HID_REPDIST_RANGE
] = g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (ui_repdist_range_change
), NULL
);
1720 g_signal_connect (data
->CY_by
, "changed", G_CALLBACK (ui_repdist_compute
), (gpointer
)data
);
1721 data
->handler_id
[HID_REPDIST_VIEW
] = g_signal_connect (data
->CY_view
, "changed", G_CALLBACK (ui_repdist_compute
), (gpointer
)data
);
1723 g_signal_connect (data
->RG_zoomx
, "value-changed", G_CALLBACK (ui_repdist_zoomx_callback
), NULL
);
1726 g_signal_connect (data
->CM_byamount
, "toggled", G_CALLBACK (ui_repdist_update
), NULL
);
1728 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), "changed", G_CALLBACK (ui_repdist_selection
), NULL
);
1730 g_signal_connect (GTK_TREE_VIEW(data
->LV_detail
), "row-activated", G_CALLBACK (ui_repdist_detail_onRowActivated
), NULL
);
1732 //setup, init and show window
1733 ui_repdist_setup(data
);
1736 if(PREFS
->toolbar_style
== 0)
1737 gtk_toolbar_unset_style(GTK_TOOLBAR(data
->TB_bar
));
1739 gtk_toolbar_set_style(GTK_TOOLBAR(data
->TB_bar
), PREFS
->toolbar_style
-1);
1742 //setup, init and show window
1743 wg
= &PREFS
->sta_wg
;
1744 gtk_window_move(GTK_WINDOW(window
), wg
->l
, wg
->t
);
1745 gtk_window_resize(GTK_WINDOW(window
), wg
->w
, wg
->h
);
1747 gtk_widget_show_all (window
);
1752 if( PREFS
->euro_active
)
1753 gtk_widget_show(data
->CM_minor
);
1755 gtk_widget_hide(data
->CM_minor
);
1757 //gtk_widget_hide(data->GR_detail);
1761 ui_repdist_sensitive(window
, NULL
);
1762 ui_repdist_update_detail(window
, NULL
);
1764 DB( g_print("range: %d\n", PREFS
->date_range_rep
) );
1766 if( PREFS
->date_range_rep
!= 0)
1767 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), PREFS
->date_range_rep
);
1769 ui_repdist_compute(window
, NULL
);
1776 ** ============================================================================
1779 static void ui_list_repdist_rate_cell_data_function (GtkTreeViewColumn
*col
,
1780 GtkCellRenderer
*renderer
,
1781 GtkTreeModel
*model
,
1785 //GtkWidget *widget;
1787 //widget = g_object_get_data(G_OBJECT(model), "minor");
1789 //todo g_assert here and null test
1794 gtk_tree_model_get(model
, iter
, GPOINTER_TO_INT(user_data
), &tmp
, -1);
1798 g_snprintf(buf
, sizeof(buf
), "%.2f %%", tmp
);
1799 g_object_set(renderer
, "text", buf
, NULL
);
1802 g_object_set(renderer
, "text", "", NULL
);
1807 static void ui_list_repdist_amount_cell_data_function (GtkTreeViewColumn
*col
,
1808 GtkCellRenderer
*renderer
,
1809 GtkTreeModel
*model
,
1815 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1817 gtk_tree_model_get(model
, iter
, GPOINTER_TO_INT(user_data
), &value
, -1);
1821 hb_strfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, GLOBALS
->kcur
, GLOBALS
->minor
);
1823 color
= get_normal_color_amount(value
);
1825 g_object_set(renderer
,
1826 "foreground", color
,
1831 g_object_set(renderer
, "text", "", NULL
);
1836 static GtkTreeViewColumn
*ui_list_repdist_amount_column(gchar
*name
, gint id
)
1838 GtkTreeViewColumn
*column
;
1839 GtkCellRenderer
*renderer
;
1841 column
= gtk_tree_view_column_new();
1842 gtk_tree_view_column_set_title(column
, name
);
1843 renderer
= gtk_cell_renderer_text_new ();
1844 g_object_set(renderer
, "xalign", 1.0, NULL
);
1845 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1846 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_list_repdist_amount_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1847 gtk_tree_view_column_set_alignment (column
, 0.5);
1848 //gtk_tree_view_column_set_sort_column_id (column, id);
1852 static GtkTreeViewColumn
*ui_list_repdist_rate_column(gint id
)
1854 GtkTreeViewColumn
*column
;
1855 GtkCellRenderer
*renderer
;
1857 column
= gtk_tree_view_column_new();
1858 gtk_tree_view_column_set_title(column
, "%");
1859 renderer
= gtk_cell_renderer_text_new ();
1860 g_object_set(renderer
, "xalign", 1.0, "yalign", 1.0, "scale", 0.8, "scale-set", TRUE
, NULL
);
1862 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1863 //gtk_tree_view_column_add_attribute(column, renderer, "text", id);
1864 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_list_repdist_rate_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1865 gtk_tree_view_column_set_alignment (column
, 0.5);
1866 //gtk_tree_view_column_set_sort_column_id (column, id);
1868 //gtk_tree_view_column_set_visible(column, FALSE);
1874 ** create our statistic list
1876 static GtkWidget
*ui_list_repdist_create(void)
1878 GtkListStore
*store
;
1880 GtkCellRenderer
*renderer
;
1881 GtkTreeViewColumn
*column
;
1883 /* create list store */
1884 store
= gtk_list_store_new(
1898 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1899 g_object_unref(store
);
1901 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view
), PREFS
->grid_lines
);
1904 column
= gtk_tree_view_column_new();
1905 gtk_tree_view_column_set_title(column
, _("Result"));
1906 renderer
= gtk_cell_renderer_text_new ();
1907 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1908 //gtk_tree_view_column_set_cell_data_func(column, renderer, ope_result_cell_data_function, NULL, NULL);
1909 gtk_tree_view_column_add_attribute(column
, renderer
, "text", LST_REPDIST_NAME
);
1910 //gtk_tree_view_column_set_sort_column_id (column, LST_REPDIST_NAME);
1911 gtk_tree_view_column_set_resizable(column
, TRUE
);
1912 gtk_tree_view_column_set_alignment (column
, 0.5);
1913 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1915 /* column: Expense */
1916 column
= ui_list_repdist_amount_column(_("Expense"), LST_REPDIST_EXPENSE
);
1917 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1918 column
= ui_list_repdist_rate_column(LST_REPDIST_EXPRATE
);
1919 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1921 /* column: Income */
1922 column
= ui_list_repdist_amount_column(_("Income"), LST_REPDIST_INCOME
);
1923 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1924 column
= ui_list_repdist_rate_column(LST_REPDIST_INCRATE
);
1925 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1927 /* column: Balance */
1928 column
= ui_list_repdist_amount_column(_("Balance"), LST_REPDIST_BALANCE
);
1929 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1930 column
= ui_list_repdist_rate_column(LST_REPDIST_BALRATE
);
1931 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1933 /* column last: empty */
1934 column
= gtk_tree_view_column_new();
1935 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1938 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_REPDIST_POS
, ui_list_repdist_compare_func
, GINT_TO_POINTER(LST_REPDIST_POS
), NULL
);
1939 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_REPDIST_EXPENSE
, ui_list_repdist_compare_func
, GINT_TO_POINTER(LST_REPDIST_EXPENSE
), NULL
);
1940 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_REPDIST_INCOME
, ui_list_repdist_compare_func
, GINT_TO_POINTER(LST_REPDIST_INCOME
), NULL
);
1941 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_REPDIST_BALANCE
, ui_list_repdist_compare_func
, GINT_TO_POINTER(LST_REPDIST_BALANCE
), NULL
);
1947 static gint
ui_list_repdist_compare_func (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
)
1949 gint sortcol
= GPOINTER_TO_INT(userdata
);
1954 gtk_tree_model_get(model
, a
,
1955 LST_REPDIST_POS
, &pos1
,
1958 gtk_tree_model_get(model
, b
,
1959 LST_REPDIST_POS
, &pos2
,
1965 case LST_REPDIST_POS
:
1966 retval
= pos2
- pos1
;
1969 retval
= (ABS(val1
) - ABS(val2
)) > 0 ? 1 : -1;
1973 //DB( g_print(" sort %d=%d or %.2f=%.2f :: %d\n", pos1,pos2, val1, val2, ret) );